diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index 84a1ee198bb..d5482409607 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -321,12 +321,6 @@ static inline u8_t *net_pkt_ip_data(struct net_pkt *pkt) return pkt->frags->data; } -static inline u8_t *net_pkt_udp_data(struct net_pkt *pkt) -{ - return &pkt->frags->data[net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt)]; -} - static inline u8_t *net_pkt_tcp_data(struct net_pkt *pkt) { return &pkt->frags->data[net_pkt_ip_hdr_len(pkt) + @@ -408,7 +402,6 @@ static inline void net_pkt_set_ieee802154_rssi(struct net_pkt *pkt, #define NET_IPV6_HDR(pkt) ((struct net_ipv6_hdr *)net_pkt_ip_data(pkt)) #define NET_IPV4_HDR(pkt) ((struct net_ipv4_hdr *)net_pkt_ip_data(pkt)) -#define NET_UDP_HDR(pkt) ((struct net_udp_hdr *)(net_pkt_udp_data(pkt))) #define NET_TCP_HDR(pkt) ((struct net_tcp_hdr *)(net_pkt_tcp_data(pkt))) static inline void net_pkt_set_src_ipv6_addr(struct net_pkt *pkt) diff --git a/include/net/udp.h b/include/net/udp.h new file mode 100644 index 00000000000..637e9d01598 --- /dev/null +++ b/include/net/udp.h @@ -0,0 +1,70 @@ +/** @file + @brief UDP utility functions + */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __UDP_H +#define __UDP_H + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(CONFIG_NET_UDP) + +/** + * @brief Get UDP packet header data from net_pkt. + * + * @details The values in the returned header are in network byte order. + * Note that you must access the UDP header values by the returned pointer, + * the hdr parameter is just a placeholder for the header data and it might + * not contain anything if header can fit properly in the first fragment in + * the network packet. + * + * @param pkt Network packet + * @param hdr Where to place the header if it does not fit in first fragment + * of the network packet. + * + * @return Return pointer to header or NULL if something went wrong. + */ +struct net_udp_hdr *net_udp_get_hdr(struct net_pkt *pkt, + struct net_udp_hdr *hdr); + +/** + * @brief Set UDP packet header data in net_pkt. + * + * @details The values in the header must be in network byte order. + * This function is normally called after a call to net_udp_get_hdr(). + * The hdr parameter value should be the same that is returned by function + * net_udp_get_hdr() call. Note that if the UDP header fits in first net_pkt + * fragment, then this function will not do anything as your hdr parameter + * was pointing directly to net_pkt. + * + * @param pkt Network packet + * @param hdr Header data pointer that was returned by net_udp_get_hdr(). + * + * @return Return pointer to header or NULL if something went wrong. + */ +struct net_udp_hdr *net_udp_set_hdr(struct net_pkt *pkt, + struct net_udp_hdr *hdr); +#else +#define net_udp_get_hdr(pkt, frag) NULL +#define net_udp_set_hdr(pkt, frag) NULL +#endif /* CONFIG_NET_UDP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __UDP_H */ diff --git a/samples/bluetooth/ipsp/src/main.c b/samples/bluetooth/ipsp/src/main.c index 87d774b0b5f..f5b41febad5 100644 --- a/samples/bluetooth/ipsp/src/main.c +++ b/samples/bluetooth/ipsp/src/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -205,10 +206,18 @@ static inline void set_dst_addr(sa_family_t family, struct net_pkt *pkt, struct sockaddr *dst_addr) { + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + printk("Invalid UDP data\n"); + return; + } + net_ipaddr_copy(&net_sin6(dst_addr)->sin6_addr, &NET_IPV6_HDR(pkt)->src); net_sin6(dst_addr)->sin6_family = AF_INET6; - net_sin6(dst_addr)->sin6_port = NET_UDP_HDR(pkt)->src_port; + net_sin6(dst_addr)->sin6_port = udp_hdr->src_port; } static void udp_received(struct net_context *context, diff --git a/samples/net/coaps_server/src/udp.c b/samples/net/coaps_server/src/udp.c index 8143daf1dbc..85ea49b08c7 100644 --- a/samples/net/coaps_server/src/udp.c +++ b/samples/net/coaps_server/src/udp.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,9 +21,17 @@ static const socklen_t addrlen = sizeof(struct sockaddr_in6); static void set_client_address(struct sockaddr *addr, struct net_pkt *rx_pkt) { + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(rx_pkt, &hdr); + if (!udp_hdr) { + printk("Invalid UDP data\n"); + return; + } + net_ipaddr_copy(&net_sin6(addr)->sin6_addr, &NET_IPV6_HDR(rx_pkt)->src); net_sin6(addr)->sin6_family = AF_INET6; - net_sin6(addr)->sin6_port = NET_UDP_HDR(rx_pkt)->src_port; + net_sin6(addr)->sin6_port = udp_hdr->src_port; } static void udp_received(struct net_context *context, diff --git a/samples/net/echo_server/src/echo-server.c b/samples/net/echo_server/src/echo-server.c index 623dc261894..1102c3d7f8f 100644 --- a/samples/net/echo_server/src/echo-server.c +++ b/samples/net/echo_server/src/echo-server.c @@ -75,6 +75,7 @@ struct net_pkt *build_reply_pkt(const char *name, reply_pkt = net_app_get_net_pkt(ctx, net_pkt_family(pkt), K_FOREVER); NET_ASSERT(reply_pkt); + NET_ASSERT(net_pkt_family(reply_pkt) == net_pkt_family(pkt)); recv_len = net_pkt_get_len(pkt); diff --git a/samples/net/echo_server/src/udp.c b/samples/net/echo_server/src/udp.c index d8e40e275cc..a1b1826002c 100644 --- a/samples/net/echo_server/src/udp.c +++ b/samples/net/echo_server/src/udp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -51,12 +52,19 @@ static inline void set_dst_addr(sa_family_t family, struct net_pkt *pkt, struct sockaddr *dst_addr) { + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + return; + } + #if defined(CONFIG_NET_IPV6) if (family == AF_INET6) { net_ipaddr_copy(&net_sin6(dst_addr)->sin6_addr, &NET_IPV6_HDR(pkt)->src); net_sin6(dst_addr)->sin6_family = AF_INET6; - net_sin6(dst_addr)->sin6_port = NET_UDP_HDR(pkt)->src_port; + net_sin6(dst_addr)->sin6_port = udp_hdr->src_port; } #endif /* CONFIG_NET_IPV6) */ @@ -65,7 +73,7 @@ static inline void set_dst_addr(sa_family_t family, net_ipaddr_copy(&net_sin(dst_addr)->sin_addr, &NET_IPV4_HDR(pkt)->src); net_sin(dst_addr)->sin_family = AF_INET; - net_sin(dst_addr)->sin_port = NET_UDP_HDR(pkt)->src_port; + net_sin(dst_addr)->sin_port = udp_hdr->src_port; } #endif /* CONFIG_NET_IPV6) */ } diff --git a/samples/net/leds_demo/src/leds-demo.c b/samples/net/leds_demo/src/leds-demo.c index 44251acbfb3..51d16daff4f 100644 --- a/samples/net/leds_demo/src/leds-demo.c +++ b/samples/net/leds_demo/src/leds-demo.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -412,10 +413,19 @@ static void udp_receive(struct net_context *context, { struct zoap_packet request; struct sockaddr_in6 from; + struct net_udp_hdr hdr, *udp_hdr; int r, header_len; net_ipaddr_copy(&from.sin6_addr, &NET_IPV6_HDR(pkt)->src); - from.sin6_port = NET_UDP_HDR(pkt)->src_port; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + printk("Invalid UDP data received\n"); + net_pkt_unref(pkt); + return; + } + + from.sin6_port = udp_hdr->src_port; from.sin6_family = AF_INET6; /* diff --git a/samples/net/mbedtls_dtlsserver/src/udp.c b/samples/net/mbedtls_dtlsserver/src/udp.c index 2dffafd9a78..4fed84b91c6 100644 --- a/samples/net/mbedtls_dtlsserver/src/udp.c +++ b/samples/net/mbedtls_dtlsserver/src/udp.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -21,9 +22,17 @@ static const socklen_t addrlen = sizeof(struct sockaddr_in6); static void set_client_address(struct sockaddr *addr, struct net_pkt *rx_buf) { + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(rx_buf, &hdr); + if (!udp_hdr) { + printk("Invalid UDP data\n"); + return; + } + net_ipaddr_copy(&net_sin6(addr)->sin6_addr, &NET_IPV6_HDR(rx_buf)->src); net_sin6(addr)->sin6_family = AF_INET6; - net_sin6(addr)->sin6_port = NET_UDP_HDR(rx_buf)->src_port; + net_sin6(addr)->sin6_port = udp_hdr->src_port; } #else @@ -31,9 +40,17 @@ static const socklen_t addrlen = sizeof(struct sockaddr_in); static void set_client_address(struct sockaddr *addr, struct net_pkt *rx_buf) { + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(rx_buf, &hdr); + if (!udp_hdr) { + printk("Invalid UDP data\n"); + return; + } + net_ipaddr_copy(&net_sin(addr)->sin_addr, &NET_IPV4_HDR(rx_buf)->src); net_sin(addr)->sin_family = AF_INET; - net_sin(addr)->sin_port = NET_UDP_HDR(rx_buf)->src_port; + net_sin(addr)->sin_port = udp_hdr->src_port; } #endif diff --git a/samples/net/mqtt_publisher/prj_96b_nitrogen.conf b/samples/net/mqtt_publisher/prj_96b_nitrogen.conf index 3ec26229d71..06511165f2c 100644 --- a/samples/net/mqtt_publisher/prj_96b_nitrogen.conf +++ b/samples/net/mqtt_publisher/prj_96b_nitrogen.conf @@ -2,7 +2,7 @@ CONFIG_INIT_STACKS=y CONFIG_NETWORKING=y CONFIG_NET_TCP=y -CONFIG_NET_UDP=n +CONFIG_NET_UDP=y CONFIG_NET_ARP=y CONFIG_NET_L2_BLUETOOTH=y CONFIG_NET_L2_BLUETOOTH_SEC_LEVEL=1 diff --git a/samples/net/zoap_client/src/zoap-client.c b/samples/net/zoap_client/src/zoap-client.c index 41adf318b9e..fb70dc200b5 100644 --- a/samples/net/zoap_client/src/zoap-client.c +++ b/samples/net/zoap_client/src/zoap-client.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #if defined(CONFIG_NET_L2_BLUETOOTH) @@ -76,6 +77,7 @@ static void udp_receive(struct net_context *context, struct zoap_reply *reply; struct zoap_packet response; struct sockaddr_in6 from; + struct net_udp_hdr hdr, *udp_hdr; int header_len, r; /* @@ -98,7 +100,14 @@ static void udp_receive(struct net_context *context, } net_ipaddr_copy(&from.sin6_addr, &NET_IPV6_HDR(pkt)->src); - from.sin6_port = NET_UDP_HDR(pkt)->src_port; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + printk("Invalid UDP data received\n"); + return; + } + + from.sin6_port = udp_hdr->src_port; reply = zoap_response_received(&response, (const struct sockaddr *) &from, diff --git a/samples/net/zoap_server/src/zoap-server.c b/samples/net/zoap_server/src/zoap-server.c index c50b14b4323..73a61216323 100644 --- a/samples/net/zoap_server/src/zoap-server.c +++ b/samples/net/zoap_server/src/zoap-server.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -1115,10 +1116,19 @@ static void udp_receive(struct net_context *context, struct zoap_packet request; struct zoap_pending *pending; struct sockaddr_in6 from; + struct net_udp_hdr hdr, *udp_hdr; int r, header_len; net_ipaddr_copy(&from.sin6_addr, &NET_IPV6_HDR(pkt)->src); - from.sin6_port = NET_UDP_HDR(pkt)->src_port; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + printk("Invalid UDP data received\n"); + net_pkt_unref(pkt); + return; + } + + from.sin6_port = udp_hdr->src_port; from.sin6_family = AF_INET6; /* diff --git a/samples/net/zperf/src/zperf_session.c b/samples/net/zperf/src/zperf_session.c index a0a3715a2c5..35cd105e9c5 100644 --- a/samples/net/zperf/src/zperf_session.c +++ b/samples/net/zperf/src/zperf_session.c @@ -7,6 +7,7 @@ #include #include +#include #include "zperf_session.h" @@ -21,6 +22,7 @@ struct session *get_session(struct net_pkt *pkt, enum session_proto proto) struct session *free = NULL; struct in6_addr ipv6 = { }; struct in_addr ipv4 = { }; + struct net_udp_hdr hdr, *udp_hdr; int i = 0; u16_t port; @@ -34,8 +36,14 @@ struct session *get_session(struct net_pkt *pkt, enum session_proto proto) return NULL; } + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + printk("Invalid UDP data\n"); + return NULL; + } + /* Get tuple of the remote connection */ - port = NET_UDP_HDR(pkt)->src_port; + port = udp_hdr->src_port; if (net_pkt_family(pkt) == AF_INET6) { net_ipaddr_copy(&ipv6, &NET_IPV6_HDR(pkt)->src); diff --git a/samples/net/zperf/src/zperf_udp_receiver.c b/samples/net/zperf/src/zperf_udp_receiver.c index 0af2f0538c9..96628349ee2 100644 --- a/samples/net/zperf/src/zperf_udp_receiver.c +++ b/samples/net/zperf/src/zperf_udp_receiver.c @@ -12,6 +12,7 @@ #include #include +#include #include "zperf.h" #include "zperf_internal.h" @@ -40,12 +41,20 @@ static inline void set_dst_addr(sa_family_t family, struct net_pkt *pkt, struct sockaddr *dst_addr) { + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + printk(TAG "Invalid UDP data\n"); + return; + } + #if defined(CONFIG_NET_IPV6) if (family == AF_INET6) { net_ipaddr_copy(&net_sin6(dst_addr)->sin6_addr, &NET_IPV6_HDR(pkt)->src); net_sin6(dst_addr)->sin6_family = AF_INET6; - net_sin6(dst_addr)->sin6_port = NET_UDP_HDR(pkt)->src_port; + net_sin6(dst_addr)->sin6_port = udp_hdr->src_port; } #endif /* CONFIG_NET_IPV6 */ @@ -54,7 +63,7 @@ static inline void set_dst_addr(sa_family_t family, net_ipaddr_copy(&net_sin(dst_addr)->sin_addr, &NET_IPV4_HDR(pkt)->src); net_sin(dst_addr)->sin_family = AF_INET; - net_sin(dst_addr)->sin_port = NET_UDP_HDR(pkt)->src_port; + net_sin(dst_addr)->sin_port = udp_hdr->src_port; } #endif /* CONFIG_NET_IPV4 */ } diff --git a/samples/net/zperf/src/zperf_udp_uploader.c b/samples/net/zperf/src/zperf_udp_uploader.c index e029297a26d..78b7ba7679f 100644 --- a/samples/net/zperf/src/zperf_udp_uploader.c +++ b/samples/net/zperf/src/zperf_udp_uploader.c @@ -22,14 +22,21 @@ static u8_t sample_packet[PACKET_SIZE_MAX]; static inline void zperf_upload_decode_stat(struct net_pkt *pkt, struct zperf_results *results) { - struct net_buf *frag = pkt->frags; + struct net_buf *frag; struct zperf_server_hdr hdr; u16_t offset; u16_t pos; - offset = net_pkt_udp_data(pkt) - net_pkt_ip_data(pkt); - offset += sizeof(struct net_udp_hdr) + - sizeof(struct zperf_udp_datagram); + frag = net_frag_get_pos(pkt, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_udp_hdr) + + sizeof(struct zperf_udp_datagram), + &offset); + if (!frag) { + printk(TAG "ERROR! Network packet too short\n"); + return; + } /* Decode stat */ if (!pkt) { diff --git a/subsys/net/ip/6lo.c b/subsys/net/ip/6lo.c index 924d78aaf23..fb929fbc8c7 100644 --- a/subsys/net/ip/6lo.c +++ b/subsys/net/ip/6lo.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "net_private.h" #include "6lo.h" @@ -684,7 +685,6 @@ static inline bool compress_IPHC_header(struct net_pkt *pkt, #endif struct net_ipv6_hdr *ipv6 = NET_IPV6_HDR(pkt); u8_t offset = 0; - struct net_udp_hdr *udp; struct net_buf *frag; u8_t compressed; @@ -752,11 +752,19 @@ static inline bool compress_IPHC_header(struct net_pkt *pkt, } /* UDP header compression */ - udp = NET_UDP_HDR(pkt); - IPHC[offset] = NET_6LO_NHC_UDP_BARE; - offset = compress_nh_udp(udp, frag, offset); + if (IS_ENABLED(CONFIG_NET_UDP)) { + struct net_udp_hdr hdr, *udp; - compressed += NET_UDPH_LEN; + udp = net_udp_get_hdr(pkt, &hdr); + NET_ASSERT(udp); + + IPHC[offset] = NET_6LO_NHC_UDP_BARE; + offset = compress_nh_udp(udp, frag, offset); + + compressed += NET_UDPH_LEN; + + net_udp_set_hdr(pkt, udp); + } end: net_buf_add(frag, offset); diff --git a/subsys/net/ip/Makefile b/subsys/net/ip/Makefile index fb852587d61..ec179be0606 100644 --- a/subsys/net/ip/Makefile +++ b/subsys/net/ip/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_NET_RPL) += rpl.o obj-$(CONFIG_NET_RPL_MRHOF) += rpl-mrhof.o obj-$(CONFIG_NET_RPL_OF0) += rpl-of0.o obj-$(CONFIG_NET_MGMT_EVENT) += net_mgmt.o +obj-$(CONFIG_NET_UDP) += udp.o obj-$(CONFIG_NET_TCP) += tcp.o obj-$(CONFIG_NET_SHELL) += net_shell.o obj-$(CONFIG_NET_STATISTICS) += net_stats.o diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index a2655cbbd44..1d117baabe7 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -18,10 +18,12 @@ #include #include +#include #include "net_private.h" #include "icmpv6.h" #include "icmpv4.h" +#include "udp_internal.h" #include "connection.h" #include "net_stats.h" @@ -44,12 +46,6 @@ static struct net_conn conns[CONFIG_NET_MAX_CONN]; -/* This is only used for getting source and destination ports. Because - * both TCP and UDP header have these in the same location, we can check - * them both using the UDP struct. - */ -#define NET_CONN_HDR(pkt) ((struct net_udp_hdr *)(net_pkt_udp_data(pkt))) - #if defined(CONFIG_NET_CONN_CACHE) /* Cache the connection so that we do not have to go @@ -213,13 +209,20 @@ static inline s32_t get_conn(enum net_ip_protocol proto, struct net_pkt *pkt, u32_t *cache_value) { + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + return NET_DROP; + } + #if defined(CONFIG_NET_IPV4) if (family == AF_INET) { return check_hash(proto, family, &NET_IPV4_HDR(pkt)->src, &NET_IPV4_HDR(pkt)->dst, - NET_UDP_HDR(pkt)->src_port, - NET_UDP_HDR(pkt)->dst_port, + udp_hdr->src_port, + udp_hdr->dst_port, cache_value); } #endif @@ -229,8 +232,8 @@ static inline s32_t get_conn(enum net_ip_protocol proto, return check_hash(proto, family, &NET_IPV6_HDR(pkt)->src, &NET_IPV6_HDR(pkt)->dst, - NET_UDP_HDR(pkt)->src_port, - NET_UDP_HDR(pkt)->dst_port, + udp_hdr->src_port, + udp_hdr->dst_port, cache_value); } #endif @@ -289,14 +292,20 @@ static inline enum net_verdict cache_check(enum net_ip_protocol proto, if (conn_cache[*pos].idx >= 0) { /* Connection is in the cache */ struct net_conn *conn; + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + return NET_CONTINUE; + } conn = &conns[conn_cache[*pos].idx]; NET_DBG("Cache %s listener for pkt %p src port %u " "dst port %u family %d cache[%d] 0x%x", net_proto2str(proto), pkt, - ntohs(NET_CONN_HDR(pkt)->src_port), - ntohs(NET_CONN_HDR(pkt)->dst_port), + ntohs(udp_hdr->src_port), + ntohs(udp_hdr->dst_port), net_pkt_family(pkt), *pos, conn_cache[*pos].value); @@ -766,6 +775,7 @@ static inline void send_icmp_error(struct net_pkt *pkt) enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) { + struct net_udp_hdr hdr, *udp_hdr; int i, best_match = -1; s16_t best_rank = -1; u16_t chksum; @@ -781,17 +791,26 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) } #endif + /* This is only used for getting source and destination ports. + * Because both TCP and UDP header have these in the same + * location, we can check them both using the UDP struct. + */ + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + return NET_DROP; + } + if (proto == IPPROTO_TCP) { chksum = NET_TCP_HDR(pkt)->chksum; } else { - chksum = NET_UDP_HDR(pkt)->chksum; + chksum = udp_hdr->chksum; } if (IS_ENABLED(CONFIG_NET_DEBUG_CONN)) { NET_DBG("Check %s listener for pkt %p src port %u dst port %u " "family %d chksum 0x%04x", net_proto2str(proto), pkt, - ntohs(NET_CONN_HDR(pkt)->src_port), - ntohs(NET_CONN_HDR(pkt)->dst_port), + ntohs(udp_hdr->src_port), + ntohs(udp_hdr->dst_port), net_pkt_family(pkt), ntohs(chksum)); } @@ -806,14 +825,14 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) if (net_sin(&conns[i].remote_addr)->sin_port) { if (net_sin(&conns[i].remote_addr)->sin_port != - NET_CONN_HDR(pkt)->src_port) { + udp_hdr->src_port) { continue; } } if (net_sin(&conns[i].local_addr)->sin_port) { if (net_sin(&conns[i].local_addr)->sin_port != - NET_CONN_HDR(pkt)->dst_port) { + udp_hdr->dst_port) { continue; } } @@ -855,16 +874,14 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) proto == IPPROTO_UDP) { u16_t chksum_calc; - NET_UDP_HDR(pkt)->chksum = 0; - chksum_calc = ~net_calc_chksum_udp(pkt); + net_udp_set_chksum(pkt, pkt->frags); + chksum_calc = net_udp_get_chksum(pkt, pkt->frags); if (chksum != chksum_calc) { net_stats_update_udp_chkerr(); goto drop; } - NET_UDP_HDR(pkt)->chksum = chksum; - } else if (IS_ENABLED(CONFIG_NET_TCP_CHECKSUM) && proto == IPPROTO_TCP) { u16_t chksum_calc; @@ -876,8 +893,6 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) net_stats_update_tcp_seg_chkerr(); goto drop; } - - NET_TCP_HDR(pkt)->chksum = chksum; } #if defined(CONFIG_NET_CONN_CACHE) diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index f370ce41ea2..84dba1962b8 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -23,7 +23,8 @@ #include #include "net_private.h" -#include "udp.h" +#include +#include "udp_internal.h" #include struct dhcp_msg { @@ -250,11 +251,13 @@ static inline bool add_sname(struct net_pkt *pkt) static void setup_header(struct net_pkt *pkt, const struct in_addr *server_addr) { struct net_ipv4_hdr *ipv4; - struct net_udp_hdr *udp; + struct net_udp_hdr hdr, *udp; u16_t len; ipv4 = NET_IPV4_HDR(pkt); - udp = NET_UDP_HDR(pkt); + + udp = net_udp_get_hdr(pkt, &hdr); + NET_ASSERT(udp && udp != &hdr); len = net_pkt_get_len(pkt); @@ -277,6 +280,8 @@ static void setup_header(struct net_pkt *pkt, const struct in_addr *server_addr) udp->len = htons(len); udp->chksum = 0; udp->chksum = ~net_calc_chksum_udp(pkt); + + net_udp_set_hdr(pkt, udp); } /* Prepare initial DHCPv4 message and add options as per message type */ diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index db4aa4c5077..5cbe81fec88 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -22,6 +22,7 @@ #include "connection.h" #include "net_stats.h" #include "icmpv4.h" +#include "udp_internal.h" #include "ipv4.h" struct net_pkt *net_ipv4_create_raw(struct net_pkt *pkt, @@ -97,8 +98,7 @@ int net_ipv4_finalize_raw(struct net_pkt *pkt, u8_t next_header) #if defined(CONFIG_NET_UDP) if (next_header == IPPROTO_UDP) { - NET_UDP_HDR(pkt)->chksum = 0; - NET_UDP_HDR(pkt)->chksum = ~net_calc_chksum_udp(pkt); + net_udp_set_chksum(pkt, pkt->frags); } #endif #if defined(CONFIG_NET_TCP) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index eaeb824f4f8..b212d5a5003 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -27,6 +27,7 @@ #include "net_private.h" #include "connection.h" #include "icmpv6.h" +#include "udp_internal.h" #include "ipv6.h" #include "nbr.h" #include "6lo.h" @@ -699,8 +700,7 @@ int net_ipv6_finalize_raw(struct net_pkt *pkt, u8_t next_header) #if defined(CONFIG_NET_UDP) if (next_header == IPPROTO_UDP) { - NET_UDP_HDR(pkt)->chksum = 0; - NET_UDP_HDR(pkt)->chksum = ~net_calc_chksum_udp(pkt); + net_udp_set_chksum(pkt, pkt->frags); } else #endif diff --git a/subsys/net/ip/l2/ieee802154/ieee802154_fragment.c b/subsys/net/ip/l2/ieee802154/ieee802154_fragment.c index 66eb3fa7964..ab964f44101 100644 --- a/subsys/net/ip/l2/ieee802154/ieee802154_fragment.c +++ b/subsys/net/ip/l2/ieee802154/ieee802154_fragment.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "ieee802154_fragment.h" @@ -320,7 +321,15 @@ static void update_protocol_header_lengths(struct net_pkt *pkt, u16_t size) NET_IPV6_HDR(pkt)->len[1] = (u8_t) (size - NET_IPV6H_LEN); if (NET_IPV6_HDR(pkt)->nexthdr == IPPROTO_UDP) { - NET_UDP_HDR(pkt)->len = htons(size - NET_IPV6H_LEN); + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + + NET_ASSERT(udp_hdr); + + udp_hdr->len = htons(size - NET_IPV6H_LEN); + + net_udp_set_hdr(pkt, udp_hdr); } } diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 6d9d42fa212..cd375c21b26 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -30,7 +30,7 @@ #include "ipv6.h" #include "ipv4.h" -#include "udp.h" +#include "udp_internal.h" #include "tcp.h" #include "net_stats.h" @@ -1850,13 +1850,23 @@ static int create_udp_packet(struct net_context *context, struct net_pkt **out_pkt) { int r = 0; + struct net_pkt *tmp; #if defined(CONFIG_NET_IPV6) if (net_pkt_family(pkt) == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)dst_addr; pkt = net_ipv6_create(context, pkt, NULL, &addr6->sin6_addr); - pkt = net_udp_append(context, pkt, ntohs(addr6->sin6_port)); + tmp = net_udp_insert(context, pkt, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), + addr6->sin6_port); + if (!tmp) { + return -ENOMEM; + } + + pkt = tmp; + r = net_ipv6_finalize(context, pkt); } else #endif /* CONFIG_NET_IPV6 */ @@ -1866,7 +1876,14 @@ static int create_udp_packet(struct net_context *context, struct sockaddr_in *addr4 = (struct sockaddr_in *)dst_addr; pkt = net_ipv4_create(context, pkt, NULL, &addr4->sin_addr); - pkt = net_udp_append(context, pkt, ntohs(addr4->sin_port)); + tmp = net_udp_insert(context, pkt, net_pkt_ip_hdr_len(pkt), + addr4->sin_port); + if (!tmp) { + return -ENOMEM; + } + + pkt = tmp; + r = net_ipv4_finalize(context, pkt); } else #endif /* CONFIG_NET_IPV4 */ @@ -2048,28 +2065,33 @@ int net_context_sendto(struct net_pkt *pkt, static void set_appdata_values(struct net_pkt *pkt, enum net_ip_protocol proto) { size_t total_len = net_pkt_get_len(pkt); + u16_t proto_len = 0; + struct net_buf *frag; + u16_t offset; #if defined(CONFIG_NET_UDP) if (proto == IPPROTO_UDP) { - net_pkt_set_appdata(pkt, net_pkt_udp_data(pkt) + - sizeof(struct net_udp_hdr)); - } else + proto_len = sizeof(struct net_udp_hdr); + } #endif /* CONFIG_NET_UDP */ #if defined(CONFIG_NET_TCP) if (proto == IPPROTO_TCP) { - net_pkt_set_appdata(pkt, net_pkt_udp_data(pkt) + - tcp_hdr_len(pkt)); - } else + net_pkt_set_appdata(pkt, net_pkt_tcp_data(pkt) + + tcp_hdr_len(pkt)); + } #endif /* CONFIG_NET_TCP */ - { - net_pkt_set_appdata(pkt, net_pkt_ip_data(pkt) + - net_pkt_ip_hdr_len(pkt)); + + frag = net_frag_get_pos(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + proto_len, + &offset); + if (frag) { + net_pkt_set_appdata(pkt, frag->data + offset); } - net_pkt_set_appdatalen(pkt, total_len - - (net_pkt_appdata(pkt) - - net_pkt_ip_data(pkt))); + net_pkt_set_appdatalen(pkt, total_len - net_pkt_ip_hdr_len(pkt) - + net_pkt_ipv6_ext_len(pkt) - proto_len); NET_ASSERT_INFO(net_pkt_appdatalen(pkt) < total_len, "Wrong appdatalen %u, total %zu", diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 7bc93342826..98a055a25d1 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -46,7 +46,7 @@ #include "rpl.h" #include "connection.h" -#include "udp.h" +#include "udp_internal.h" #include "tcp.h" #include "net_stats.h" diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 3e830cd1406..8545753a492 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -1720,6 +1720,32 @@ u8_t *net_pkt_icmp_opt_data(struct net_pkt *pkt, size_t opt_len) return frag->data + offset; } +struct net_udp_hdr *net_pkt_udp_data(struct net_pkt *pkt) +{ + struct net_buf *frag; + u16_t offset; + + frag = net_frag_get_pos(pkt, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), + &offset); + if (!frag) { + /* We tried to read past the end of the data */ + NET_ASSERT_INFO(frag, + "IP hdr %d ext len %d offset %d pos %d " + "total %zd", + net_pkt_ip_hdr_len(pkt), + net_pkt_ipv6_ext_len(pkt), + offset, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), + net_buf_frags_len(pkt->frags)); + return NULL; + } + + return (struct net_udp_hdr *)(frag->data + offset); +} + void net_pkt_init(void) { NET_DBG("Allocating %u RX (%zu bytes), %u TX (%zu bytes), " diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index dac33ebebb7..ea28b39397e 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -57,6 +57,19 @@ struct net_icmp_hdr *net_icmp_header_fits(struct net_pkt *pkt, return NULL; } +struct net_udp_hdr *net_pkt_udp_data(struct net_pkt *pkt); + +static inline +struct net_udp_hdr *net_udp_header_fits(struct net_pkt *pkt, + struct net_udp_hdr *hdr) +{ + if (net_header_fits(pkt, (u8_t *)hdr, sizeof(*hdr))) { + return hdr; + } + + return NULL; +} + #if defined(CONFIG_NET_IPV4) extern u16_t net_calc_chksum_ipv4(struct net_pkt *pkt); #endif /* CONFIG_NET_IPV4 */ diff --git a/subsys/net/ip/udp.c b/subsys/net/ip/udp.c new file mode 100644 index 00000000000..f0645ddeeef --- /dev/null +++ b/subsys/net/ip/udp.c @@ -0,0 +1,279 @@ +/** @file + * @brief UDP packet helpers. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_NET_DEBUG_UDP) +#define SYS_LOG_DOMAIN "net/udp" +#define NET_LOG_ENABLED 1 +#endif + +#include "net_private.h" +#include "udp_internal.h" + +#define PKT_WAIT_TIME K_SECONDS(1) + +struct net_pkt *net_udp_append_raw(struct net_pkt *pkt, + u16_t src_port, + u16_t dst_port) +{ + struct net_buf *frag; + u16_t offset; + + net_pkt_append(pkt, sizeof(src_port), (u8_t *)&src_port, + PKT_WAIT_TIME); + net_pkt_append(pkt, sizeof(dst_port), (u8_t *)&dst_port, + PKT_WAIT_TIME); + net_pkt_append_be16(pkt, net_pkt_get_len(pkt) - + net_pkt_ip_hdr_len(pkt) - + net_pkt_ipv6_ext_len(pkt)); + + frag = net_frag_get_pos(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_udp_hdr), + &offset); + if (frag) { + net_pkt_set_appdata(pkt, frag->data + offset); + } + + return pkt; +} + +struct net_pkt *net_udp_insert_raw(struct net_pkt *pkt, + u16_t offset, + u16_t src_port, + u16_t dst_port) +{ + struct net_buf *frag, *prev, *udp; + u16_t pos; + + frag = net_frag_get_pos(pkt, offset, &pos); + if (!frag && pos == 0xffff) { + NET_DBG("Offset %d out of pkt len %zd", + offset, net_pkt_get_len(pkt)); + return NULL; + } + + /* We can only insert the UDP header between existing two + * fragments. + */ + if (frag && pos != 0) { + NET_DBG("Cannot insert UDP data into offset %d", offset); + return NULL; + } + + if (pkt->frags != frag) { + struct net_buf *tmp = pkt->frags; + + prev = NULL; + + while (tmp->frags) { + if (tmp->frags == frag) { + prev = tmp; + break; + } + + tmp = tmp->frags; + } + } else { + prev = pkt->frags; + } + + if (!prev) { + goto fail; + } + + udp = net_pkt_get_frag(pkt, PKT_WAIT_TIME); + if (!udp) { + goto fail; + } + + /* Source and destination ports are already in network byte order */ + net_buf_add_mem(udp, &src_port, sizeof(src_port)); + net_buf_add_mem(udp, &dst_port, sizeof(dst_port)); + + net_buf_add_be16(udp, net_pkt_get_len(pkt) - + net_pkt_ip_hdr_len(pkt) - + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_udp_hdr)); + + net_buf_add_be16(udp, 0); /* chksum */ + + net_buf_frag_insert(prev, udp); + + frag = net_frag_get_pos(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_udp_hdr), + &pos); + if (frag) { + net_pkt_set_appdata(pkt, frag->data + pos); + } + + return pkt; + +fail: + NET_DBG("Cannot insert UDP header into %p", pkt); + return NULL; +} + +struct net_buf *net_udp_set_chksum(struct net_pkt *pkt, struct net_buf *frag) +{ + struct net_udp_hdr *hdr; + u16_t chksum = 0; + u16_t pos; + + hdr = net_pkt_udp_data(pkt); + if (net_udp_header_fits(pkt, hdr)) { + hdr->chksum = 0; + hdr->chksum = ~net_calc_chksum_udp(pkt); + + return frag; + } + + /* We need to set the checksum to 0 first before the calc */ + frag = net_pkt_write(pkt, frag, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + 2 + 2 + 2 /* src + dst + len */, + &pos, sizeof(chksum), (u8_t *)&chksum, + PKT_WAIT_TIME); + + chksum = ~net_calc_chksum_udp(pkt); + + frag = net_pkt_write(pkt, frag, pos - 2, &pos, sizeof(chksum), + (u8_t *)&chksum, PKT_WAIT_TIME); + + NET_ASSERT(frag); + + return frag; +} + +u16_t net_udp_get_chksum(struct net_pkt *pkt, struct net_buf *frag) +{ + struct net_udp_hdr *hdr; + u16_t chksum; + u16_t pos; + + hdr = net_pkt_udp_data(pkt); + if (net_udp_header_fits(pkt, hdr)) { + return hdr->chksum; + } + + frag = net_frag_read(frag, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + 2 + 2 + 2 /* src + dst + len */, + &pos, sizeof(chksum), (u8_t *)&chksum); + NET_ASSERT(frag); + + return chksum; +} + +struct net_udp_hdr *net_udp_get_hdr(struct net_pkt *pkt, + struct net_udp_hdr *hdr) +{ + struct net_udp_hdr *udp_hdr; + struct net_buf *frag; + u16_t pos; + + udp_hdr = net_pkt_udp_data(pkt); + if (net_udp_header_fits(pkt, udp_hdr)) { + return udp_hdr; + } + + frag = net_frag_read(pkt->frags, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), + &pos, sizeof(hdr->src_port), + (u8_t *)&hdr->src_port); + frag = net_frag_read(frag, pos, &pos, sizeof(hdr->dst_port), + (u8_t *)&hdr->dst_port); + frag = net_frag_read(frag, pos, &pos, sizeof(hdr->len), + (u8_t *)&hdr->len); + frag = net_frag_read(frag, pos, &pos, sizeof(hdr->chksum), + (u8_t *)&hdr->chksum); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_udp_hdr *net_udp_set_hdr(struct net_pkt *pkt, + struct net_udp_hdr *hdr) +{ + struct net_buf *frag; + u16_t pos; + + if (net_udp_header_fits(pkt, hdr)) { + return hdr; + } + + frag = net_pkt_write(pkt, pkt->frags, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), + &pos, sizeof(hdr->src_port), + (u8_t *)&hdr->src_port, PKT_WAIT_TIME); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->dst_port), + (u8_t *)&hdr->dst_port, PKT_WAIT_TIME); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->len), + (u8_t *)&hdr->len, PKT_WAIT_TIME); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->chksum), + (u8_t *)&hdr->chksum, PKT_WAIT_TIME); + + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_pkt *net_udp_append(struct net_context *context, + struct net_pkt *pkt, + u16_t port) +{ + /* Append writes using *_be16() so it swap the port here */ + return net_udp_append_raw(pkt, + net_sin((struct sockaddr *) + &context->local)->sin_port, + port); +} + +struct net_pkt *net_udp_insert(struct net_context *context, + struct net_pkt *pkt, + u16_t offset, + u16_t port) +{ + return net_udp_insert_raw(pkt, + offset, + net_sin((struct sockaddr *) + &context->local)->sin_port, + port); +} + +int net_udp_register(const struct sockaddr *remote_addr, + const struct sockaddr *local_addr, + u16_t remote_port, + u16_t local_port, + net_conn_cb_t cb, + void *user_data, + struct net_conn_handle **handle) +{ + return net_conn_register(IPPROTO_UDP, remote_addr, local_addr, + remote_port, local_port, cb, user_data, + handle); +} + +int net_udp_unregister(struct net_conn_handle *handle) +{ + return net_conn_unregister(handle); +} + +void net_udp_init(void) +{ +} diff --git a/subsys/net/ip/udp.h b/subsys/net/ip/udp.h index 6a8d11236b2..3b24dc1e8aa 100644 --- a/subsys/net/ip/udp.h +++ b/subsys/net/ip/udp.h @@ -40,13 +40,11 @@ static inline struct net_pkt *net_udp_append_raw(struct net_pkt *pkt, u16_t src_port, u16_t dst_port) { - NET_UDP_HDR(pkt)->src_port = htons(src_port); - NET_UDP_HDR(pkt)->dst_port = htons(dst_port); - - net_buf_add(pkt->frags, sizeof(struct net_udp_hdr)); - - NET_UDP_HDR(pkt)->len = htons(net_pkt_get_len(pkt) - - net_pkt_ip_hdr_len(pkt)); + net_pkt_append_be16(pkt, src_port); + net_pkt_append_be16(pkt, dst_port); + net_pkt_append_be16(pkt, net_pkt_get_len(pkt) - + net_pkt_ip_hdr_len(pkt) - + net_pkt_ipv6_ext_len(pkt)); net_pkt_set_appdata(pkt, net_pkt_udp_data(pkt) + sizeof(struct net_udp_hdr)); @@ -54,6 +52,68 @@ static inline struct net_pkt *net_udp_append_raw(struct net_pkt *pkt, return pkt; } +#ifndef NET_UDP_PKT_WAIT_TIME +#define NET_UDP_PKT_WAIT_TIME K_SECONDS(1) +#endif + +static inline struct net_buf *net_udp_set_chksum(struct net_pkt *pkt, + struct net_buf *frag) +{ + u16_t chksum; + u16_t pos; + + frag = net_pkt_write_be16(pkt, pkt->frags, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + 2 + 2 + 2 /* src + dst + len */, + &pos, 0); + + chksum = ~net_calc_chksum_udp(pkt); + + frag = net_pkt_write(pkt, frag, pos - 2, &pos, sizeof(chksum), + (u8_t *)&chksum, NET_UDP_PKT_WAIT_TIME); + + NET_ASSERT(frag); + + return frag; +} + +static inline u16_t net_udp_get_chksum(struct net_pkt *pkt, + struct net_buf *frag) +{ + u16_t chksum; + u16_t pos; + + frag = net_frag_read_be16(pkt->frags, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + 2 + 2 + 2 /* src + dst + len */, + &pos, &chksum); + NET_ASSERT(frag); + + return chksum; +} + +static inline struct net_udp_hdr *net_udp_get_hdr(struct net_pkt *pkt, + struct net_udp_udp *hdr) +{ + struct net_buf *frag = pkt->frags; + u16_t pos; + + frag = net_frag_read_be16(frag, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), + &pos, &hdr->src_port); + frag = net_frag_read_be16(frag, pos, &pos, &hdr->dst_port); + frag = net_frag_read_be16(frag, pos, &pos, &hdr->len); + frag = net_frag_read_be16(frag, pos, &pos, &hdr->chksum); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + /** * @brief Append UDP packet into net_pkt * diff --git a/subsys/net/ip/udp_internal.h b/subsys/net/ip/udp_internal.h new file mode 100644 index 00000000000..24cbca4c2e1 --- /dev/null +++ b/subsys/net/ip/udp_internal.h @@ -0,0 +1,161 @@ +/** @file + @brief UDP data handler + + This is not to be included by the application and is only used by + core IP stack. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __UDP_INTERNAL_H +#define __UDP_INTERNAL_H + +#include + +#include +#include +#include +#include + +#include "connection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(CONFIG_NET_UDP) +/** + * @brief Append UDP packet into net_pkt + * + * @param pkt Network packet + * @param src_port Source port in host byte order. + * @param dst_port Destination port in host byte order. + * + * @return Return network packet that contains the UDP packet. + */ +struct net_pkt *net_udp_append_raw(struct net_pkt *pkt, + u16_t src_port, + u16_t dst_port); + +/** + * @brief Insert UDP packet into net_pkt chain. The UDP header is added + * right after the IP header which is after first fragment. + * + * @param pkt Network packet + * @param offset Offset where to insert (typically after IP header) + * @param src_port Source port in host byte order. + * @param dst_port Destination port in host byte order. + * + * @return Return network packet that contains the UDP packet. + */ +struct net_pkt *net_udp_insert_raw(struct net_pkt *pkt, + u16_t offset, + u16_t src_port, + u16_t dst_port); + +/** + * @brief Set UDP checksum in network packet. + * + * @param pkt Network packet + * @param frag Fragment where to start calculating the offset. + * Typically this is set to pkt->frags by the caller. + * + * @return Return the actual fragment where the checksum was written. + */ +struct net_buf *net_udp_set_chksum(struct net_pkt *pkt, struct net_buf *frag); + +/** + * @brief Get UDP checksum from network packet. + * + * @param pkt Network packet + * @param frag Fragment where to start calculating the offset. + * Typically this is set to pkt->frags by the caller. + * + * @return Return the checksum in host byte order. + */ +u16_t net_udp_get_chksum(struct net_pkt *pkt, struct net_buf *frag); + +/** + * @brief Append UDP packet into net_pkt + * + * @param context Network context for a connection + * @param pkt Network packet + * @param port Destination port in network byte order. + * + * @return Return network packet that contains the UDP packet. + */ +struct net_pkt *net_udp_append(struct net_context *context, + struct net_pkt *pkt, + u16_t port); + +/** + * @brief Insert UDP packet into net_pkt after specific offset. + * + * @param context Network context for a connection + * @param pkt Network packet + * @param offset Offset where to insert (typically after IP header) + * @param port Destination port in network byte order. + * + * @return Return network packet that contains the UDP packet or NULL if + * there is an failure. + */ +struct net_pkt *net_udp_insert(struct net_context *context, + struct net_pkt *pkt, + u16_t offset, + u16_t port); + +#else +#define net_udp_append_raw(pkt, src_port, dst_port) (pkt) +#define net_udp_append(context, pkt, port) (pkt) +#define net_udp_insert_raw(pkt, offset, src_port, dst_port) (pkt) +#define net_udp_insert(context, pkt, offset, port) (pkt) +#define net_udp_get_chksum(pkt, frag) (0) +#define net_udp_set_chksum(pkt, frag) NULL +#endif /* CONFIG_NET_UDP */ + +/** + * @brief Register a callback to be called when UDP packet + * is received corresponding to received packet. + * + * @param remote_addr Remote address of the connection end point. + * @param local_addr Local address of the connection end point. + * @param remote_port Remote port of the connection end point. + * @param local_port Local port of the connection end point. + * @param cb Callback to be called + * @param user_data User data supplied by caller. + * @param handle UDP handle that can be used when unregistering + * + * @return Return 0 if the registration succeed, <0 otherwise. + */ +int net_udp_register(const struct sockaddr *remote_addr, + const struct sockaddr *local_addr, + u16_t remote_port, + u16_t local_port, + net_conn_cb_t cb, + void *user_data, + struct net_conn_handle **handle); + +/** + * @brief Unregister UDP handler. + * + * @param handle Handle from registering. + * + * @return Return 0 if the unregistration succeed, <0 otherwise. + */ +int net_udp_unregister(struct net_conn_handle *handle); + +#if defined(CONFIG_NET_UDP) +void net_udp_init(void); +#else +#define net_udp_init(...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __UDP_INTERNAL_H */ diff --git a/tests/net/context/src/main.c b/tests/net/context/src/main.c index 8cc8d37d0c7..15b13041c99 100644 --- a/tests/net/context/src/main.c +++ b/tests/net/context/src/main.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "net_private.h" @@ -1074,6 +1075,8 @@ static void net_context_iface_init(struct net_if *iface) static int tester_send(struct net_if *iface, struct net_pkt *pkt) { + struct net_udp_hdr hdr, *udp_hdr; + if (!pkt->frags) { TC_ERROR("No data to send!\n"); return -ENODATA; @@ -1110,9 +1113,16 @@ static int tester_send(struct net_if *iface, struct net_pkt *pkt) net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr); } - port = NET_UDP_HDR(pkt)->src_port; - NET_UDP_HDR(pkt)->src_port = NET_UDP_HDR(pkt)->dst_port; - NET_UDP_HDR(pkt)->dst_port = port; + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (!udp_hdr) { + TC_ERROR("UDP data receive failed."); + goto out; + } + + port = udp_hdr->src_port; + udp_hdr->src_port = udp_hdr->dst_port; + udp_hdr->dst_port = port; + net_udp_set_hdr(pkt, udp_hdr); if (net_recv_data(iface, pkt) < 0) { TC_ERROR("Data receive failed."); diff --git a/tests/net/dhcpv4/prj.conf b/tests/net/dhcpv4/prj.conf index 9f956ff30c7..8e3babb3112 100644 --- a/tests/net/dhcpv4/prj.conf +++ b/tests/net/dhcpv4/prj.conf @@ -15,9 +15,15 @@ CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=1 CONFIG_NET_DEBUG_IF=y CONFIG_NET_DEBUG_CORE=y +CONFIG_NET_DEBUG_ICMPV4=y CONFIG_NET_DEBUG_DHCPV4=y +CONFIG_NET_DEBUG_IPV4=y +CONFIG_NET_DEBUG_CONN=y +CONFIG_NET_IPV4=y CONFIG_NET_IPV6=n -#CONFIG_SYS_LOG_NET_LEVEL=4 +#CONFIG_NET_DEBUG_L2_ETHERNET=y +#CONFIG_NET_DEBUG_NET_PKT=y +CONFIG_SYS_LOG_NET_LEVEL=2 CONFIG_NET_MGMT=y CONFIG_NET_MGMT_EVENT=y diff --git a/tests/net/dhcpv4/src/main.c b/tests/net/dhcpv4/src/main.c index d8801c77407..caffc76cfcc 100644 --- a/tests/net/dhcpv4/src/main.c +++ b/tests/net/dhcpv4/src/main.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -250,7 +251,9 @@ static void set_udp_header(struct net_pkt *pkt) struct net_udp_hdr *udp; u16_t length; - udp = NET_UDP_HDR(pkt); + udp = (struct net_udp_hdr *)((u8_t *)(NET_IPV4_HDR(pkt)) + + sizeof(struct net_ipv4_hdr)); + udp->src_port = htons(SERVER_PORT); udp->dst_port = htons(CLIENT_PORT); @@ -474,7 +477,6 @@ static int tester_send(struct net_if *iface, struct net_pkt *pkt) } parse_dhcp_message(pkt, &msg); - net_pkt_unref(pkt); if (msg.type == DISCOVER) { /* Reply with DHCPv4 offer message */ @@ -500,6 +502,7 @@ static int tester_send(struct net_if *iface, struct net_pkt *pkt) return -EINVAL; } + net_pkt_unref(pkt); return NET_OK; } diff --git a/tests/net/ipv6_fragment/src/main.c b/tests/net/ipv6_fragment/src/main.c index 056c73789b0..844aac75a63 100644 --- a/tests/net/ipv6_fragment/src/main.c +++ b/tests/net/ipv6_fragment/src/main.c @@ -25,7 +25,7 @@ #include "net_private.h" #include "ipv6.h" -#include "udp.h" +#include "udp_internal.h" #if defined(CONFIG_NET_DEBUG_IPV6) #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__) @@ -664,8 +664,7 @@ static void send_ipv6_fragment(void) NET_IPV6_HDR(pkt)->len[1] = total_len - NET_IPV6_HDR(pkt)->len[0] * 256; - NET_UDP_HDR(pkt)->chksum = 0; - NET_UDP_HDR(pkt)->chksum = ~net_calc_chksum_udp(pkt); + net_udp_set_chksum(pkt, pkt->frags); test_failed = false; diff --git a/tests/net/udp/prj.conf b/tests/net/udp/prj.conf index 76623658c41..5c5d264be78 100644 --- a/tests/net/udp/prj.conf +++ b/tests/net/udp/prj.conf @@ -1,6 +1,7 @@ CONFIG_NETWORKING=y CONFIG_NET_L2_DUMMY=y CONFIG_NET_UDP=y +CONFIG_NET_TCP=n CONFIG_NET_MAX_CONN=64 CONFIG_NET_CONN_CACHE=y CONFIG_NET_IPV6=y @@ -21,6 +22,7 @@ CONFIG_NET_DEBUG_CORE=y CONFIG_NET_DEBUG_CONN=y #CONFIG_NET_DEBUG_NET_PKT=y #CONFIG_NET_DEBUG_IF=y +CONFIG_SYS_LOG_NET_LEVEL=2 # Turn off UDP checksum checking as the test fails otherwise. CONFIG_NET_UDP_CHECKSUM=n diff --git a/tests/net/udp/src/main.c b/tests/net/udp/src/main.c index e02858408f4..b6eae389f78 100644 --- a/tests/net/udp/src/main.c +++ b/tests/net/udp/src/main.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -31,11 +32,17 @@ #define DBG(fmt, ...) #endif -#include "udp.h" +#include "udp_internal.h" + +#if defined(CONFIG_NET_DEBUG_UDP) +#define NET_LOG_ENABLED 1 +#endif #include "net_private.h" +static bool test_failed; static bool fail = true; static struct k_sem recv_lock; +static char payload[] = { 'f', 'o', 'o', 'b', 'a', 'r', '\0' }; struct net_udp_context { u8_t mac_addr[sizeof(struct net_eth_addr)]; @@ -171,6 +178,8 @@ static enum net_verdict test_fail(struct net_conn *conn, return NET_DROP; } +#define NET_UDP_HDR(pkt) ((struct net_udp_hdr *)(net_pkt_udp_data(pkt))) + static void setup_ipv6_udp(struct net_pkt *pkt, struct in6_addr *remote_addr, struct in6_addr *local_addr, @@ -181,7 +190,7 @@ static void setup_ipv6_udp(struct net_pkt *pkt, NET_IPV6_HDR(pkt)->tcflow = 0; NET_IPV6_HDR(pkt)->flow = 0; NET_IPV6_HDR(pkt)->len[0] = 0; - NET_IPV6_HDR(pkt)->len[1] = NET_UDPH_LEN; + NET_IPV6_HDR(pkt)->len[1] = NET_UDPH_LEN + strlen(payload); NET_IPV6_HDR(pkt)->nexthdr = IPPROTO_UDP; NET_IPV6_HDR(pkt)->hop_limit = 255; @@ -190,14 +199,114 @@ static void setup_ipv6_udp(struct net_pkt *pkt, net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, local_addr); net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); - - NET_UDP_HDR(pkt)->src_port = htons(remote_port); - NET_UDP_HDR(pkt)->dst_port = htons(local_port); - net_pkt_set_ipv6_ext_len(pkt, 0); net_buf_add(pkt->frags, net_pkt_ip_hdr_len(pkt) + sizeof(struct net_udp_hdr)); + + NET_UDP_HDR(pkt)->src_port = htons(remote_port); + NET_UDP_HDR(pkt)->dst_port = htons(local_port); + + net_buf_add_mem(pkt->frags, payload, strlen(payload)); +} + +u8_t ipv6_hop_by_hop_ext_hdr[] = { +/* Next header UDP */ +0x11, +/* Length (multiple of 8 octets) */ +0x0C, +/* Experimental extension */ +0x3e, +/* Length in bytes */ +0x20, +0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, +0x49, 0x4A, 0x4B, 0x4C, 0x4E, 0x4F, 0x50, 0x51, +0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, +0x5A, 0x5B, 0x5C, 0x5D, 0x5F, 0x60, 0x61, 0x62, +/* Another experimental extension */ +0x3e, +/* Length in bytes */ +0x20, +0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, +0x6B, 0x6C, 0x6D, 0x6F, 0x70, 0x71, 0x72, 0x73, +0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, +0x7C, 0x7D, 0x7E, 0x21, 0x22, 0x23, 0x24, 0x25, +/* Another experimental extension */ +0x3e, +/* Length in bytes */ +0x20, +0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, +0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, +0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, +0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, +}; + +static void setup_ipv6_udp_long(struct net_pkt *pkt, + struct in6_addr *remote_addr, + struct in6_addr *local_addr, + u16_t remote_port, + u16_t local_port) +{ + struct net_udp_hdr hdr, *udp_hdr; + struct net_ipv6_hdr ipv6; + + ipv6.vtc = 0x60; + ipv6.tcflow = 0; + ipv6.flow = 0; + ipv6.len[0] = 0; + ipv6.len[1] = NET_UDPH_LEN + strlen(payload) + + sizeof(ipv6_hop_by_hop_ext_hdr); + + ipv6.nexthdr = 0; /* HBHO */ + ipv6.hop_limit = 255; + + net_ipaddr_copy(&ipv6.src, remote_addr); + net_ipaddr_copy(&ipv6.dst, local_addr); + + net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); + + hdr.src_port = htons(remote_port); + hdr.dst_port = htons(local_port); + + net_pkt_append_all(pkt, sizeof(ipv6), (u8_t *)&ipv6, K_FOREVER); + net_pkt_append_all(pkt, sizeof(ipv6_hop_by_hop_ext_hdr), + ipv6_hop_by_hop_ext_hdr, K_FOREVER); + net_pkt_append_all(pkt, sizeof(hdr), (u8_t *)&hdr, K_FOREVER); + net_pkt_append_all(pkt, strlen(payload), payload, K_FOREVER); + + net_pkt_set_ipv6_ext_len(pkt, sizeof(ipv6_hop_by_hop_ext_hdr)); + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (udp_hdr != &hdr) { + TC_ERROR("Invalid UDP header pointer\n"); + return; + } + + udp_hdr->src_port = htons(remote_port); + udp_hdr->dst_port = htons(local_port); + + net_udp_set_hdr(pkt, &hdr); + + udp_hdr = net_udp_get_hdr(pkt, &hdr); + if (udp_hdr != &hdr) { + TC_ERROR("Invalid UDP header pointer %p\n", udp_hdr); + test_failed = true; + return; + } + + if (udp_hdr->src_port != htons(remote_port)) { + TC_ERROR("Invalid remote port, should have been %d was %d\n", + remote_port, ntohs(udp_hdr->src_port)); + test_failed = true; + } + + if (udp_hdr->dst_port != htons(local_port)) { + TC_ERROR("Invalid local port, should have been %d was %d\n", + local_port, ntohs(udp_hdr->dst_port)); + test_failed = true; + } + + net_hexdump_frags("frag", pkt); } static void setup_ipv4_udp(struct net_pkt *pkt, @@ -210,7 +319,7 @@ static void setup_ipv4_udp(struct net_pkt *pkt, NET_IPV4_HDR(pkt)->tos = 0; NET_IPV4_HDR(pkt)->len[0] = 0; NET_IPV4_HDR(pkt)->len[1] = NET_UDPH_LEN + - sizeof(struct net_ipv4_hdr); + sizeof(struct net_ipv4_hdr) + strlen(payload); NET_IPV4_HDR(pkt)->proto = IPPROTO_UDP; @@ -218,14 +327,15 @@ static void setup_ipv4_udp(struct net_pkt *pkt, net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, local_addr); net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr)); - - NET_UDP_HDR(pkt)->src_port = htons(remote_port); - NET_UDP_HDR(pkt)->dst_port = htons(local_port); - net_pkt_set_ipv6_ext_len(pkt, 0); net_buf_add(pkt->frags, net_pkt_ip_hdr_len(pkt) + sizeof(struct net_udp_hdr)); + + NET_UDP_HDR(pkt)->src_port = htons(remote_port); + NET_UDP_HDR(pkt)->dst_port = htons(local_port); + + net_buf_add_mem(pkt->frags, payload, strlen(payload)); } #define TIMEOUT 200 @@ -258,11 +368,59 @@ static bool send_ipv6_udp_msg(struct net_if *iface, } if (k_sem_take(&recv_lock, TIMEOUT)) { - printk("Timeout, packet not received\n"); if (expect_failure) { - return false; - } else { return true; + } else { + printk("Timeout, packet not received\n"); + return false; + } + } + + /* Check that the returned user data is the same as what was given + * as a parameter. + */ + if (ud != returned_ud && !expect_failure) { + printk("IPv6 wrong user data %p returned, expected %p\n", + returned_ud, ud); + return false; + } + + return !fail; +} + +static bool send_ipv6_udp_long_msg(struct net_if *iface, + struct in6_addr *src, + struct in6_addr *dst, + u16_t src_port, + u16_t dst_port, + struct ud *ud, + bool expect_failure) +{ + struct net_pkt *pkt; + struct net_buf *frag; + int ret; + + pkt = net_pkt_get_reserve_tx(0, K_FOREVER); + frag = net_pkt_get_frag(pkt, K_FOREVER); + net_pkt_frag_add(pkt, frag); + + net_pkt_set_iface(pkt, iface); + net_pkt_set_ll_reserve(pkt, net_buf_headroom(frag)); + + setup_ipv6_udp_long(pkt, src, dst, src_port, dst_port); + + ret = net_recv_data(iface, pkt); + if (ret < 0) { + printk("Cannot recv pkt %p, ret %d\n", pkt, ret); + return false; + } + + if (k_sem_take(&recv_lock, TIMEOUT)) { + if (expect_failure) { + return true; + } else { + printk("Timeout, packet not received\n"); + return false; } } @@ -306,11 +464,11 @@ static bool send_ipv4_udp_msg(struct net_if *iface, } if (k_sem_take(&recv_lock, TIMEOUT)) { - printk("Timeout, packet not received\n"); if (expect_failure) { - return false; - } else { return true; + } else { + printk("Timeout, packet not received\n"); + return false; } } @@ -422,7 +580,8 @@ static bool run_tests(void) user_data.local_addr = (struct sockaddr *)laddr; \ user_data.remote_port = rport; \ user_data.local_port = lport; \ - user_data.test = #raddr"-"#laddr"-"#rport"-"#lport; \ + user_data.test = "DST="#raddr"-SRC="#laddr"-RP="#rport \ + "-LP="#lport; \ \ set_port(family, (struct sockaddr *)raddr, \ (struct sockaddr *)laddr, rport, lport); \ @@ -448,7 +607,7 @@ static bool run_tests(void) test_fail, INT_TO_POINTER(0), NULL); \ if (!ret) { \ printk("UDP register invalid match %s failed\n", \ - #raddr"-"#laddr"-"#rport"-"#lport); \ + "DST="#raddr"-SRC="#laddr"-RP="#rport"-LP="#lport); \ return false; \ } @@ -469,6 +628,15 @@ static bool run_tests(void) return false; \ } +#define TEST_IPV6_LONG_OK(ud, raddr, laddr, rport, lport) \ + st = send_ipv6_udp_long_msg(iface, raddr, laddr, rport, lport, ud, \ + false); \ + if (!st) { \ + printk("%d: UDP long test \"%s\" fail\n", __LINE__, \ + ud->test); \ + return false; \ + } + #define TEST_IPV4_OK(ud, raddr, laddr, rport, lport) \ st = send_ipv4_udp_msg(iface, raddr, laddr, rport, lport, ud, \ false); \ @@ -481,7 +649,7 @@ static bool run_tests(void) #define TEST_IPV6_FAIL(ud, raddr, laddr, rport, lport) \ st = send_ipv6_udp_msg(iface, raddr, laddr, rport, lport, ud, \ true); \ - if (st) { \ + if (!st) { \ printk("%d: UDP neg test \"%s\" fail\n", __LINE__, \ ud->test); \ return false; \ @@ -490,7 +658,7 @@ static bool run_tests(void) #define TEST_IPV4_FAIL(ud, raddr, laddr, rport, lport) \ st = send_ipv4_udp_msg(iface, raddr, laddr, rport, lport, ud, \ true); \ - if (st) { \ + if (!st) { \ printk("%d: UDP neg test \"%s\" fail\n", __LINE__, \ ud->test); \ return false; \ @@ -499,6 +667,8 @@ static bool run_tests(void) ud = REGISTER(AF_INET6, &any_addr6, &any_addr6, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); UNREGISTER(ud); @@ -520,6 +690,8 @@ static bool run_tests(void) ud = REGISTER(AF_INET6, NULL, &any_addr6, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); UNREGISTER(ud); @@ -548,6 +720,7 @@ static bool run_tests(void) ud = REGISTER(AF_UNSPEC, NULL, NULL, 0, 0); TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 12345, 42421); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 12345, 42421); + TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 12345, 42421); /* Remote addr same as local addr, these two will never match */ REGISTER(AF_INET6, &my_addr6, NULL, 1234, 4242); @@ -585,7 +758,9 @@ void main(void) { k_thread_priority_set(k_current_get(), K_PRIO_COOP(7)); - if (run_tests()) { + test_failed = false; + + if (run_tests() || !test_failed) { TC_END_REPORT(TC_PASS); } else { TC_END_REPORT(TC_FAIL);