| /* network.c - Loopback demo: IPV6 + UDP */ |
| |
| /* |
| * Copyright (c) 2015 Intel Corporation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <zephyr.h> |
| |
| #if defined(CONFIG_STDOUT_CONSOLE) |
| #include <stdio.h> |
| #define PRINT printf |
| #else |
| #include <misc/printk.h> |
| #define PRINT printk |
| #endif |
| |
| #include <net/ip_buf.h> |
| #include <net/net_core.h> |
| #include <net/net_socket.h> |
| |
| #include <net_driver_loopback.h> |
| |
| /* Longer packet sending works only if fragmentation is supported |
| * by network stack. |
| */ |
| /* Generated by http://www.lipsum.com/ |
| * 2 paragraphs, 185 words, 1231 bytes of Lorem Ipsum |
| * The main() will add one null byte at the end so the maximum |
| * length for the data to send is 1232 bytes. |
| */ |
| static const char *text = |
| "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam " |
| "congue non neque vel tempor. In id porta nibh, ut cursus tortor. " |
| "Morbi eleifend tristique vehicula. Nunc vitae risus mauris. " |
| "Praesent vel imperdiet dolor, et ultricies nibh. Aliquam erat " |
| "volutpat. Maecenas pellentesque dolor vitae dictum tincidunt. " |
| "Fusce vel nibh nec leo tristique auctor eu a massa. Nam et tellus " |
| "ac tortor sollicitudin semper vitae nec tortor. Aliquam nec lacus " |
| "velit. Maecenas ornare ullamcorper justo non auctor. Donec " |
| "aliquam feugiat turpis, quis elementum sem rutrum ut. Sed eu " |
| "ullamcorper libero, ut suscipit magna." |
| "\n" |
| "Donec vehicula magna ut varius aliquam. Ut vitae commodo nulla, " |
| "quis ornare dolor. Nulla tortor sem, venenatis eu iaculis id, " |
| "commodo ut massa. Sed est lorem, euismod vitae enim sed, " |
| "hendrerit gravida felis. Donec eros lacus, auctor ut ultricies " |
| "eget, lobortis quis nisl. Aliquam sit amet blandit eros. " |
| "Interdum et malesuada fames ac ante ipsum primis in faucibus. " |
| "Quisque egestas nisl leo, sed consectetur leo ornare eu. " |
| "Suspendisse vitae urna vel purus maximus finibus. Proin sed " |
| "sollicitudin turpis. Mauris interdum neque eu tellus " |
| "pellentesque, id fringilla nisi fermentum. Suspendisse gravida " |
| "pharetra sodales orci aliquam."; |
| |
| /* Specify delay between greetings (in ms); compute equivalent in ticks */ |
| #define SLEEPTIME 1000 |
| #define SLEEPTICKS (SLEEPTIME * sys_clock_ticks_per_sec / 1000) |
| |
| #define STACKSIZE 2000 |
| static char receiver_stack[STACKSIZE]; |
| static char sender_stack[STACKSIZE]; |
| |
| static struct net_addr any_addr; |
| static struct net_addr loopback_addr; |
| |
| static int sent; |
| static int received; |
| |
| static nano_thread_id_t sender_id; |
| static nano_thread_id_t receiver_id; |
| |
| static int failure; |
| static int data_len; |
| |
| /* How many packets to send/receive */ |
| #if defined(CONFIG_NETWORK_LOOPBACK_TEST_COUNT) |
| #define TEST_COUNT CONFIG_NETWORK_LOOPBACK_TEST_COUNT |
| #else |
| #define TEST_COUNT 0 |
| #endif |
| static unsigned long count = TEST_COUNT; |
| |
| int eval_rcvd_data(char *rcvd_buf, int rcvd_len) |
| { |
| int rc = 0; |
| |
| if (data_len != rcvd_len) { |
| rc = -1; |
| PRINT("Received %d bytes but was sent %d bytes\n", |
| rcvd_len, data_len); |
| } else { |
| /* Data integrity */ |
| rc = memcmp(text, rcvd_buf, data_len-1); |
| if (rc != 0) { |
| PRINT("Sent and received data does not match.\n"); |
| PRINT("Sent: %.*s\n", data_len, text); |
| PRINT("Received: %.*s\n", |
| data_len, rcvd_buf); |
| } |
| } |
| return rc; |
| } |
| |
| void fiber_receiver(void) |
| { |
| struct net_context *ctx; |
| struct net_buf *buf; |
| char *rcvd_buf; |
| int rcvd_len; |
| |
| ctx = net_context_get(IPPROTO_UDP, |
| &any_addr, 0, |
| &loopback_addr, 4242); |
| if (!ctx) { |
| PRINT("%s: Cannot get network context\n", __func__); |
| return; |
| } |
| |
| while (!failure) { |
| /* Fiber blocks until something is ready to be read */ |
| buf = net_receive(ctx, TICKS_UNLIMITED); |
| if (buf) { |
| /* Application level data and its length */ |
| rcvd_buf = ip_buf_appdata(buf); |
| rcvd_len = ip_buf_appdatalen(buf); |
| |
| PRINT("[%d] %s: Received: %d bytes\n", |
| received, __func__, rcvd_len); |
| |
| if (eval_rcvd_data(rcvd_buf, rcvd_len) != 0) { |
| PRINT("[%d] %s: net_receive failed!\n", |
| received, __func__); |
| failure = 1; |
| } |
| ip_buf_unref(buf); |
| received++; |
| } |
| fiber_wakeup(sender_id); |
| fiber_sleep(SLEEPTICKS); |
| if (count && (count < received)) { |
| break; |
| } |
| } |
| } |
| |
| void prepare_to_send(struct net_buf *buf, size_t *len) |
| { |
| char *ptr; |
| int text_len; |
| |
| text_len = strlen(text); |
| *len = sys_rand32_get() % text_len; |
| |
| /* net_buf_add: returns a pointer to the current tail of |
| * buf->data before adding n bytes. |
| * Adding 0 bytes just allows us to get a pointer to the |
| * tail without affecting buf->len. |
| */ |
| ptr = net_buf_add(buf, 0); |
| memcpy(ptr, text, *len); |
| net_buf_add(buf, *len); |
| /* We need to know where the text finishes to add the |
| * end-of-line character. |
| */ |
| ptr = net_buf_add(buf, 1); |
| *ptr = '\0'; |
| |
| *len += 1; |
| } |
| |
| void fiber_sender(void) |
| { |
| struct net_context *ctx; |
| struct net_buf *buf; |
| uint16_t sent_len; |
| size_t len; |
| int header_size; |
| |
| ctx = net_context_get(IPPROTO_UDP, |
| &loopback_addr, 4242, |
| &any_addr, 0); |
| if (!ctx) { |
| PRINT("Cannot get network context\n"); |
| return; |
| } |
| |
| while (!failure) { |
| buf = ip_buf_get_tx(ctx); |
| if (buf) { |
| prepare_to_send(buf, &len); |
| sent_len = buf->len; |
| header_size = ip_buf_reserve(buf); |
| data_len = sent_len - header_size; |
| ip_buf_appdatalen(buf) = data_len; |
| |
| PRINT("[%d] %s: App data: %d bytes, IPv6+UDP: %d bytes, " |
| "Total packet size: %d bytes\n", |
| sent, __func__, len, header_size, sent_len); |
| |
| if (net_send(buf) < 0) { |
| PRINT("[%d] %s: net_send failed!\n", |
| sent, __func__); |
| failure = 1; |
| } |
| ip_buf_unref(buf); |
| sent++; |
| } |
| fiber_wakeup(receiver_id); |
| fiber_sleep(SLEEPTICKS); |
| if (sent != received) { |
| failure = 1; |
| } |
| if (count && (count < sent)) { |
| break; |
| } |
| |
| } |
| |
| if (failure) { |
| PRINT("TEST FAILED\n"); |
| } else { |
| PRINT("TEST PASSED\n"); |
| } |
| } |
| |
| void main(void) |
| { |
| struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; /* :: */ |
| struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; /* ::1 */ |
| |
| PRINT("%s: running network loopback test\n", __func__); |
| |
| sys_rand32_init(); |
| |
| net_init(); |
| net_driver_loopback_init(); |
| |
| any_addr.in6_addr = in6addr_any; |
| any_addr.family = AF_INET6; |
| |
| loopback_addr.in6_addr = in6addr_loopback; |
| loopback_addr.family = AF_INET6; |
| |
| receiver_id = task_fiber_start(receiver_stack, STACKSIZE, |
| (nano_fiber_entry_t)fiber_receiver, |
| 0, 0, 7, 0); |
| |
| sender_id = task_fiber_start(sender_stack, STACKSIZE, |
| (nano_fiber_entry_t)fiber_sender, |
| 0, 0, 7, 0); |
| } |