| /* Initializations */ |
| #define SYS_LOG_DOMAIN "example-app" |
| #define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG |
| #define NET_DEBUG 1 |
| |
| #include <zephyr.h> |
| |
| #include <net/nbuf.h> |
| #include <net/net_core.h> |
| #include <net/net_context.h> |
| |
| #define MY_IP6ADDR { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \ |
| 0, 0, 0, 0, 0, 0, 0, 0x1 } } } |
| #define MY_PORT 4242 |
| |
| struct in6_addr in6addr_my = MY_IP6ADDR; |
| struct sockaddr_in6 my_addr6 = { 0 }; |
| struct net_context *context; |
| int ret; |
| |
| struct nano_sem quit_lock; |
| |
| static inline void quit(void) |
| { |
| nano_sem_give(&quit_lock); |
| } |
| |
| static inline void init_app(void) |
| { |
| nano_sem_init(&quit_lock); |
| |
| /* Add our address to the network interface */ |
| net_if_ipv6_addr_add(net_if_get_default(), &in6addr_my, |
| NET_ADDR_MANUAL, 0); |
| } |
| |
| void main(void) |
| { |
| NET_INFO("Run sample application"); |
| |
| init_app(); |
| |
| create_context(); |
| |
| bind_address(); |
| |
| receive_data(); |
| |
| nano_sem_take(&quit_lock, TICKS_UNLIMITED); |
| |
| close_context(); |
| |
| NET_INFO("Stopping sample application"); |
| } |
| |
| /* Context creation */ |
| static int create_context(void) |
| { |
| ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &context); |
| if (!ret) { |
| NET_ERR("Cannot get context (%d)", ret); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| /* Context bind */ |
| static int bind_address(void) |
| { |
| net_ipaddr_copy(&my_addr6.sin6_addr, &in6addr_my); |
| my_addr6.sin6_family = AF_INET6; |
| my_addr6.sin6_port = htons(MY_PORT); |
| |
| ret = net_context_bind(context, (struct sockaddr *)&my_addr6); |
| if (ret < 0) { |
| NET_ERR("Cannot bind IPv6 UDP port %d (%d)", |
| ntohs(my_addr6.sin6_port), ret); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| /* Receive data */ |
| #define MAX_DBG_PRINT 64 |
| |
| static struct net_buf *udp_recv(const char *name, |
| struct net_context *context, |
| struct net_buf *buf) |
| { |
| struct net_buf *reply_buf, *frag, *tmp; |
| int header_len, recv_len, reply_len; |
| |
| NET_INFO("%s received %u bytes", name, |
| net_nbuf_appdatalen(buf)); |
| |
| reply_buf = net_nbuf_get_tx(context, K_FOREVER); |
| |
| NET_ASSERT(reply_buf); |
| |
| recv_len = net_buf_frags_len(buf->frags); |
| |
| tmp = buf->frags; |
| |
| /* First fragment will contain IP header so move the data |
| * down in order to get rid of it. |
| */ |
| header_len = net_nbuf_appdata(buf) - tmp->data; |
| |
| NET_ASSERT(header_len < CONFIG_NET_NBUF_DATA_SIZE); |
| |
| net_buf_pull(tmp, header_len); |
| |
| while (tmp) { |
| frag = net_nbuf_get_data(context, K_FOREVER); |
| |
| memcpy(net_buf_add(frag, tmp->len), tmp->data, tmp->len); |
| |
| net_buf_frag_add(reply_buf, frag); |
| |
| net_buf_frag_del(buf, tmp); |
| |
| tmp = buf->frags; |
| } |
| |
| reply_len = net_buf_frags_len(reply_buf->frags); |
| |
| NET_ASSERT_INFO(recv_len != reply_len, |
| "Received %d bytes, sending %d bytes", |
| recv_len, reply_len); |
| |
| return reply_buf; |
| } |
| |
| static inline void udp_sent(struct net_context *context, |
| int status, |
| void *token, |
| void *user_data) |
| { |
| if (!status) { |
| NET_INFO("Sent %d bytes", POINTER_TO_UINT(token)); |
| } |
| } |
| |
| static inline void set_dst_addr(sa_family_t family, |
| struct net_buf *buf, |
| struct sockaddr *dst_addr) |
| { |
| if (family == AF_INET6) { |
| net_ipaddr_copy(&net_sin6(dst_addr)->sin6_addr, |
| &NET_IPV6_BUF(buf)->src); |
| net_sin6(dst_addr)->sin6_family = AF_INET6; |
| net_sin6(dst_addr)->sin6_port = NET_UDP_BUF(buf)->src_port; |
| } |
| } |
| |
| static void udp_received(struct net_context *context, |
| struct net_buf *buf, |
| int status, |
| void *user_data) |
| { |
| struct net_buf *reply_buf; |
| struct sockaddr dst_addr; |
| sa_family_t family = net_nbuf_family(buf); |
| static char dbg[MAX_DBG_PRINT + 1]; |
| int ret; |
| |
| snprintf(dbg, MAX_DBG_PRINT, "UDP IPv%c", |
| family == AF_INET6 ? '6' : '4'); |
| |
| set_dst_addr(family, buf, &dst_addr); |
| |
| reply_buf = udp_recv(dbg, context, buf); |
| |
| net_nbuf_unref(buf); |
| |
| ret = net_context_sendto(reply_buf, &dst_addr, udp_sent, 0, |
| UINT_TO_POINTER(net_buf_frags_len(reply_buf)), |
| user_data); |
| if (ret < 0) { |
| NET_ERR("Cannot send data to peer (%d)", ret); |
| |
| net_nbuf_unref(reply_buf); |
| |
| quit(); |
| } |
| } |
| |
| static int receive_data(void) |
| { |
| ret = net_context_recv(context, udp_received, 0, NULL); |
| if (ret < 0) { |
| NET_ERR("Cannot receive IPv6 UDP packets"); |
| |
| quit(); |
| |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| /* Context close */ |
| static int close_context(void) |
| { |
| ret = net_context_put(context); |
| if (ret < 0) { |
| NET_ERR("Cannot close IPv6 UDP context"); |
| return ret; |
| } |
| |
| return 0; |
| } |