215 lines
4.1 KiB
C
215 lines
4.1 KiB
C
/* Initializations */
|
|
#define SYS_LOG_DOMAIN "example-app"
|
|
#define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG
|
|
#define NET_DEBUG 1
|
|
|
|
#include <zephyr.h>
|
|
|
|
#include <net/net_pkt.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_pkt_appdatalen(buf));
|
|
|
|
reply_buf = net_pkt_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_pkt_appdata(buf) - tmp->data;
|
|
|
|
NET_ASSERT(header_len < CONFIG_NET_BUF_DATA_SIZE);
|
|
|
|
net_buf_pull(tmp, header_len);
|
|
|
|
while (tmp) {
|
|
frag = net_pkt_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_HDR(buf)->src);
|
|
net_sin6(dst_addr)->sin6_family = AF_INET6;
|
|
net_sin6(dst_addr)->sin6_port = NET_UDP_HDR(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_pkt_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_pkt_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_pkt_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;
|
|
}
|