From d5222f6d05e52bebab7244b80a4acecc49909f7b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 26 Nov 2018 20:31:25 +0100 Subject: [PATCH 01/70] net/pkt: Add dummy getter/setters for IPv4/IPv6 attributes All as static inline functions to let the compiler check the types etc... And use ARG_UNUSED() always where relevant. Signed-off-by: Tomasz Bursztyka --- include/net/net_pkt.h | 129 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 7 deletions(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index 308be12eba18d..a70cf305b2ae9 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -366,6 +366,20 @@ static inline void net_pkt_set_ipv4_ttl(struct net_pkt *pkt, { pkt->ipv4_ttl = ttl; } +#else +static inline u8_t net_pkt_ipv4_ttl(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv4_ttl(struct net_pkt *pkt, + u8_t ttl) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(ttl); +} #endif #if defined(CONFIG_NET_IPV6) @@ -411,6 +425,62 @@ static inline void net_pkt_set_ipv6_hop_limit(struct net_pkt *pkt, { pkt->ipv6_hop_limit = hop_limit; } +#else /* CONFIG_NET_IPV6 */ +static inline u8_t net_pkt_ipv6_ext_opt_len(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv6_ext_opt_len(struct net_pkt *pkt, + u8_t len) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(len); +} + +static inline u16_t net_pkt_ipv6_ext_len(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv6_ext_len(struct net_pkt *pkt, u16_t len) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(len); +} + +static inline u16_t net_pkt_ipv6_hdr_prev(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv6_hdr_prev(struct net_pkt *pkt, + u16_t offset) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(offset); +} + +static inline u8_t net_pkt_ipv6_hop_limit(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv6_hop_limit(struct net_pkt *pkt, + u8_t hop_limit) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(hop_limit); +} +#endif /* CONFIG_NET_IPV6 */ #if defined(CONFIG_NET_IPV6_FRAGMENT) static inline u16_t net_pkt_ipv6_fragment_start(struct net_pkt *pkt) @@ -445,11 +515,49 @@ static inline void net_pkt_set_ipv6_fragment_id(struct net_pkt *pkt, { pkt->ipv6_fragment_id = id; } +#else /* CONFIG_NET_IPV6_FRAGMENT */ +static inline u16_t net_pkt_ipv6_fragment_start(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv6_fragment_start(struct net_pkt *pkt, + u16_t start) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(start); +} + +static inline u16_t net_pkt_ipv6_fragment_offset(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv6_fragment_offset(struct net_pkt *pkt, + u16_t offset) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(offset); +} + +static inline u32_t net_pkt_ipv6_fragment_id(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv6_fragment_id(struct net_pkt *pkt, + u32_t id) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(id); +} #endif /* CONFIG_NET_IPV6_FRAGMENT */ -#else /* CONFIG_NET_IPV6 */ -#define net_pkt_ipv6_ext_len(...) 0 -#define net_pkt_set_ipv6_ext_len(...) -#endif /* CONFIG_NET_IPV6 */ #if NET_TC_COUNT > 1 static inline u8_t net_pkt_priority(struct net_pkt *pkt) @@ -676,14 +784,21 @@ static inline void net_pkt_set_ipv4_auto(struct net_pkt *pkt, { pkt->ipv4_auto_arp_msg = is_auto_arp_msg; } -#else +#else /* CONFIG_NET_IPV4_AUTO */ static inline bool net_pkt_ipv4_auto(struct net_pkt *pkt) { + ARG_UNUSED(pkt); + return false; } -#define net_pkt_set_ipv4_auto(...) -#endif +static inline void net_pkt_set_ipv4_auto(struct net_pkt *pkt, + bool is_auto_arp_msg) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(is_auto_arp_msg); +} +#endif /* CONFIG_NET_IPV4_AUTO */ #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)) From cecd4c4354c415fb27138b84533921a768e8b935 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 23 Nov 2018 16:23:14 +0100 Subject: [PATCH 02/70] net/pkt: Add new allocators These struct net_pkt allocators will give the possibility to allocate at once the net_pkt and the buffer associated with, taking care of the header space and MTU relevantly. This enables to use the variable length allocator from net_buf. However, it is not yet the default and is set as experimental. As it is provided in parallel to existing allocators, it has to keep a slab per-direction and thus a pointer in net_pkt, as well as appdata, appdatalen etc... Resulting in "bloating" net_pkt. This will be solved when, finally, former allocators will be removed. Signed-off-by: Tomasz Bursztyka --- include/net/net_pkt.h | 167 +++++++++++++- subsys/net/ip/Kconfig | 39 +++- subsys/net/ip/net_pkt.c | 487 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 679 insertions(+), 14 deletions(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index a70cf305b2ae9..203e05360f44d 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -55,8 +55,11 @@ struct net_pkt { /** Slab pointer from where it belongs to */ struct k_mem_slab *slab; - /** List of buffer fragments holding the packet */ - struct net_buf *frags; + /** buffer holding the packet */ + union { + struct net_buf *frags; + struct net_buf *buffer; + }; /** Network connection context */ struct net_context *context; @@ -1996,6 +1999,166 @@ const char *net_pkt_pool2str(struct net_buf_pool *pool); #define net_pkt_print(...) #endif /* CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG */ +/* New allocator, and API are defined below. + * This will be simpler when time will come to get rid of former API above. + */ +#if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC) || \ + (CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG) + +struct net_pkt *net_pkt_alloc_debug(s32_t timeout, + const char *caller, int line); +#define net_pkt_alloc(_timeout) \ + net_pkt_alloc_debug(_timeout, __func__, __LINE__) + +struct net_pkt *net_pkt_rx_alloc_debug(s32_t timeout, + const char *caller, int line); +#define net_pkt_rx_alloc(_timeout) \ + net_pkt_rx_alloc_debug(_timeout, __func__, __LINE__) + +struct net_pkt *net_pkt_alloc_on_iface_debug(struct net_if *iface, + s32_t timeout, + const char *caller, + int line); +#define net_pkt_alloc_on_iface(_iface, _timeout) \ + net_pkt_alloc_on_iface_debug(_iface, _timeout, __func__, __LINE__) + +struct net_pkt *net_pkt_rx_alloc_on_iface_debug(struct net_if *iface, + s32_t timeout, + const char *caller, + int line); +#define net_pkt_rx_alloc_on_iface(_iface, _timeout) \ + net_pkt_rx_alloc_on_iface_debug(_iface, _timeout, \ + __func__, __LINE__) + +int net_pkt_alloc_buffer_debug(struct net_pkt *pkt, + size_t size, + enum net_ip_protocol proto, + s32_t timeout, + const char *caller, int line); +#define net_pkt_alloc_buffer(_pkt, _size, _proto, _timeout) \ + net_pkt_alloc_buffer_debug(_pkt, _size, _proto, _timeout, \ + __func__, __LINE__) + +struct net_pkt *net_pkt_alloc_with_buffer_debug(struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout, + const char *caller, + int line); +#define net_pkt_alloc_with_buffer(_iface, _size, _family, \ + _proto, _timeout) \ + net_pkt_alloc_with_buffer_debug(_iface, _size, _family, \ + _proto, _timeout, \ + __func__, __LINE__) + +struct net_pkt *net_pkt_rx_alloc_with_buffer_debug(struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout, + const char *caller, + int line); +#define net_pkt_rx_alloc_with_buffer(_iface, _size, _family, \ + _proto, _timeout) \ + net_pkt_rx_alloc_with_buffer_debug(_iface, _size, _family, \ + _proto, _timeout, \ + __func__, __LINE__) +#else + +/** + * @brief Allocate an initialized net_pkt + * + * Note: for the time being, 2 pools are used. One for TX and one for RX. + * This allocater has to be used for TX. + * + * @param timeout Maximum time in milliseconds to wait for an allocation. + * + * @return a pointer to a newly allocated net_pkt on success, NULL otherwise. + */ +struct net_pkt *net_pkt_alloc(s32_t timeout); + +/** + * @brief Allocate an initialized net_pkt for RX + * + * Note: for the time being, 2 pools are used. One for TX and one for RX. + * This allocater has to be used for RX. + * + * @param timeout Maximum time in milliseconds to wait for an allocation. + * + * @return a pointer to a newly allocated net_pkt on success, NULL otherwise. + */ +struct net_pkt *net_pkt_rx_alloc(s32_t timeout); + +/** + * @brief Allocate a network packet for a specific network interface. + * + * @param iface The network interface the packet is supposed to go through. + * @param timeout Maximum time in milliseconds to wait for an allocation. + * + * @return a pointer to a newly allocated net_pkt on success, NULL otherwise. + */ +struct net_pkt *net_pkt_alloc_on_iface(struct net_if *iface, s32_t timeout); + +/* Same as above but specifically for RX packet */ +struct net_pkt *net_pkt_rx_alloc_on_iface(struct net_if *iface, s32_t timeout); + +/** + * @brief Allocate buffer for a net_pkt + * + * Note: such allocator will take into account space necessary for headers, + * MTU, and existing buffer (if any). Beware that, due to all these + * criterias, the allocated size might be smaller/bigger than requested + * one. + * + * @param pkt The network packet requiring buffer to be allocated. + * @param size The size of buffer being requested. + * @param proto The IP protocol type (can be 0 for none). + * @param timeout Maximum time in milliseconds to wait for an allocation. + * + * @return 0 on success, negative errno code otherwise. + */ +int net_pkt_alloc_buffer(struct net_pkt *pkt, + size_t size, + enum net_ip_protocol proto, + s32_t timeout); + +/** + * @brief Allocate a network packet and buffer at once + * + * @param iface The network interface the packet is supposed to go through. + * @param size The size of buffer being requested. + * @param family The family to which the packet belongs to. + * @param proto The IP protocol type (can be 0 for none). + * @param timeout Maximum time in milliseconds to wait for an allocation. + * + * @return a pointer to a newly allocated net_pkt on success, NULL otherwise. + */ +struct net_pkt *net_pkt_alloc_with_buffer(struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout); + +/* Same as above but specifically for RX packet */ +struct net_pkt *net_pkt_rx_alloc_with_buffer(struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout); + +#endif /* CONFIG_NET_DEBUG_NET_PKT_ALLOC | + * CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG + */ + +/** + * @brief Append a buffer in packet + * + * @param pkt Network packet where to append the buffer + * @param buffer Buffer to append + */ +void net_pkt_append_buffer(struct net_pkt *pkt, struct net_buf *buffer); + /** * @} */ diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 989b5dd9cc155..5008fb6d8cf68 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -435,17 +435,42 @@ config NET_BUF_TX_COUNT Each data buffer will occupy CONFIG_NET_BUF_DATA_SIZE + smallish header (sizeof(struct net_buf)) amount of data. +choice + prompt "Network packet data allocator type" + default NET_BUF_FIXED_DATA_SIZE + help + Select the memory allocator for the network buffers that hold the + packet data. + +config NET_BUF_FIXED_DATA_SIZE + bool "Fixed data size buffer" + help + Each buffer comes with a built time configured size. If runtime + requested is bigger than that, it will allocate as many net_buf + as necessary to reach that request. + +config NET_BUF_VARIABLE_DATA_SIZE + bool "Variable data size buffer [EXPERIMENTAL]" + help + The buffer is dynamically allocated from runtime requested size. + +endchoice + config NET_BUF_DATA_SIZE int "Size of each network data fragment" - default 125 if NET_L2_IEEE802154 default 128 + depends on NET_BUF_FIXED_DATA_SIZE + help + This value tells what is the fixed size of each network buffer. + +config NET_BUF_DATA_POOL_SIZE + int "Size of the memory pool where buffers are allocated from" + default 4096 if NET_L2_ETHERNET + default 2048 + depends on NET_BUF_VARIABLE_DATA_SIZE help - This value tells what is the size of the data fragment that is - received from the network. - Example: For IEEE 802.15.4, the network packet is 127 bytes long, - which leaves in worst case 81 bytes for user data (MTU). - In order to be able to receive at least full IPv6 packet which - has a size of 1280 bytes, the one should allocate 16 fragments here. + This value tell what is the size of the memory pool where each + network buffer is allocated from. choice prompt "Default Network Interface" diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index ee9674322de2f..68ec62baab16c 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -81,12 +81,24 @@ LOG_MODULE_REGISTER(net_pkt, CONFIG_NET_PKT_LOG_LEVEL); #error "Too small net_buf fragment size" #endif -NET_PKT_SLAB_DEFINE(rx_pkts, CONFIG_NET_PKT_RX_COUNT); -NET_PKT_SLAB_DEFINE(tx_pkts, CONFIG_NET_PKT_TX_COUNT); +K_MEM_SLAB_DEFINE(rx_pkts, sizeof(struct net_pkt), CONFIG_NET_PKT_RX_COUNT, 4); +K_MEM_SLAB_DEFINE(tx_pkts, sizeof(struct net_pkt), CONFIG_NET_PKT_TX_COUNT, 4); -/* The data fragment pool is for storing network data. */ -NET_PKT_DATA_POOL_DEFINE(rx_bufs, CONFIG_NET_BUF_RX_COUNT); -NET_PKT_DATA_POOL_DEFINE(tx_bufs, CONFIG_NET_BUF_TX_COUNT); +#if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE) + +NET_BUF_POOL_FIXED_DEFINE(rx_bufs, CONFIG_NET_BUF_RX_COUNT, + CONFIG_NET_BUF_DATA_SIZE, NULL); +NET_BUF_POOL_FIXED_DEFINE(tx_bufs, CONFIG_NET_BUF_TX_COUNT, + CONFIG_NET_BUF_DATA_SIZE, NULL); + +#else /* !CONFIG_NET_BUF_FIXED_DATA_SIZE */ + +NET_BUF_POOL_VAR_DEFINE(rx_bufs, CONFIG_NET_BUF_RX_COUNT, + CONFIG_NET_BUF_DATA_POOL_SIZE, NULL); +NET_BUF_POOL_VAR_DEFINE(tx_bufs, CONFIG_NET_BUF_TX_COUNT, + CONFIG_NET_BUF_DATA_POOL_SIZE, NULL); + +#endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */ /* Allocation tracking is only available if separately enabled */ #if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC) @@ -2182,6 +2194,471 @@ struct net_pkt *net_pkt_clone(struct net_pkt *pkt, s32_t timeout) return clone; } +/* New allocator and API starts here */ + +#if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE) + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool, + size_t size, s32_t timeout, + const char *caller, int line) +#else +static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool, + size_t size, s32_t timeout) +#endif +{ + u32_t alloc_start = k_uptime_get_32(); + struct net_buf *first = NULL; + struct net_buf *current = NULL; + + while (size) { + struct net_buf *new; + + new = net_buf_alloc_fixed(pool, timeout); + if (!new) { + goto error; + } + + if (!first && !current) { + first = new; + } else { + current->frags = new; + } + + current = new; + if (current->size > size) { + current->size = size; + } + + size -= current->size; + + if (timeout != K_NO_WAIT && timeout != K_FOREVER) { + u32_t diff = k_uptime_get_32() - alloc_start; + + timeout -= min(timeout, diff); + } + +#if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG + NET_FRAG_CHECK_IF_NOT_IN_USE(new, new->ref + 1); + + net_pkt_alloc_add(new, false, caller, line); + + NET_DBG("%s (%s) [%d] frag %p ref %d (%s():%d)", + pool2str(pool), get_name(pool), get_frees(pool), + new, new->ref, caller, line); +#endif + } + + return first; +error: + if (first) { + net_buf_unref(first); + } + + return NULL; +} + +#else /* !CONFIG_NET_BUF_FIXED_DATA_SIZE */ + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool, + size_t size, s32_t timeout, + const char *caller, int line) +#else +static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool, + size_t size, s32_t timeout) +#endif +{ + struct net_buf *buf; + + buf = net_buf_alloc_len(pool, size, timeout); + +#if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG + NET_FRAG_CHECK_IF_NOT_IN_USE(buf, buf->ref + 1); + + net_pkt_alloc_add(buf, false, caller, line); + + NET_DBG("%s (%s) [%d] frag %p ref %d (%s():%d)", + pool2str(pool), get_name(pool), get_frees(pool), + buf, buf->ref, caller, line); +#endif + + return buf; +} + +#endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */ + +static size_t pkt_buffer_length(struct net_pkt *pkt, + size_t size, + enum net_ip_protocol proto, + size_t existing) +{ + size_t max_len = net_if_get_mtu(net_pkt_iface(pkt)); + sa_family_t family = net_pkt_family(pkt); + + /* Family vs iface MTU */ + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { + max_len = max(max_len, NET_IPV6_MTU); + } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { + max_len = max(max_len, NET_IPV4_MTU); + } + + max_len -= existing; + + return min(size, max_len); +} + +static size_t pkt_estimate_headers_length(struct net_pkt *pkt, + sa_family_t family, + enum net_ip_protocol proto) +{ + size_t hdr_len = 0; + + if (family == AF_UNSPEC) { + return 0; + } + + /* Family header */ + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { + hdr_len += NET_IPV6H_LEN; + } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { + hdr_len += NET_IPV4H_LEN; + } + + /* + protocol header */ + if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) { + hdr_len += NET_TCPH_LEN + NET_TCP_MAX_OPT_SIZE; + } else if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) { + hdr_len += NET_UDPH_LEN; + } else if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) { + hdr_len += NET_ICMPH_LEN; + } + + NET_DBG("HDRs length estimation %zu", hdr_len); + + return hdr_len; +} + +static size_t pkt_get_size(struct net_pkt *pkt) +{ + struct net_buf *buf = pkt->buffer; + size_t size = 0; + + while (buf) { + size += buf->size; + buf = buf->frags; + } + + return size; +} + + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +int net_pkt_alloc_buffer_debug(struct net_pkt *pkt, + size_t size, + enum net_ip_protocol proto, + s32_t timeout, + const char *caller, + int line) +#else +int net_pkt_alloc_buffer(struct net_pkt *pkt, + size_t size, + enum net_ip_protocol proto, + s32_t timeout) +#endif +{ + u32_t alloc_start = k_uptime_get_32(); + size_t alloc_len = 0; + size_t hdr_len = 0; + struct net_buf *buf; + + if (!size && proto == 0 && net_pkt_family(pkt) == AF_UNSPEC) { + return 0; + } + + if (k_is_in_isr()) { + timeout = K_NO_WAIT; + } + + /* Verifying existing buffer and take into account free space there */ + alloc_len = pkt_get_size(pkt) - net_pkt_get_len(pkt); + if (!alloc_len) { + /* In case of no free space, it will account for header + * space estimation + */ + hdr_len = pkt_estimate_headers_length(pkt, + net_pkt_family(pkt), + proto); + } + + /* Calculate the maximum that can be allocated depending on size */ + alloc_len = pkt_buffer_length(pkt, size + hdr_len, proto, alloc_len); + + NET_DBG("Data allocation maximum size %zu (requested %zu)", + alloc_len, size); + + if (timeout != K_NO_WAIT && timeout != K_FOREVER) { + u32_t diff = k_uptime_get_32() - alloc_start; + + timeout -= min(timeout, diff); + } + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + buf = pkt_alloc_buffer(pkt->slab == &tx_pkts ? + &tx_bufs : &rx_bufs, + alloc_len, timeout, + caller, line); +#else + buf = pkt_alloc_buffer(pkt->slab == &tx_pkts ? + &tx_bufs : &rx_bufs, + alloc_len, timeout); +#endif + + if (!buf) { + NET_ERR("Data buffer allocation failed."); + return -ENOMEM; + } + + net_pkt_append_buffer(pkt, buf); + + return 0; +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +static struct net_pkt *pkt_alloc(struct k_mem_slab *slab, s32_t timeout, + const char *caller, int line) +#else +static struct net_pkt *pkt_alloc(struct k_mem_slab *slab, s32_t timeout) +#endif +{ + struct net_pkt *pkt; + int ret; + + if (k_is_in_isr()) { + timeout = K_NO_WAIT; + } + + ret = k_mem_slab_alloc(slab, (void **)&pkt, timeout); + if (ret) { + return NULL; + } + + memset(pkt, 0, sizeof(struct net_pkt)); + + pkt->atomic_ref = ATOMIC_INIT(1); + pkt->slab = slab; + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + net_pkt_alloc_add(pkt, true, caller, line); +#endif + + return pkt; +} + + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +struct net_pkt *net_pkt_alloc_debug(s32_t timeout, + const char *caller, int line) +#else +struct net_pkt *net_pkt_alloc(s32_t timeout) +#endif +{ +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + return pkt_alloc(&tx_pkts, timeout, caller, line); +#else + return pkt_alloc(&tx_pkts, timeout); +#endif +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +struct net_pkt *net_pkt_rx_alloc_debug(s32_t timeout, + const char *caller, int line) +#else +struct net_pkt *net_pkt_rx_alloc(s32_t timeout) +#endif +{ +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + return pkt_alloc(&rx_pkts, timeout, caller, line); +#else + return pkt_alloc(&rx_pkts, timeout); +#endif +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +static struct net_pkt *pkt_alloc_on_iface(struct k_mem_slab *slab, + struct net_if *iface, s32_t timeout, + const char *caller, int line) +#else +static struct net_pkt *pkt_alloc_on_iface(struct k_mem_slab *slab, + struct net_if *iface, s32_t timeout) + +#endif +{ + struct net_pkt *pkt; + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + pkt = pkt_alloc(slab, timeout, caller, line); +#else + pkt = pkt_alloc(slab, timeout); +#endif + + if (pkt) { + net_pkt_set_iface(pkt, iface); + } + + return pkt; +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +struct net_pkt *net_pkt_alloc_on_iface_debug(struct net_if *iface, + s32_t timeout, + const char *caller, + int line) +#else +struct net_pkt *net_pkt_alloc_on_iface(struct net_if *iface, s32_t timeout) +#endif +{ +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + return pkt_alloc_on_iface(&tx_pkts, iface, timeout, caller, line); +#else + return pkt_alloc_on_iface(&tx_pkts, iface, timeout); +#endif +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +struct net_pkt *net_pkt_rx_alloc_on_iface_debug(struct net_if *iface, + s32_t timeout, + const char *caller, + int line) +#else +struct net_pkt *net_pkt_rx_alloc_on_iface(struct net_if *iface, s32_t timeout) +#endif +{ +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + return pkt_alloc_on_iface(&rx_pkts, iface, timeout, caller, line); +#else + return pkt_alloc_on_iface(&rx_pkts, iface, timeout); +#endif +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +static struct net_pkt * +pkt_alloc_with_buffer(struct k_mem_slab *slab, + struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout, + const char *caller, + int line) +#else +static struct net_pkt * +pkt_alloc_with_buffer(struct k_mem_slab *slab, + struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout) +#endif +{ + u32_t alloc_start = k_uptime_get_32(); + struct net_pkt *pkt; + int ret; + + NET_DBG("On iface %p size %zu", iface, size); + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + pkt = pkt_alloc_on_iface(slab, iface, timeout, caller, line); +#else + pkt = pkt_alloc_on_iface(slab, iface, timeout); +#endif + + if (!pkt) { + return NULL; + } + + net_pkt_set_family(pkt, family); + + if (timeout != K_NO_WAIT && timeout != K_FOREVER) { + u32_t diff = k_uptime_get_32() - alloc_start; + + timeout -= min(timeout, diff); + } + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + ret = net_pkt_alloc_buffer_debug(pkt, size, proto, timeout, + caller, line); +#else + ret = net_pkt_alloc_buffer(pkt, size, proto, timeout); +#endif + + if (ret) { + net_pkt_unref(pkt); + return NULL; + } + + return pkt; +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +struct net_pkt *net_pkt_alloc_with_buffer_debug(struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout, + const char *caller, + int line) +#else +struct net_pkt *net_pkt_alloc_with_buffer(struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout) +#endif +{ +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + return pkt_alloc_with_buffer(&tx_pkts, iface, size, family, + proto, timeout, caller, line); +#else + return pkt_alloc_with_buffer(&tx_pkts, iface, size, family, + proto, timeout); +#endif +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +struct net_pkt *net_pkt_rx_alloc_with_buffer_debug(struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout, + const char *caller, + int line) +#else +struct net_pkt *net_pkt_rx_alloc_with_buffer(struct net_if *iface, + size_t size, + sa_family_t family, + enum net_ip_protocol proto, + s32_t timeout) +#endif +{ +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + return pkt_alloc_with_buffer(&rx_pkts, iface, size, family, + proto, timeout, caller, line); +#else + return pkt_alloc_with_buffer(&rx_pkts, iface, size, family, + proto, timeout); +#endif +} + +void net_pkt_append_buffer(struct net_pkt *pkt, struct net_buf *buffer) +{ + if (!pkt->buffer) { + pkt->buffer = buffer; + } else { + net_buf_frag_insert(net_buf_frag_last(pkt->buffer), buffer); + } +} + void net_pkt_init(void) { #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG From 8e859dd7b8f6fb7e1e09477dfae60b2c4cea7343 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 26 Nov 2018 17:22:12 +0100 Subject: [PATCH 03/70] net/pkt: Add an API to read/write into the buffer in a simpler way Adding a cursor into net_pkt. This is used to read/write data in a much simpler way, for pre-allocated buffers in net_pkt. This avoids API users to deal with net_buf below directly. However, to be used - as for the new allocators - it will require deep net stack core and API changes. Signed-off-by: Tomasz Bursztyka --- include/net/net_pkt.h | 285 +++++++++++++++++++++++++++- subsys/net/ip/net_pkt.c | 408 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 692 insertions(+), 1 deletion(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index 203e05360f44d..5153defcca92a 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -42,6 +42,15 @@ extern "C" { struct net_context; + +/* buffer cursor used in net_pkt */ +struct net_pkt_cursor { + /** Current net_buf pointer by the cursor */ + struct net_buf *buf; + /** Current position in the data buffer of the net_buf */ + u8_t *pos; +}; + /* Note that if you add new fields into net_pkt, remember to update * net_pkt_clone() function. */ @@ -61,6 +70,9 @@ struct net_pkt { struct net_buf *buffer; }; + /** Internal buffer iterator used for reading/writing */ + struct net_pkt_cursor cursor; + /** Network connection context */ struct net_context *context; @@ -115,6 +127,8 @@ struct net_pkt { sys_snode_t sent_list; #endif + u8_t overwrite : 1; /* Is packet content being overwritten? */ + u8_t sent_or_eof: 1; /* For outgoing packet: is this sent or not * For incoming packet of a socket: last * packet before EOF @@ -135,7 +149,7 @@ struct net_pkt { u8_t forwarding : 1; /* Are we forwarding this pkt * Used only if defined(CONFIG_NET_ROUTE) */ - u8_t family : 4; /* IPv4 vs IPv6 */ + u8_t family : 3; /* IPv4 vs IPv6 */ u8_t ipv4_auto_arp_msg : 1; /* Is this pkt IPv4 autoconf ARP message. * Used only if * defined(CONFIG_NET_IPV4_AUTO) @@ -813,6 +827,16 @@ static inline void net_pkt_set_src_ipv6_addr(struct net_pkt *pkt) &NET_IPV6_HDR(pkt)->src); } +static inline void net_pkt_set_overwrite(struct net_pkt *pkt, bool overwrite) +{ + pkt->overwrite = overwrite; +} + +static inline bool net_pkt_is_being_overwritten(struct net_pkt *pkt) +{ + return pkt->overwrite; +} + /* @endcond */ /** @@ -2159,6 +2183,265 @@ struct net_pkt *net_pkt_rx_alloc_with_buffer(struct net_if *iface, */ void net_pkt_append_buffer(struct net_pkt *pkt, struct net_buf *buffer); +/** + * @brief Get available buffer space from a pkt + * + * @param pkt The net_pkt which buffer availabality should be evaluated + * + * @return the amount of buffer available + */ +size_t net_pkt_available_buffer(struct net_pkt *pkt); + +/** + * @brief Initialize net_pkt cursor + * + * Note: This will inialize the net_pkt cursor from its buffer. + * + * @param pkt The net_pkt which cursor is going to be initialized + */ +void net_pkt_cursor_init(struct net_pkt *pkt); + +/** + * @brief Backup net_pkt cursor + * + * @param pkt The net_pkt which cursor is going to be backuped + * @param backup The cursor where to backup net_pkt cursor + */ +static inline void net_pkt_cursor_backup(struct net_pkt *pkt, + struct net_pkt_cursor *backup) +{ + backup->buf = pkt->cursor.buf; + backup->pos = pkt->cursor.pos; +} + +/** + * @brief Restore net_pkt cursor from a backup + * + * @param pkt The net_pkt which cursor is going to be restored + * @param backup The cursor from where to restore net_pkt cursor + */ +static inline void net_pkt_cursor_restore(struct net_pkt *pkt, + struct net_pkt_cursor *backup) +{ + pkt->cursor.buf = backup->buf; + pkt->cursor.pos = backup->pos; +} + +/** + * @brief Returns current position of the cursor + * + * @param pkt The net_pkt which cursor's position is going to be returned + * + * @return cursor's position + */ +static inline void *net_pkt_cursor_get_pos(struct net_pkt *pkt) +{ + return pkt->cursor.pos; +} + +/** + * @brief Skip some data from a net_pkt + * + * Note: net_pkt's cursor should be properly initialized + * Cursor will be updated according to parameter. + * Depending on the value of pkt->overwrite bit, this function + * will affect the buffer length or not: if it's 0, skip will + * actually apply the move in the buffer as it had written in it. + * + * @param pkt The net_pkt which cursor will be updated to skip given + * amount of data from the buffer. + * @param length Amount of data to skip in the buffer + * + * @return 0 in success, negative errno code otherwise. + */ +int net_pkt_skip(struct net_pkt *pkt, size_t length); + +/** + * @brief Memset some data in a net_pkt + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip. + * Cursor will be updated according to parameter. + * + * @param pkt The net_pkt which cursor will be updated to skip given + * amount of data from the buffer. + * @param byte The byte to write in memory + * @param length Amount of data to memset with given byte + * + * @return 0 in success, negative errno code otherwise. + */ +int net_pkt_memset(struct net_pkt *pkt, int byte, size_t length); + +/** + * @brief Copy data from a packet into another one. + * + * Note: Both net_pkt cursors should be properly initialized and, + * eventally, properly positioned using net_pkt_skip. + * Cursors will be updated according to parameters. + * + * @param pkt_dst Destination network packet. + * @param pkt_src Source network packet. + * @param length Length of data to be copied. + * + * @return 0 on success, negative errno code otherwise. + */ +int net_pkt_copy_new(struct net_pkt *pkt_dst, + struct net_pkt *pkt_src, + size_t length); + +/** + * @brief Clone pkt and its fragment chain. + * + * @param pkt Original pkt to be cloned + * @param timeout Timeout to wait for free buffer + * + * @return NULL if error, cloned packet otherwise. + */ +struct net_pkt *net_pkt_clone_new(struct net_pkt *pkt, s32_t timeout); + +/** + * @brief Read some data from a net_pkt + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip. + * Cursor will be updated according to parameters. + * @param pkt The network packet from where to read some data + * @param data The destination buffer where to copy the data + * @param length The amount of data to copy + * + * @return 0 on success, negative errno code otherwise. + */ +int net_pkt_read_new(struct net_pkt *pkt, void *data, size_t length); + +/* Read u8_t data data a net_pkt */ +static inline int net_pkt_read_u8_new(struct net_pkt *pkt, u8_t *data) +{ + return net_pkt_read_new(pkt, data, 1); +} + +/** + * @brief Read u16_t big endian data from a net_pkt + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip. + * Cursor will be updated according to parameters. + * + * @param pkt The network packet from where to read + * @param data The destination u16_t where to copy the data + * + * @return 0 on success, negative errno code otherwise. + */ +int net_pkt_read_be16_new(struct net_pkt *pkt, u16_t *data); + +/** + * @brief Read u32_t big endian data from a net_pkt + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip. + * Cursor will be updated according to parameters. + * + * @param pkt The network packet from where to read + * @param data The destination u32_t where to copy the data + * + * @return 0 on success, negative errno code otherwise. + */ +int net_pkt_read_be32_new(struct net_pkt *pkt, u32_t *data); + +/** + * @brief Write data into a net_pkt + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip_read/write. + * Cursor will be updated according to parameters. + * + * @param pkt The network packet where to write + * @param data Data to be written + * @param length Length of the data to be written + * + * @return 0 on success, negative errno code otherwise. + */ +int net_pkt_write_new(struct net_pkt *pkt, const void *data, size_t length); + +/* Write u8_t data into a net_pkt. */ +static inline int net_pkt_write_u8_new(struct net_pkt *pkt, u8_t data) +{ + return net_pkt_write_new(pkt, &data, sizeof(u8_t)); +} + +/* Write u16_t big endian data into a net_pkt. */ +static inline int net_pkt_write_be16_new(struct net_pkt *pkt, u16_t data) +{ + u16_t data_be16 = htons(data); + + return net_pkt_write_new(pkt, &data_be16, sizeof(u16_t)); +} + +/* Write u32_t big endian data into a net_pkt. */ +static inline int net_pkt_write_be32_new(struct net_pkt *pkt, u32_t data) +{ + u32_t data_be32 = htonl(data); + + return net_pkt_write_new(pkt, &data_be32, sizeof(u32_t)); +} + +/* Write u32_t little endian data into a net_pkt. */ +static inline int net_pkt_write_le32_new(struct net_pkt *pkt, u32_t data) +{ + u32_t data_le32 = sys_cpu_to_le32(data); + + return net_pkt_write_new(pkt, &data_le32, sizeof(u32_t)); +} + +/** + * @brief Update the overall length of a packet + * + * Note: Unlike net_pkt_pull_new() below, this does not take packet cursor + * into account. It's mainly a helper dedicated for ipv4 and ipv6 + * input functions. It shrinks the overall length by given parameter. + * + * @param pkt Network packet + * @param length The new length of the packet + * + * @return 0 on success, negative errno code otherwise. + */ +int net_pkt_update_length(struct net_pkt *pkt, size_t length); + +/** + * @brief Remove data from the packet at current location + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip/read/write. + * + * @param pkt Network packet + * @param length Number of bytes to be removed + * + * @return 0 on success, negative errno code otherwise. + */ +int net_pkt_pull_new(struct net_pkt *pkt, size_t length); + +/** + * @brief Get the actual offset in the packet from its cursor + * + * @param pkt Network packet. + * + * @return a valid offset on success, 0 otherwise as there is nothing that + * can be done to evaluate the offset. + */ +u16_t net_pkt_get_current_offset(struct net_pkt *pkt); + +/** + * @brief Check if a data size could fit contiguously + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip_read/write. + * + * @param pkt Network packet. + * @param size The size to check for contiguity + * + * @return true if that is the case, false otherwise. + */ +bool net_pkt_is_contiguous(struct net_pkt *pkt, size_t size); + /** * @} */ diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 68ec62baab16c..f6e231aa6b5e4 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -2352,6 +2352,14 @@ static size_t pkt_get_size(struct net_pkt *pkt) return size; } +size_t net_pkt_available_buffer(struct net_pkt *pkt) +{ + if (!pkt) { + return 0; + } + + return pkt_get_size(pkt) - net_pkt_get_len(pkt); +} #if NET_LOG_LEVEL >= LOG_LEVEL_DBG int net_pkt_alloc_buffer_debug(struct net_pkt *pkt, @@ -2452,6 +2460,8 @@ static struct net_pkt *pkt_alloc(struct k_mem_slab *slab, s32_t timeout) net_pkt_alloc_add(pkt, true, caller, line); #endif + net_pkt_cursor_init(pkt); + return pkt; } @@ -2654,11 +2664,409 @@ void net_pkt_append_buffer(struct net_pkt *pkt, struct net_buf *buffer) { if (!pkt->buffer) { pkt->buffer = buffer; + net_pkt_cursor_init(pkt); } else { net_buf_frag_insert(net_buf_frag_last(pkt->buffer), buffer); } } +void net_pkt_cursor_init(struct net_pkt *pkt) +{ + pkt->cursor.buf = pkt->buffer; + if (pkt->cursor.buf) { + pkt->cursor.pos = pkt->cursor.buf->data; + } else { + pkt->cursor.pos = NULL; + } +} + +static void pkt_cursor_jump(struct net_pkt *pkt, bool write) +{ + struct net_pkt_cursor *cursor = &pkt->cursor; + + cursor->buf = cursor->buf->frags; + while (cursor->buf) { + size_t len = write ? cursor->buf->size : cursor->buf->len; + + if (!len) { + cursor->buf = cursor->buf->frags; + } else { + break; + } + } + + if (cursor->buf) { + cursor->pos = cursor->buf->data; + } else { + cursor->pos = NULL; + } +} + +static void pkt_cursor_advance(struct net_pkt *pkt, bool write) +{ + struct net_pkt_cursor *cursor = &pkt->cursor; + size_t len; + + if (!cursor->buf) { + return; + } + + len = write ? cursor->buf->size : cursor->buf->len; + if ((cursor->pos - cursor->buf->data) == len) { + pkt_cursor_jump(pkt, write); + } + + if (write) { + pkt->length += length; + } +} + +static void pkt_cursor_update(struct net_pkt *pkt, + size_t length, bool write) +{ + struct net_pkt_cursor *cursor = &pkt->cursor; + size_t len; + + if (net_pkt_is_being_overwritten(pkt)) { + write = false; + } + + len = write ? cursor->buf->size : cursor->buf->len; + if (length + (cursor->pos - cursor->buf->data) == len && + !(net_pkt_is_being_overwritten(pkt) && len < cursor->buf->size)) { + pkt_cursor_jump(pkt, write); + } else { + cursor->pos += length; + } +} + +/* Internal function that does all operation (skip/read/write/memset) */ +static int net_pkt_cursor_operate(struct net_pkt *pkt, + void *data, size_t length, + bool copy, bool write) +{ + /* We use such variable to avoid lengthy lines */ + struct net_pkt_cursor *c_op = &pkt->cursor; + + while (c_op->buf && length) { + size_t d_len, len; + + pkt_cursor_advance(pkt, net_pkt_is_being_overwritten(pkt) ? + false : write); + if (c_op->buf == NULL) { + break; + } + + if (write && !net_pkt_is_being_overwritten(pkt)) { + d_len = c_op->buf->size - (c_op->pos - c_op->buf->data); + } else { + d_len = c_op->buf->len - (c_op->pos - c_op->buf->data); + } + + if (!d_len) { + break; + } + + if (length < d_len) { + len = length; + } else { + len = d_len; + } + + if (copy) { + memcpy(write ? c_op->pos : data, + write ? data : c_op->pos, + len); + } else if (data) { + memset(c_op->pos, *(int *)data, len); + } + + if (write && !net_pkt_is_being_overwritten(pkt)) { + net_buf_add(c_op->buf, len); + } + + pkt_cursor_update(pkt, len, write); + + if (copy && data) { + data = (u8_t *) data + len; + } + + length -= len; + } + + if (length) { + NET_DBG("Still some length to go %zu", length); + return -ENOBUFS; + } + + return 0; +} + +int net_pkt_skip(struct net_pkt *pkt, size_t skip) +{ + NET_DBG("pkt %p skip %zu", pkt, skip); + + return net_pkt_cursor_operate(pkt, NULL, skip, false, true); +} + +int net_pkt_memset(struct net_pkt *pkt, int byte, size_t amount) +{ + NET_DBG("pkt %p byte %d amount %zu", pkt, byte, amount); + + return net_pkt_cursor_operate(pkt, &byte, amount, false, true); +} + +int net_pkt_read_new(struct net_pkt *pkt, void *data, size_t length) +{ + NET_DBG("pkt %p data %p length %zu", pkt, data, length); + + return net_pkt_cursor_operate(pkt, data, length, true, false); +} + +int net_pkt_read_be16_new(struct net_pkt *pkt, u16_t *data) +{ + u8_t d16[2]; + int ret; + + ret = net_pkt_read_new(pkt, d16, sizeof(u16_t)); + + *data = d16[0] << 8 | d16[1]; + + return ret; +} + +int net_pkt_read_be32_new(struct net_pkt *pkt, u32_t *data) +{ + u8_t d32[4]; + int ret; + + ret = net_pkt_read_new(pkt, d32, sizeof(u32_t)); + + *data = d32[0] << 24 | d32[1] << 16 | d32[2] << 8 | d32[3]; + + return ret; +} + +int net_pkt_write_new(struct net_pkt *pkt, const void *data, size_t length) +{ + NET_DBG("pkt %p data %p length %zu", pkt, data, length); + + return net_pkt_cursor_operate(pkt, (void *)data, length, true, true); +} + +int net_pkt_copy_new(struct net_pkt *pkt_dst, + struct net_pkt *pkt_src, + size_t length) +{ + struct net_pkt_cursor *c_dst = &pkt_dst->cursor; + struct net_pkt_cursor *c_src = &pkt_src->cursor; + + while (c_dst->buf && c_src->buf && length) { + size_t s_len, d_len, len; + + pkt_cursor_advance(pkt_dst, true); + pkt_cursor_advance(pkt_src, false); + + if (!c_dst->buf || !c_src->buf) { + break; + } + + s_len = c_src->buf->len - (c_src->pos - c_src->buf->data); + d_len = c_dst->buf->size - (c_dst->pos - c_dst->buf->data); + if (length < s_len && length < d_len) { + len = length; + } else { + if (d_len < s_len) { + len = d_len; + } else { + len = s_len; + } + } + + if (!len) { + break; + } + + memcpy(c_dst->pos, c_src->pos, len); + + if (!net_pkt_is_being_overwritten(pkt_dst)) { + net_buf_add(c_dst->buf, len); + } + + pkt_cursor_update(pkt_dst, len, true); + pkt_cursor_update(pkt_src, len, false); + + length -= len; + } + + if (length) { + NET_DBG("Still some length to go %zu", length); + return -ENOBUFS; + } + + return 0; +} + +struct net_pkt *net_pkt_clone_new(struct net_pkt *pkt, s32_t timeout) +{ + struct net_pkt *clone_pkt; + + clone_pkt = net_pkt_alloc_with_buffer(net_pkt_iface(pkt), + net_pkt_get_len(pkt), + AF_UNSPEC, 0, timeout); + if (!clone_pkt) { + return NULL; + } + + net_pkt_cursor_init(pkt); + + if (net_pkt_copy_new(clone_pkt, pkt, net_pkt_get_len(pkt))) { + net_pkt_unref(clone_pkt); + return NULL; + } + + if (clone_pkt->buffer) { + /* The link header pointers are only usable if there is + * a buffer that we copied because those pointers point + * to start of the fragment which we do not have right now. + */ + memcpy(&clone_pkt->lladdr_src, &pkt->lladdr_src, + sizeof(clone_pkt->lladdr_src)); + memcpy(&clone_pkt->lladdr_dst, &pkt->lladdr_dst, + sizeof(clone_pkt->lladdr_dst)); + } + + net_pkt_set_family(clone_pkt, net_pkt_family(pkt)); + net_pkt_set_context(clone_pkt, net_pkt_context(pkt)); + net_pkt_set_token(clone_pkt, net_pkt_token(pkt)); + net_pkt_set_next_hdr(clone_pkt, NULL); + net_pkt_set_ip_hdr_len(clone_pkt, net_pkt_ip_hdr_len(pkt)); + net_pkt_set_vlan_tag(clone_pkt, net_pkt_vlan_tag(pkt)); + net_pkt_set_timestamp(clone_pkt, net_pkt_timestamp(pkt)); + net_pkt_set_priority(clone_pkt, net_pkt_priority(pkt)); + net_pkt_set_orig_iface(clone_pkt, net_pkt_orig_iface(pkt)); + + if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { + net_pkt_set_ipv4_ttl(clone_pkt, net_pkt_ipv4_ttl(pkt)); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6) { + net_pkt_set_ipv6_hop_limit(clone_pkt, + net_pkt_ipv6_hop_limit(pkt)); + net_pkt_set_ipv6_ext_len(clone_pkt, net_pkt_ipv6_ext_len(pkt)); + net_pkt_set_ipv6_ext_opt_len(clone_pkt, + net_pkt_ipv6_ext_opt_len(pkt)); + net_pkt_set_ipv6_hdr_prev(clone_pkt, + net_pkt_ipv6_hdr_prev(pkt)); + } + + net_pkt_cursor_init(clone_pkt); + + NET_DBG("Cloned %p to %p", pkt, clone_pkt); + + return clone_pkt; +} + +int net_pkt_update_length(struct net_pkt *pkt, size_t length) +{ + struct net_buf *buf; + + for (buf = pkt->buffer; buf; buf = buf->frags) { + if (buf->len < length) { + length -= buf->len; + } else { + buf->len = length; + length = 0; + } + } + + return !length ? 0 : -EINVAL; +} + +int net_pkt_pull_new(struct net_pkt *pkt, size_t length) +{ + struct net_pkt_cursor *c_op = &pkt->cursor; + struct net_pkt_cursor backup; + + net_pkt_cursor_backup(pkt, &backup); + + while (length) { + u8_t left, rem; + + pkt_cursor_advance(pkt, false); + + left = c_op->buf->len - (c_op->pos - c_op->buf->data); + if (!left) { + break; + } + + rem = left; + if (rem > length) { + rem = length; + } + + c_op->buf->len -= rem; + left -= rem; + if (left) { + memmove(c_op->pos, c_op->pos+rem, rem); + } + + /* For now, empty buffer are not freed, and there is no + * compaction done either. + * net_pkt_pull_new() is currently used only in very specific + * places where such memory optimization would not make + * that much sense. Let's see in future if it's worth do to it. + */ + + length -= rem; + } + + net_pkt_cursor_restore(pkt, &backup); + + if (length) { + NET_DBG("Still some length to go %zu", length); + return -ENOBUFS; + } + + return 0; +} + +u16_t net_pkt_get_current_offset(struct net_pkt *pkt) +{ + struct net_buf *buf = pkt->buffer; + u16_t offset; + + if (!pkt->cursor.buf || !pkt->cursor.pos) { + return 0; + } + + offset = 0; + + while (buf != pkt->cursor.buf) { + offset += buf->len; + buf = buf->frags; + } + + offset += pkt->cursor.pos - buf->data; + + return offset; +} + +bool net_pkt_is_contiguous(struct net_pkt *pkt, size_t size) +{ + if (pkt->cursor.buf && pkt->cursor.pos) { + size_t len; + + len = net_pkt_is_being_overwritten(pkt) ? + pkt->cursor.buf->len : pkt->cursor.buf->size; + len -= pkt->cursor.pos - pkt->cursor.buf->data; + if (len >= size) { + return true; + } + } + + return false; +} + void net_pkt_init(void) { #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG From 881ebeaab812175ace8c58463b262463bdad1f9b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 27 Nov 2018 08:49:50 +0100 Subject: [PATCH 04/70] net/pkt: Add generic get/set data functions These ones would support linearizing non-contiguous area, however requiring a bit more complex type as an "accessor". Signed-off-by: Tomasz Bursztyka --- include/net/net_pkt.h | 74 +++++++++++++++++++++++++++++++++++++++++ subsys/net/ip/Kconfig | 13 ++++++++ subsys/net/ip/net_pkt.c | 55 +++++++++++++++++++++++++++--- 3 files changed, 138 insertions(+), 4 deletions(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index 5153defcca92a..fa75032ccffc4 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -2442,6 +2442,80 @@ u16_t net_pkt_get_current_offset(struct net_pkt *pkt); */ bool net_pkt_is_contiguous(struct net_pkt *pkt, size_t size); +struct net_pkt_data_access { +#if !defined(CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS) + void *data; +#endif + const size_t size; +}; + +#if defined(CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS) +#define NET_PKT_DATA_ACCESS_DEFINE(_name, _type) \ + struct net_pkt_data_access _name = { \ + .size = sizeof(_type), \ + } + +#define NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(_name, _type) \ + NET_PKT_DATA_ACCESS_DEFINE(_name, _type) + +#else +#define NET_PKT_DATA_ACCESS_DEFINE(_name, _type) \ + _type _hdr_##_name; \ + struct net_pkt_data_access _name = { \ + .data = &_hdr_##_name, \ + .size = sizeof(_type), \ + } + +#define NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(_name, _type) \ + struct net_pkt_data_access _name = { \ + .data = NULL, \ + .size = sizeof(_type), \ + } + +#endif /* CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS */ + +/** + * @brief Get data from a network packet in a contiguous way + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip_read/write. + * Cursor will be updated according to parameters. + * + * @param pkt The network packet from where to get the data. + * @param access A pointer to a valid net_pkt_data_access describing the + * data to get in a contiguous way. + * + * @return a pointer to the requested contiguous data, NULL otherwise. + */ +void *net_pkt_get_data_new(struct net_pkt *pkt, + struct net_pkt_data_access *access); + +/** + * @brief Set contiguous data into a network packet + * + * Note: net_pkt's cursor should be properly initialized and, + * eventally, properly positioned using net_pkt_skip_read/write. + * Cursor will be updated according to parameters. + * + * @param pkt The network packet to where the data should be set. + * @param access A pointer to a valid net_pkt_data_access describing the + * data to set. + * + * @return 0 on success, a negative errno otherwise. + */ +int net_pkt_set_data(struct net_pkt *pkt, + struct net_pkt_data_access *access); + +/** + * Acknowledge previously contiguous data taken from a network packet + * Packet needs to be set to overwrite mode. + */ +static inline int net_pkt_acknowledge_data(struct net_pkt *pkt, + struct net_pkt_data_access *access) +{ + return net_pkt_skip(pkt, access->size); +} + /** * @} */ diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 5008fb6d8cf68..febaf26393c71 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -472,6 +472,19 @@ config NET_BUF_DATA_POOL_SIZE This value tell what is the size of the memory pool where each network buffer is allocated from. +config NET_HEADERS_ALWAYS_CONTIGUOUS + bool + default n + help + This a hidden option, which one should use with a lot of care. + NO bug reports will be accepted if that option is enabled! + You are warned. + If you are 100% sure the headers memore space is always in a + contiguous space, this will save stack usage and ROM in net core. + This is a possible case when using IPv4 only, with + NET_BUF_FIXED_DATA_SIZE enabled and NET_BUF_DATA_SIZE of 128 for + instance. + choice prompt "Default Network Interface" default NET_DEFAULT_IF_FIRST diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index f6e231aa6b5e4..68dae1e4b084d 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -2715,10 +2715,6 @@ static void pkt_cursor_advance(struct net_pkt *pkt, bool write) if ((cursor->pos - cursor->buf->data) == len) { pkt_cursor_jump(pkt, write); } - - if (write) { - pkt->length += length; - } } static void pkt_cursor_update(struct net_pkt *pkt, @@ -2851,6 +2847,10 @@ int net_pkt_write_new(struct net_pkt *pkt, const void *data, size_t length) { NET_DBG("pkt %p data %p length %zu", pkt, data, length); + if (data == pkt->cursor.pos && net_pkt_is_contiguous(pkt, length)) { + return net_pkt_skip(pkt, length); + } + return net_pkt_cursor_operate(pkt, (void *)data, length, true, true); } @@ -3067,6 +3067,53 @@ bool net_pkt_is_contiguous(struct net_pkt *pkt, size_t size) return false; } +void *net_pkt_get_data_new(struct net_pkt *pkt, + struct net_pkt_data_access *access) +{ + if (IS_ENABLED(CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS)) { + if (!net_pkt_is_contiguous(pkt, access->size)) { + return NULL; + } + + return pkt->cursor.pos; + } else { + if (net_pkt_is_contiguous(pkt, access->size)) { + access->data = pkt->cursor.pos; + } else if (net_pkt_is_being_overwritten(pkt)) { + struct net_pkt_cursor backup; + + if (!access->data) { + NET_ERR("Uncontiguous data" + " cannot be linearized"); + return NULL; + } + + net_pkt_cursor_backup(pkt, &backup); + + if (net_pkt_read_new(pkt, access->data, access->size)) { + net_pkt_cursor_restore(pkt, &backup); + return NULL; + } + + net_pkt_cursor_restore(pkt, &backup); + } + + return access->data; + } + + return NULL; +} + +int net_pkt_set_data(struct net_pkt *pkt, + struct net_pkt_data_access *access) +{ + if (IS_ENABLED(CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS)) { + return net_pkt_skip(pkt, access->size); + } + + return net_pkt_write_new(pkt, access->data, access->size); +} + void net_pkt_init(void) { #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG From f62f755e0471de2bd4beeebb1dd757f1a4b8b278 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 27 Nov 2018 12:00:31 +0100 Subject: [PATCH 05/70] net/ipv4: Add new API to create/finalize IPv4 headers. This API is meant to work with pre-allocated net_pkt. It assumes net_pkt's buffer cursor is at the right position where to create the IPv4 header. Once done, the cursor will be placed right after the newly created IPv4 header. Finalizing assumes the same. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv4.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ subsys/net/ip/ipv4.h | 27 ++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index efdee74efaab4..90458121ec2e3 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -96,6 +96,81 @@ void net_ipv4_finalize(struct net_pkt *pkt, u8_t next_header_proto) } } +int net_ipv4_create_new(struct net_pkt *pkt, + const struct in_addr *src, + const struct in_addr *dst) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr); + struct net_ipv4_hdr *ipv4_hdr; + + ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data_new(pkt, + &ipv4_access); + if (!ipv4_hdr) { + return -ENOBUFS; + } + + ipv4_hdr->vhl = 0x45; + ipv4_hdr->tos = 0x00; + ipv4_hdr->len = 0; + ipv4_hdr->id[0] = 0; + ipv4_hdr->id[1] = 0; + ipv4_hdr->offset[0] = 0; + ipv4_hdr->offset[1] = 0; + + ipv4_hdr->ttl = net_pkt_ipv4_ttl(pkt); + if (ipv4_hdr->ttl == 0) { + ipv4_hdr->ttl = net_if_ipv4_get_ttl(net_pkt_iface(pkt)); + } + + ipv4_hdr->proto = 0; + ipv4_hdr->chksum = 0; + + net_ipaddr_copy(&ipv4_hdr->dst, dst); + net_ipaddr_copy(&ipv4_hdr->src, src); + + net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr)); + + return net_pkt_set_data(pkt, &ipv4_access); +} + +int net_ipv4_finalize_new(struct net_pkt *pkt, u8_t next_header_proto) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr); + struct net_ipv4_hdr *ipv4_hdr; + + net_pkt_set_overwrite(pkt, true); + + ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data_new(pkt, + &ipv4_access); + if (!ipv4_hdr) { + return -ENOBUFS; + } + + ipv4_hdr->len = htons(net_pkt_get_len(pkt)); + ipv4_hdr->proto = next_header_proto; + + if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt)) || + next_header_proto == IPPROTO_ICMP) { + ipv4_hdr->chksum = net_calc_chksum_ipv4(pkt); + + net_pkt_set_data(pkt, &ipv4_access); + + if (IS_ENABLED(CONFIG_NET_UDP) && + next_header_proto == IPPROTO_UDP) { + return net_udp_finalize(pkt); + } else if (IS_ENABLED(CONFIG_NET_TCP) && + next_header_proto == IPPROTO_TCP) { + net_tcp_set_chksum(pkt, pkt->buffer); + } else if (next_header_proto == IPPROTO_ICMP) { + net_icmpv4_set_chksum(pkt); + } + } else { + net_pkt_set_data(pkt, &ipv4_access); + } + + return 0; +} + const struct in_addr *net_ipv4_unspecified_address(void) { static const struct in_addr addr; diff --git a/subsys/net/ip/ipv4.h b/subsys/net/ip/ipv4.h index d38552d84f040..e0db151a69195 100644 --- a/subsys/net/ip/ipv4.h +++ b/subsys/net/ip/ipv4.h @@ -52,4 +52,31 @@ struct net_pkt *net_ipv4_create(struct net_pkt *pkt, */ void net_ipv4_finalize(struct net_pkt *pkt, u8_t next_header_proto); + +/** + * @brief Create IPv4 packet in provided net_pkt. + * + * @param pkt Network packet + * @param src Source IPv4 address + * @param dst Destination IPv4 address + * + * @return 0 on success, negative errno otherwise. + */ +int net_ipv4_create_new(struct net_pkt *pkt, + const struct in_addr *src, + const struct in_addr *dst); + +/** + * @brief Finalize IPv4 packet. It should be called right before + * sending the packet and after all the data has been added into + * the packet. This function will set the length of the + * packet and calculate the higher protocol checksum if needed. + * + * @param pkt Network packet + * @param next_header_proto Protocol type of the next header after IPv4 header. + * + * @return 0 on success, negative errno otherwise. + */ +int net_ipv4_finalize_new(struct net_pkt *pkt, u8_t next_header_proto); + #endif /* __IPV4_H */ From d97b4668f0e40c20f97d2b222d85a1ab9fdbe5bb Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 27 Nov 2018 11:34:57 +0100 Subject: [PATCH 06/70] net/udp: Add new API to create/finalize UDP headers This API is meant to work with pre-allocated net_pkt. It assumes net_pkt's buffer cursor is at the right position where to create the UDP header. Once done, the cursor will be placed right after the newly created UDP header. Finalizing assumes the same. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/udp.c | 39 ++++++++++++++++++++++++++++++++ subsys/net/ip/udp_internal.h | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/subsys/net/ip/udp.c b/subsys/net/ip/udp.c index 275a7c1c6234c..2d3a1408b1bd8 100644 --- a/subsys/net/ip/udp.c +++ b/subsys/net/ip/udp.c @@ -16,6 +16,45 @@ LOG_MODULE_REGISTER(net_udp, CONFIG_NET_UDP_LOG_LEVEL); #define PKT_WAIT_TIME K_SECONDS(1) +int net_udp_create(struct net_pkt *pkt, u16_t src_port, u16_t dst_port) +{ + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + struct net_udp_hdr *udp_hdr; + + udp_hdr = (struct net_udp_hdr *)net_pkt_get_data_new(pkt, &udp_access); + if (!udp_hdr) { + return -ENOBUFS; + } + + udp_hdr->src_port = src_port; + udp_hdr->dst_port = dst_port; + udp_hdr->len = 0; + udp_hdr->chksum = 0; + + return net_pkt_set_data(pkt, &udp_access); +} + +int net_udp_finalize(struct net_pkt *pkt) +{ + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + struct net_udp_hdr *udp_hdr; + u16_t length; + + udp_hdr = (struct net_udp_hdr *)net_pkt_get_data_new(pkt, &udp_access); + if (!udp_hdr) { + return -ENOBUFS; + } + + length = net_pkt_get_len(pkt) - + net_pkt_ip_hdr_len(pkt) - + net_pkt_ipv6_ext_len(pkt); + + udp_hdr->len = htons(length); + udp_hdr->chksum = net_calc_chksum_udp(pkt); + + return net_pkt_set_data(pkt, &udp_access); +} + struct net_pkt *net_udp_insert(struct net_pkt *pkt, u16_t offset, u16_t src_port, diff --git a/subsys/net/ip/udp_internal.h b/subsys/net/ip/udp_internal.h index 801512fd50f69..29ac4ec21b979 100644 --- a/subsys/net/ip/udp_internal.h +++ b/subsys/net/ip/udp_internal.h @@ -67,10 +67,53 @@ struct net_pkt *net_udp_insert(struct net_pkt *pkt, u16_t src_port, u16_t dst_port); +/** + * @brief Create UDP packet into net_pkt + * + * Note: pkt's cursor should be set a the right position. + * (i.e. after IP header) + * + * @param pkt Network packet + * @param src_port Destination port in network byte order. + * @param dst_port Destination port in network byte order. + * + * @return 0 on success, negative errno otherwise. + */ +int net_udp_create(struct net_pkt *pkt, u16_t src_port, u16_t dst_port); + +/** + * @brief Finalize UDP packet + * + * Note: calculates final length and setting up the checksum. + * + * @param pkt Network packet + * + * @return 0 on success, negative errno otherwise. + */ +int net_udp_finalize(struct net_pkt *pkt); + #else #define net_udp_insert(pkt, offset, src_port, dst_port) (pkt) #define net_udp_get_chksum(pkt, frag) (0) #define net_udp_set_chksum(pkt, frag) NULL + +static inline int net_udp_create(struct net_pkt *pkt, + u16_t src_port, u16_t dst_port) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(src_port); + ARG_UNUSED(dst_port); + + return 0; +} + +static inline int net_udp_finalize(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + #endif /* CONFIG_NET_UDP */ /** From 0f1b0314304a7afacf4aca0576b30558e496940f Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 27 Nov 2018 14:16:41 +0100 Subject: [PATCH 07/70] net/icmpv4: Switch echo request to new net pkt allocator and API This is the easiest piece to change using the new API, and can be used as showing how this API can be used. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv4.c | 60 ++++++++++++++++++++++++++++++------------ subsys/net/ip/icmpv4.h | 4 --- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 4a7a719a0373f..9f58a8020c8a7 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -161,51 +161,77 @@ static struct net_buf *icmpv4_create(struct net_pkt *pkt, u8_t icmp_type, return frag; } +static int icmpv4_create_new(struct net_pkt *pkt, u8_t icmp_type, + u8_t icmp_code) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, + &icmpv4_access); + if (!icmp_hdr) { + return -ENOBUFS; + } + + icmp_hdr->type = icmp_type; + icmp_hdr->code = icmp_code; + icmp_hdr->chksum = 0; + + return net_pkt_set_data(pkt, &icmpv4_access); +} + int net_icmpv4_send_echo_request(struct net_if *iface, struct in_addr *dst, u16_t identifier, u16_t sequence) { - struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4; + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, + struct net_icmpv4_echo_req); + int ret = -ENOBUFS; + struct net_icmpv4_echo_req *echo_req; const struct in_addr *src; struct net_pkt *pkt; - int ret; - if (!ipv4) { + if (!iface->config.ip.ipv4) { return -EINVAL; } /* Take the first address of the network interface */ - src = &ipv4->unicast[0].address.in_addr; + src = &iface->config.ip.ipv4->unicast[0].address.in_addr; - pkt = net_pkt_get_reserve_tx(PKT_WAIT_TIME); + pkt = net_pkt_alloc_with_buffer(iface, + sizeof(struct net_icmpv4_echo_req), + AF_INET, IPPROTO_ICMP, + PKT_WAIT_TIME); if (!pkt) { return -ENOMEM; } - net_pkt_set_iface(pkt, iface); - - if (!net_ipv4_create(pkt, src, dst, iface, IPPROTO_ICMP)) { - ret = -ENOMEM; + if (net_ipv4_create_new(pkt, src, dst) || + icmpv4_create_new(pkt, NET_ICMPV4_ECHO_REQUEST, 0)) { goto drop; } - if (!icmpv4_create(pkt, NET_ICMPV4_ECHO_REQUEST, 0)) { - ret = -ENOMEM; + echo_req = (struct net_icmpv4_echo_req *)net_pkt_get_data_new( + pkt, &icmpv4_access); + if (!echo_req) { goto drop; } - net_buf_add(pkt->frags, sizeof(struct net_icmpv4_echo_req)); + echo_req->identifier = htons(identifier); + echo_req->sequence = htons(sequence); - NET_ICMPV4_ECHO_REQ(pkt)->identifier = htons(identifier); - NET_ICMPV4_ECHO_REQ(pkt)->sequence = htons(sequence); + net_pkt_set_data(pkt, &icmpv4_access); - net_ipv4_finalize(pkt, IPPROTO_ICMP); + net_pkt_cursor_init(pkt); + + net_ipv4_finalize_new(pkt, IPPROTO_ICMP); NET_DBG("Sending ICMPv4 Echo Request type %d from %s to %s", NET_ICMPV4_ECHO_REQUEST, - log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->src)), - log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst))); + log_strdup(net_sprint_ipv4_addr(src)), + log_strdup(net_sprint_ipv4_addr(dst))); if (net_send_data(pkt) >= 0) { net_stats_update_icmp_sent(iface); diff --git a/subsys/net/ip/icmpv4.h b/subsys/net/ip/icmpv4.h index 8e47033fd240d..63f2c75c10bdf 100644 --- a/subsys/net/ip/icmpv4.h +++ b/subsys/net/ip/icmpv4.h @@ -30,10 +30,6 @@ struct net_icmpv4_echo_req { u16_t sequence; } __packed; -#define NET_ICMPV4_ECHO_REQ(pkt) \ - ((struct net_icmpv4_echo_req *)((u8_t *)net_pkt_icmp_data(pkt) + \ - sizeof(struct net_icmp_hdr))) - typedef enum net_verdict (*icmpv4_callback_handler_t)(struct net_pkt *pkt); struct net_icmpv4_handler { From 7c8d675a3b1309efc369e741219a81671cd5f2a1 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 27 Nov 2018 20:16:42 +0100 Subject: [PATCH 08/70] drivers/ethernet: Use new net_pkt API for sending and receiving Use the new API where relevant. Only sam_gmac is left aside for now. This simplifies a lot the code as the caller should only care about allocating net_pkt and its buffer once, and thus will not need to mess with "frags" etc... Signed-off-by: Tomasz Bursztyka --- drivers/ethernet/eth_dw.c | 6 +-- drivers/ethernet/eth_e1000.c | 30 +++++--------- drivers/ethernet/eth_enc28j60.c | 30 ++++---------- drivers/ethernet/eth_mcux.c | 64 +++++++---------------------- drivers/ethernet/eth_native_posix.c | 43 ++++++------------- drivers/ethernet/eth_stm32_hal.c | 14 +++---- subsys/net/l2/ethernet/ethernet.c | 2 + 7 files changed, 59 insertions(+), 130 deletions(-) diff --git a/drivers/ethernet/eth_dw.c b/drivers/ethernet/eth_dw.c index 55b7b30dc646f..f5c6e80a620ef 100644 --- a/drivers/ethernet/eth_dw.c +++ b/drivers/ethernet/eth_dw.c @@ -86,14 +86,14 @@ static void eth_rx(struct device *dev) frm_len -= sizeof(u32_t); } - pkt = net_pkt_get_reserve_rx(K_NO_WAIT); + pkt = net_pkt_rx_alloc_with_buffer(context->iface, frm_len, + AF_UNSPEC, 0, K_NO_WAIT); if (!pkt) { LOG_ERR("Failed to obtain RX buffer"); goto error; } - if (!net_pkt_append_all(pkt, frm_len, (u8_t *)context->rx_buf, - K_NO_WAIT)) { + if (net_pkt_write_new(pkt, (void *)context->rx_buf, frm_len)) { LOG_ERR("Failed to append RX buffer to context buffer"); net_pkt_unref(pkt); goto error; diff --git a/drivers/ethernet/eth_e1000.c b/drivers/ethernet/eth_e1000.c index c3da959eddfba..de0214d8752ef 100644 --- a/drivers/ethernet/eth_e1000.c +++ b/drivers/ethernet/eth_e1000.c @@ -50,19 +50,6 @@ static enum ethernet_hw_caps e1000_caps(struct device *dev) ETHERNET_LINK_1000BASE_T; } -static size_t e1000_linearize(struct net_pkt *pkt, void *buf, size_t bufsize) -{ - size_t len = 0; - struct net_buf *nb; - - for (nb = pkt->frags; nb; nb = nb->frags) { - memcpy((u8_t *) buf + len, nb->data, nb->len); - len += nb->len; - } - - return len; -} - static int e1000_tx(struct e1000_dev *dev, void *data, size_t data_len) { dev->tx.addr = POINTER_TO_INT(data); @@ -83,7 +70,11 @@ static int e1000_tx(struct e1000_dev *dev, void *data, size_t data_len) static int e1000_send(struct device *device, struct net_pkt *pkt) { struct e1000_dev *dev = device->driver_data; - size_t len = e1000_linearize(pkt, dev->txb, sizeof(dev->txb)); + size_t len = net_pkt_get_len(pkt); + + if (net_pkt_read_new(pkt, dev->txb, len)) { + return -EIO; + } return e1000_tx(dev, dev->txb, len); } @@ -99,19 +90,20 @@ static struct net_pkt *e1000_rx(struct e1000_dev *dev) goto out; } - pkt = net_pkt_get_reserve_rx(K_NO_WAIT); + pkt = net_pkt_rx_alloc_with_buffer(dev->iface, dev->rx.len - 4, + AF_UNSPEC, 0, K_NO_WAIT); if (!pkt) { - LOG_ERR("Out of RX buffers"); + LOG_ERR("Out of buffers"); goto out; } - if (!net_pkt_append_all(pkt, dev->rx.len - 4, - INT_TO_POINTER((u32_t) dev->rx.addr), - K_NO_WAIT)) { + if (net_pkt_write_new(pkt, INT_TO_POINTER((u32_t) dev->rx.addr), + dev->rx.len - 4)) { LOG_ERR("Out of memory for received frame"); net_pkt_unref(pkt); pkt = NULL; } + out: return pkt; } diff --git a/drivers/ethernet/eth_enc28j60.c b/drivers/ethernet/eth_enc28j60.c index d1c33b4111069..f00853f9cfc8b 100644 --- a/drivers/ethernet/eth_enc28j60.c +++ b/drivers/ethernet/eth_enc28j60.c @@ -500,7 +500,6 @@ static int eth_enc28j60_rx(struct device *dev) do { struct net_buf *pkt_buf = NULL; - struct net_buf *last_buf = NULL; u16_t frm_len = 0U; u8_t info[RSV_SIZE]; struct net_pkt *pkt; @@ -538,36 +537,22 @@ static int eth_enc28j60_rx(struct device *dev) lengthfr = frm_len; /* Get the frame from the buffer */ - pkt = net_pkt_get_reserve_rx(config->timeout); + pkt = net_pkt_rx_alloc_with_buffer(context->iface, frm_len, + AF_UNSPEC, 0, + config->timeout); if (!pkt) { LOG_ERR("Could not allocate rx buffer"); eth_stats_update_errors_rx(context->iface); goto done; } + pkt_buf = pkt->buffer; + do { size_t frag_len; u8_t *data_ptr; size_t spi_frame_len; - /* Reserve a data frag to receive the frame */ - pkt_buf = net_pkt_get_frag(pkt, config->timeout); - if (!pkt_buf) { - LOG_ERR("Could not allocate data buffer"); - eth_stats_update_errors_rx(context->iface); - net_pkt_unref(pkt); - - goto done; - } - - if (!last_buf) { - net_pkt_frag_insert(pkt, pkt_buf); - } else { - net_buf_frag_insert(last_buf, pkt_buf); - } - - last_buf = pkt_buf; - data_ptr = pkt_buf->data; /* Review the space available for the new frag */ @@ -585,6 +570,7 @@ static int eth_enc28j60_rx(struct device *dev) /* One fragment has been written via SPI */ frm_len -= spi_frame_len; + pkt_buf = pkt_buf->frags; } while (frm_len > 0); /* Let's pop the useless CRC */ @@ -599,7 +585,9 @@ static int eth_enc28j60_rx(struct device *dev) /* Feed buffer frame to IP stack */ LOG_DBG("Received packet of length %u", lengthfr); - net_recv_data(context->iface, pkt); + if (net_recv_data(context->iface, pkt) < 0) { + net_pkt_unref(pkt); + } done: /* Free buffer memory and decrement rx counter */ eth_enc28j60_set_bank(dev, ENC28J60_REG_ERXRDPTL); diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index b582b70037a31..79fb01816a445 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -490,16 +490,13 @@ static bool eth_get_ptp_data(struct net_if *iface, struct net_pkt *pkt, static int eth_tx(struct device *dev, struct net_pkt *pkt) { struct eth_context *context = dev->driver_data; - const struct net_buf *frag; - u8_t *dst; + u16_t total_len = net_pkt_get_len(pkt); status_t status; unsigned int imask; #if defined(CONFIG_PTP_CLOCK_MCUX) bool timestamped_frame; #endif - u16_t total_len = net_pkt_get_len(pkt); - k_sem_take(&context->tx_buf_sem, K_FOREVER); /* As context->frame_buf is shared resource used by both eth_tx @@ -507,13 +504,9 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt) */ imask = irq_lock(); - /* Copy the fragments */ - dst = context->frame_buf; - frag = pkt->frags; - while (frag) { - memcpy(dst, frag->data, frag->len); - dst += frag->len; - frag = frag->frags; + if (net_pkt_read_new(pkt, context->frame_buf, total_len)) { + irq_unlock(imask); + return -EIO; } /* FIXME: Dirty workaround. @@ -559,13 +552,11 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt) static void eth_rx(struct device *iface) { struct eth_context *context = iface->driver_data; - struct net_buf *prev_buf; - struct net_pkt *pkt; - const u8_t *src; + u16_t vlan_tag = NET_VLAN_TAG_UNSPEC; u32_t frame_length = 0U; + struct net_pkt *pkt; status_t status; unsigned int imask; - u16_t vlan_tag = NET_VLAN_TAG_UNSPEC; #if defined(CONFIG_PTP_CLOCK_MCUX) enet_ptp_time_data_t ptpTimeData; @@ -588,7 +579,9 @@ static void eth_rx(struct device *iface) goto flush; } - pkt = net_pkt_get_reserve_rx(K_NO_WAIT); + /* Using root iface. It will be updated in net_recv_data() */ + pkt = net_pkt_rx_alloc_with_buffer(context->iface, frame_length, + AF_UNSPEC, 0, K_NO_WAIT); if (!pkt) { goto flush; } @@ -607,39 +600,12 @@ static void eth_rx(struct device *iface) goto error; } - src = context->frame_buf; - prev_buf = NULL; - do { - struct net_buf *pkt_buf; - size_t frag_len; - - pkt_buf = net_pkt_get_frag(pkt, K_NO_WAIT); - if (!pkt_buf) { - irq_unlock(imask); - LOG_ERR("Failed to get fragment buf"); - net_pkt_unref(pkt); - assert(status == kStatus_Success); - goto error; - } - - if (!prev_buf) { - net_pkt_frag_insert(pkt, pkt_buf); - } else { - net_buf_frag_insert(prev_buf, pkt_buf); - } - - prev_buf = pkt_buf; - - frag_len = net_buf_tailroom(pkt_buf); - if (frag_len > frame_length) { - frag_len = frame_length; - } - - memcpy(pkt_buf->data, src, frag_len); - net_buf_add(pkt_buf, frag_len); - src += frag_len; - frame_length -= frag_len; - } while (frame_length > 0); + if (net_pkt_write_new(pkt, context->frame_buf, frame_length)) { + irq_unlock(imask); + LOG_ERR("Unable to write frame into the pkt"); + net_pkt_unref(pkt); + goto error; + } #if defined(CONFIG_NET_VLAN) { diff --git a/drivers/ethernet/eth_native_posix.c b/drivers/ethernet/eth_native_posix.c index 8ebbaf7673d3d..1225bd3011abf 100644 --- a/drivers/ethernet/eth_native_posix.c +++ b/drivers/ethernet/eth_native_posix.c @@ -210,15 +210,12 @@ static void update_gptp(struct net_if *iface, struct net_pkt *pkt, static int eth_send(struct device *dev, struct net_pkt *pkt) { struct eth_context *ctx = dev->driver_data; - struct net_buf *frag; - int count = 0; + int count = net_pkt_get_len(pkt); int ret; - frag = pkt->frags; - while (frag) { - memcpy(ctx->send + count, frag->data, frag->len); - count += frag->len; - frag = frag->frags; + ret = net_pkt_read_new(pkt, ctx->send, count); + if (ret) { + return ret; } update_gptp(net_pkt_iface(pkt), pkt, true); @@ -269,37 +266,24 @@ static inline struct net_if *get_iface(struct eth_context *ctx, static int read_data(struct eth_context *ctx, int fd) { u16_t vlan_tag = NET_VLAN_TAG_UNSPEC; - int count = 0; struct net_if *iface; struct net_pkt *pkt; - struct net_buf *frag; - u32_t pkt_len; - int ret; + int count; - ret = eth_read_data(fd, ctx->recv, sizeof(ctx->recv)); - if (ret <= 0) { + count = eth_read_data(fd, ctx->recv, sizeof(ctx->recv)); + if (count <= 0) { return 0; } - pkt = net_pkt_get_reserve_rx(NET_BUF_TIMEOUT); + pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, count, + AF_UNSPEC, 0, NET_BUF_TIMEOUT); if (!pkt) { return -ENOMEM; } - do { - frag = net_pkt_get_frag(pkt, NET_BUF_TIMEOUT); - if (!frag) { - net_pkt_unref(pkt); - return -ENOMEM; - } - - net_pkt_frag_add(pkt, frag); - - net_buf_add_mem(frag, ctx->recv + count, - min(net_buf_tailroom(frag), ret)); - ret -= frag->len; - count += frag->len; - } while (ret > 0); + if (net_pkt_write_new(pkt, ctx->recv, count)) { + return -ENOBUFS; + } #if defined(CONFIG_NET_VLAN) { @@ -325,9 +309,8 @@ static int read_data(struct eth_context *ctx, int fd) #endif iface = get_iface(ctx, vlan_tag); - pkt_len = net_pkt_get_len(pkt); - LOG_DBG("Recv pkt %p len %d", pkt, pkt_len); + LOG_DBG("Recv pkt %p len %d", pkt, count); update_gptp(iface, pkt, false); diff --git a/drivers/ethernet/eth_stm32_hal.c b/drivers/ethernet/eth_stm32_hal.c index d3b209265aa01..94ae9cdda78fc 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -61,7 +61,6 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt) ETH_HandleTypeDef *heth; u8_t *dma_buffer; int res; - struct net_buf *frag; u16_t total_len; __IO ETH_DMADescTypeDef *dma_tx_desc; @@ -88,11 +87,9 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt) dma_buffer = (u8_t *)(dma_tx_desc->Buffer1Addr); - frag = pkt->frags; - while (frag) { - memcpy(dma_buffer, frag->data, frag->len); - dma_buffer += frag->len; - frag = frag->frags; + if (net_pkt_read_new(pkt, dma_buffer, total_len)) { + res = -EIO; + goto error; } if (HAL_ETH_TransmitFrame(heth, total_len) != HAL_OK) { @@ -146,13 +143,14 @@ static struct net_pkt *eth_rx(struct device *dev) total_len = heth->RxFrameInfos.length; dma_buffer = (u8_t *)heth->RxFrameInfos.buffer; - pkt = net_pkt_get_reserve_rx(K_NO_WAIT); + pkt = net_pkt_rx_alloc_with_buffer(dev_data->iface, total_len, + AF_UNSPEC, 0, K_NO_WAIT); if (!pkt) { LOG_ERR("Failed to obtain RX buffer"); goto release_desc; } - if (!net_pkt_append_all(pkt, total_len, dma_buffer, K_NO_WAIT)) { + if (net_pkt_write_new(pkt, dma_buffer, total_len)) { LOG_ERR("Failed to append RX buffer to context buffer"); net_pkt_unref(pkt); pkt = NULL; diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c index 79679307d5c0a..43d62478b903f 100644 --- a/subsys/net/l2/ethernet/ethernet.c +++ b/subsys/net/l2/ethernet/ethernet.c @@ -559,6 +559,8 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) goto error; } + net_pkt_cursor_init(pkt); + ret = api->send(net_if_get_device(iface), pkt); if (ret != 0) { eth_stats_update_errors_tx(iface); From 2f7a89d4207b4e20758f2140a033b151c7d235d3 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 29 Nov 2018 17:08:57 +0100 Subject: [PATCH 09/70] net/dhcpv4: Switch to new net_pkt API Use new allocator and function to r/w dhcp messages. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/dhcpv4.c | 377 +++++++++++++++++++---------------------- subsys/net/ip/dhcpv4.h | 29 +++- 2 files changed, 200 insertions(+), 206 deletions(-) diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index cbb6f97547995..417c347639fe7 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -62,23 +62,21 @@ static const char *dhcpv4_msg_type_name(enum dhcpv4_msg_type msg_type) /* Add magic cookie to DCHPv4 messages */ static inline bool dhcpv4_add_cookie(struct net_pkt *pkt) { - return net_pkt_append_all(pkt, sizeof(magic_cookie), - magic_cookie, K_FOREVER); + if (net_pkt_write_new(pkt, (void *)magic_cookie, + ARRAY_SIZE(magic_cookie))) { + return false; + } + + return true; } /* Add a an option with the form OPTION LENGTH VALUE. */ static bool dhcpv4_add_option_length_value(struct net_pkt *pkt, u8_t option, - u8_t size, const u8_t *value) + u8_t size, const void *value) { - if (!net_pkt_append_u8(pkt, option)) { - return false; - } - - if (!net_pkt_append_u8(pkt, size)) { - return false; - } - - if (!net_pkt_append_all(pkt, size, value, K_FOREVER)) { + if (net_pkt_write_u8_new(pkt, option) || + net_pkt_write_u8_new(pkt, size) || + net_pkt_write_new(pkt, value, size)) { return false; } @@ -97,13 +95,12 @@ static bool dhcpv4_add_msg_type(struct net_pkt *pkt, u8_t type) */ static bool dhcpv4_add_req_options(struct net_pkt *pkt) { - static const u8_t data[5] = { DHCPV4_OPTIONS_REQ_LIST, - 3, /* Length */ - DHCPV4_OPTIONS_SUBNET_MASK, - DHCPV4_OPTIONS_ROUTER, - DHCPV4_OPTIONS_DNS_SERVER }; + static u8_t data[3] = { DHCPV4_OPTIONS_SUBNET_MASK, + DHCPV4_OPTIONS_ROUTER, + DHCPV4_OPTIONS_DNS_SERVER }; - return net_pkt_append_all(pkt, sizeof(data), data, K_FOREVER); + return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_REQ_LIST, + ARRAY_SIZE(data), data); } static bool dhcpv4_add_server_id(struct net_pkt *pkt, @@ -123,91 +120,76 @@ static bool dhcpv4_add_req_ipaddr(struct net_pkt *pkt, /* Add DHCPv4 Options end, rest of the message can be padded wit zeros */ static inline bool dhcpv4_add_end(struct net_pkt *pkt) { - return net_pkt_append_u8(pkt, DHCPV4_OPTIONS_END); -} - -/* File is empty ATM */ -static inline bool dhcpv4_add_file(struct net_pkt *pkt) -{ - const u16_t size = SIZE_OF_FILE; - - if (net_pkt_append_memset(pkt, size, 0, PKT_WAIT_TIME) != size) { + if (net_pkt_write_u8_new(pkt, DHCPV4_OPTIONS_END)) { return false; } return true; } -/* SNAME is empty ATM */ -static inline bool dhcpv4_add_sname(struct net_pkt *pkt) +/* File is empty ATM */ +static inline bool dhcpv4_add_file(struct net_pkt *pkt) { - const u16_t size = SIZE_OF_SNAME; - - if (net_pkt_append_memset(pkt, size, 0, PKT_WAIT_TIME) != size) { + if (net_pkt_memset(pkt, 0, SIZE_OF_FILE)) { return false; } return true; } -/* Setup UDP header */ -static bool dhcpv4_setup_udp_header(struct net_pkt *pkt) +/* SNAME is empty ATM */ +static inline bool dhcpv4_add_sname(struct net_pkt *pkt) { - struct net_udp_hdr hdr, *udp; - u16_t len; - - udp = net_udp_get_hdr(pkt, &hdr); - if (!udp || udp == &hdr) { - NET_ERR("Could not get UDP header"); + if (net_pkt_memset(pkt, 0, SIZE_OF_SNAME)) { return false; } - len = net_pkt_get_len(pkt) - NET_IPV4H_LEN; - - /* Setup UDP header */ - udp->src_port = htons(DHCPV4_CLIENT_PORT); - udp->dst_port = htons(DHCPV4_SERVER_PORT); - udp->len = htons(len); - - net_udp_set_hdr(pkt, udp); - return true; } -/* Prepare initial DHCPv4 message and add options as per message type */ -static struct net_pkt *dhcpv4_prepare_message(struct net_if *iface, u8_t type, - const struct in_addr *ciaddr, - const struct in_addr *server_addr) +/* Create DHCPv4 message and add options as per message type */ +static struct net_pkt *dhcpv4_create_message(struct net_if *iface, u8_t type, + const struct in_addr *ciaddr, + const struct in_addr *server_addr, + bool server_id, bool requested_ip) { + NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg); const struct in_addr src = INADDR_ANY_INIT; + size_t size = DHCPV4_MESSAGE_SIZE; struct net_pkt *pkt; - struct net_buf *frag; struct dhcp_msg *msg; - pkt = net_pkt_get_reserve_tx(K_FOREVER); - net_pkt_set_iface(pkt, iface); - net_pkt_set_ipv4_ttl(pkt, 0xFF); + if (server_id) { + size += DHCPV4_OLV_MSG_SERVER_ID; + } - net_ipv4_create(pkt, &src, server_addr, iface, IPPROTO_UDP); + if (requested_ip) { + size += DHCPV4_OLV_MSG_REQ_IPADDR; + } + + if (type == DHCPV4_MSG_TYPE_DISCOVER) { + size += DHCPV4_OLV_MSG_REQ_LIST; + } - frag = pkt->frags; + pkt = net_pkt_alloc_with_buffer(iface, size, AF_INET, + IPPROTO_UDP, K_FOREVER); - /* Leave room for UDP header which will be filled in later */ - net_buf_add(frag, NET_UDPH_LEN); + net_pkt_set_ipv4_ttl(pkt, 0xFF); - if (net_buf_tailroom(frag) < sizeof(struct dhcp_msg)) { + if (net_ipv4_create_new(pkt, &src, server_addr) || + net_udp_create(pkt, htons(DHCPV4_CLIENT_PORT), + htons(DHCPV4_SERVER_PORT))) { goto fail; } - msg = (struct dhcp_msg *)(frag->data + NET_IPV4UDPH_LEN); - (void)memset(msg, 0, sizeof(struct dhcp_msg)); + msg = (struct dhcp_msg *)net_pkt_get_data_new(pkt, &dhcp_access); - msg->op = DHCPV4_MSG_BOOT_REQUEST; + (void)memset(msg, 0, sizeof(struct dhcp_msg)); + msg->op = DHCPV4_MSG_BOOT_REQUEST; msg->htype = HARDWARE_ETHERNET_TYPE; - msg->hlen = HARDWARE_ETHERNET_LEN; - - msg->xid = htonl(iface->config.dhcpv4.xid); + msg->hlen = HARDWARE_ETHERNET_LEN; + msg->xid = htonl(iface->config.dhcpv4.xid); msg->flags = htons(DHCPV4_MSG_BROADCAST); if (ciaddr) { @@ -221,7 +203,9 @@ static struct net_pkt *dhcpv4_prepare_message(struct net_if *iface, u8_t type, memcpy(msg->chaddr, net_if_get_link_addr(iface)->addr, net_if_get_link_addr(iface)->len); - net_buf_add(frag, sizeof(struct dhcp_msg)); + if (net_pkt_set_data(pkt, &dhcp_access)) { + goto fail; + } if (!dhcpv4_add_sname(pkt) || !dhcpv4_add_file(pkt) || @@ -230,10 +214,31 @@ static struct net_pkt *dhcpv4_prepare_message(struct net_if *iface, u8_t type, goto fail; } + if ((server_id && + !dhcpv4_add_server_id(pkt, &iface->config.dhcpv4.server_id)) || + (requested_ip && + !dhcpv4_add_req_ipaddr(pkt, &iface->config.dhcpv4.requested_ip))) { + goto fail; + } + + if (type == DHCPV4_MSG_TYPE_DISCOVER && !dhcpv4_add_req_options(pkt)) { + goto fail; + } + + if (!dhcpv4_add_end(pkt)) { + goto fail; + } + + net_pkt_cursor_init(pkt); + + net_ipv4_finalize_new(pkt, IPPROTO_UDP); + return pkt; fail: + NET_DBG("Message creation failed"); net_pkt_unref(pkt); + return NULL; } @@ -279,36 +284,16 @@ static u32_t dhcpv4_send_request(struct net_if *iface) */ ciaddr = &iface->config.dhcpv4.requested_ip; - server_addr = net_ipv4_broadcast_address(); break; } - pkt = dhcpv4_prepare_message(iface, DHCPV4_MSG_TYPE_REQUEST, - ciaddr, server_addr); + pkt = dhcpv4_create_message(iface, DHCPV4_MSG_TYPE_REQUEST, + ciaddr, server_addr, with_server_id, + with_requested_ip); if (!pkt) { goto fail; } - if (with_server_id && - !dhcpv4_add_server_id(pkt, &iface->config.dhcpv4.server_id)) { - goto fail; - } - - if (with_requested_ip && - !dhcpv4_add_req_ipaddr(pkt, &iface->config.dhcpv4.requested_ip)) { - goto fail; - } - - if (!dhcpv4_add_end(pkt)) { - goto fail; - } - - if (!dhcpv4_setup_udp_header(pkt)) { - goto fail; - } - - net_ipv4_finalize(pkt, IPPROTO_UDP); - if (net_send_data(pkt) < 0) { goto fail; } @@ -332,8 +317,6 @@ static u32_t dhcpv4_send_request(struct net_if *iface) return timeout; fail: - NET_DBG("Message preparation failed"); - if (pkt) { net_pkt_unref(pkt); } @@ -349,22 +332,13 @@ static u32_t dhcpv4_send_discover(struct net_if *iface) iface->config.dhcpv4.xid++; - pkt = dhcpv4_prepare_message(iface, DHCPV4_MSG_TYPE_DISCOVER, - NULL, net_ipv4_broadcast_address()); + pkt = dhcpv4_create_message(iface, DHCPV4_MSG_TYPE_DISCOVER, + NULL, net_ipv4_broadcast_address(), + false, false); if (!pkt) { goto fail; } - if (!dhcpv4_add_req_options(pkt) || !dhcpv4_add_end(pkt)) { - goto fail; - } - - if (!dhcpv4_setup_udp_header(pkt)) { - goto fail; - } - - net_ipv4_finalize(pkt, IPPROTO_UDP); - if (net_send_data(pkt) < 0) { goto fail; } @@ -382,13 +356,13 @@ static u32_t dhcpv4_send_discover(struct net_if *iface) return timeout; fail: - NET_DBG("Message preparation failed"); - if (pkt) { net_pkt_unref(pkt); } - return UINT32_MAX; + return iface->config.dhcpv4.xid % + (DHCPV4_INITIAL_DELAY_MAX - DHCPV4_INITIAL_DELAY_MIN) + + DHCPV4_INITIAL_DELAY_MIN; } static void dhcpv4_update_timeout_work(u32_t timeout) @@ -600,36 +574,29 @@ static void dhcpv4_timeout(struct k_work *work) /* Parse DHCPv4 options and retrieve relavant information * as per RFC 2132. */ -static enum net_verdict dhcpv4_parse_options(struct net_if *iface, - struct net_buf *frag, - u16_t offset, - enum dhcpv4_msg_type *msg_type) +static bool dhcpv4_parse_options(struct net_pkt *pkt, + struct net_if *iface, + enum dhcpv4_msg_type *msg_type) { u8_t cookie[4]; u8_t length; u8_t type; - u16_t pos; - - frag = net_frag_read(frag, offset, &pos, sizeof(magic_cookie), - (u8_t *)cookie); - if (!frag || memcmp(magic_cookie, cookie, sizeof(magic_cookie))) { + if (net_pkt_read_new(pkt, cookie, sizeof(cookie)) || + memcmp(magic_cookie, cookie, sizeof(magic_cookie))) { NET_DBG("Incorrect magic cookie"); - return NET_DROP; + return false; } - while (frag) { - frag = net_frag_read_u8(frag, pos, &pos, &type); - + while (!net_pkt_read_u8_new(pkt, &type)) { if (type == DHCPV4_OPTIONS_END) { NET_DBG("options_end"); - return NET_OK; + return true; } - frag = net_frag_read_u8(frag, pos, &pos, &length); - if (!frag) { + if (net_pkt_read_u8_new(pkt, &length)) { NET_ERR("option parsing, bad length"); - return NET_DROP; + return false; } switch (type) { @@ -638,14 +605,12 @@ static enum net_verdict dhcpv4_parse_options(struct net_if *iface, if (length != 4) { NET_ERR("options_subnet_mask, bad length"); - return NET_DROP; + return false; } - frag = net_frag_read(frag, pos, &pos, length, - netmask.s4_addr); - if (!frag && pos) { + if (net_pkt_read_new(pkt, netmask.s4_addr, length)) { NET_ERR("options_subnet_mask, short packet"); - return NET_DROP; + return false; } net_if_ipv4_set_netmask(iface, &netmask); @@ -664,14 +629,13 @@ static enum net_verdict dhcpv4_parse_options(struct net_if *iface, */ if (length % 4 != 0 || length < 4) { NET_ERR("options_router, bad length"); - return NET_DROP; + return false; } - frag = net_frag_read(frag, pos, &pos, 4, router.s4_addr); - frag = net_frag_skip(frag, pos, &pos, length - 4); - if (!frag && pos) { + if (net_pkt_read_new(pkt, router.s4_addr, 4) || + net_pkt_skip(pkt, length - 4)) { NET_ERR("options_router, short packet"); - return NET_DROP; + return false; } NET_DBG("options_router: %s", @@ -695,16 +659,15 @@ static enum net_verdict dhcpv4_parse_options(struct net_if *iface, */ if (length % 4 != 0) { NET_ERR("options_dns, bad length"); - return NET_DROP; + return false; } (void)memset(&dns, 0, sizeof(dns)); - frag = net_frag_read(frag, pos, &pos, 4, - dns.sin_addr.s4_addr); - frag = net_frag_skip(frag, pos, &pos, length - 4); - if (!frag && pos) { + + if (net_pkt_read_new(pkt, dns.sin_addr.s4_addr, 4) || + net_pkt_skip(pkt, length - 4)) { NET_ERR("options_dns, short packet"); - return NET_DROP; + return false; } dns.sin_family = AF_INET; @@ -715,7 +678,7 @@ static enum net_verdict dhcpv4_parse_options(struct net_if *iface, if (status < 0) { NET_DBG("options_dns, failed to set " "resolve address: %d", status); - return NET_DROP; + return false; } break; @@ -724,88 +687,100 @@ static enum net_verdict dhcpv4_parse_options(struct net_if *iface, case DHCPV4_OPTIONS_LEASE_TIME: if (length != 4) { NET_ERR("options_lease_time, bad length"); - return NET_DROP; + return false; + } + + if (net_pkt_read_be32_new( + pkt, &iface->config.dhcpv4.lease_time) || + !iface->config.dhcpv4.lease_time) { + NET_ERR("options_lease_time, wrong value"); + return false; } - frag = net_frag_read_be32(frag, pos, &pos, - &iface->config.dhcpv4.lease_time); NET_DBG("options_lease_time: %u", iface->config.dhcpv4.lease_time); - if (!iface->config.dhcpv4.lease_time) { - return NET_DROP; - } - break; case DHCPV4_OPTIONS_RENEWAL: if (length != 4) { NET_DBG("options_renewal, bad length"); - return NET_DROP; + return false; + } + + if (net_pkt_read_be32_new( + pkt, &iface->config.dhcpv4.renewal_time) || + !iface->config.dhcpv4.renewal_time) { + NET_DBG("options_renewal, wrong value"); + return false; } - frag = net_frag_read_be32(frag, pos, &pos, - &iface->config.dhcpv4.renewal_time); NET_DBG("options_renewal: %u", iface->config.dhcpv4.renewal_time); - if (!iface->config.dhcpv4.renewal_time) { - return NET_DROP; - } - break; case DHCPV4_OPTIONS_REBINDING: if (length != 4) { NET_DBG("options_rebinding, bad length"); - return NET_DROP; + return false; + } + + if (net_pkt_read_be32_new( + pkt, + &iface->config.dhcpv4.rebinding_time) || + !iface->config.dhcpv4.rebinding_time) { + NET_DBG("options_rebinding, wrong value"); + return false; } - frag = net_frag_read_be32(frag, pos, &pos, - &iface->config.dhcpv4.rebinding_time); NET_DBG("options_rebinding: %u", iface->config.dhcpv4.rebinding_time); - if (!iface->config.dhcpv4.rebinding_time) { - return NET_DROP; - } - break; case DHCPV4_OPTIONS_SERVER_ID: if (length != 4) { NET_DBG("options_server_id, bad length"); - return NET_DROP; + return false; + } + + if (net_pkt_read_new( + pkt, + iface->config.dhcpv4.server_id.s4_addr, + length)) { + NET_DBG("options_server_id, read err"); + return false; } - frag = net_frag_read(frag, pos, &pos, length, - iface->config.dhcpv4.server_id.s4_addr); NET_DBG("options_server_id: %s", log_strdup(net_sprint_ipv4_addr( &iface->config.dhcpv4.server_id))); break; case DHCPV4_OPTIONS_MSG_TYPE: { - u8_t v; - if (length != 1) { NET_DBG("options_msg_type, bad length"); - return NET_DROP; + return false; + } + + if (net_pkt_read_u8_new(pkt, (u8_t *)msg_type)) { + NET_DBG("options_msg_type, read err"); + return false; } - frag = net_frag_read_u8(frag, pos, &pos, &v); - *msg_type = v; break; } default: NET_DBG("option unknown: %d", type); - frag = net_frag_skip(frag, pos, &pos, length); - break; - } - if (!frag && pos) { - return NET_DROP; + if (net_pkt_skip(pkt, length)) { + NET_DBG("option unknown, skip err"); + return false; + } + + break; } } /* Invalid case: Options without DHCPV4_OPTIONS_END. */ - return NET_DROP; + return false; } static inline void dhcpv4_handle_msg_offer(struct net_if *iface) @@ -902,20 +877,18 @@ static enum net_verdict net_dhcpv4_input(struct net_conn *conn, struct net_pkt *pkt, void *user_data) { + NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg); enum dhcpv4_msg_type msg_type = 0; struct dhcp_msg *msg; - struct net_buf *frag; struct net_if *iface; - u8_t min; - u16_t pos; if (!conn) { NET_DBG("Invalid connection"); return NET_DROP; } - if (!pkt || !pkt->frags) { - NET_DBG("Invalid packet, no fragments"); + if (!pkt) { + NET_DBG("Invalid packet"); return NET_DROP; } @@ -925,19 +898,26 @@ static enum net_verdict net_dhcpv4_input(struct net_conn *conn, return NET_DROP; } - frag = pkt->frags; - min = NET_IPV4UDPH_LEN + sizeof(struct dhcp_msg); - /* If the message is not DHCP then continue passing to * related handlers. */ - if (net_pkt_get_len(pkt) < min) { + if (net_pkt_get_len(pkt) < NET_IPV4UDPH_LEN + sizeof(struct dhcp_msg)) { NET_DBG("Input msg is not related to DHCPv4"); return NET_CONTINUE; } - msg = (struct dhcp_msg *)(frag->data + NET_IPV4UDPH_LEN); + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_init(pkt); + + if (net_pkt_skip(pkt, NET_IPV4UDPH_LEN)) { + return NET_DROP; + } + + msg = (struct dhcp_msg *)net_pkt_get_data_new(pkt, &dhcp_access); + if (!msg) { + return NET_DROP; + } NET_DBG("Received dhcp msg [op=0x%x htype=0x%x hlen=%u xid=0x%x " "secs=%u flags=0x%x chaddr=%s", @@ -960,22 +940,22 @@ static enum net_verdict net_dhcpv4_input(struct net_conn *conn, NET_DBG("Unexpected op (%d), xid (%x vs %x) or chaddr", msg->op, iface->config.dhcpv4.xid, ntohl(msg->xid)); - goto drop; + return NET_DROP; } - memcpy(iface->config.dhcpv4.requested_ip.s4_addr, msg->yiaddr, - sizeof(msg->yiaddr)); + memcpy(iface->config.dhcpv4.requested_ip.s4_addr, + msg->yiaddr, sizeof(msg->yiaddr)); + + net_pkt_acknowledge_data(pkt, &dhcp_access); /* SNAME, FILE are not used at the moment, skip it */ - frag = net_frag_skip(frag, min, &pos, SIZE_OF_SNAME + SIZE_OF_FILE); - if (!frag && pos) { + if (net_pkt_skip(pkt, SIZE_OF_SNAME + SIZE_OF_FILE)) { NET_DBG("short packet while skipping sname"); - goto drop; + return NET_DROP; } - if (dhcpv4_parse_options(iface, frag, pos, &msg_type) == NET_DROP) { - NET_DBG("Invalid Options"); - goto drop; + if (!dhcpv4_parse_options(pkt, iface, &msg_type)) { + return NET_DROP; } net_pkt_unref(pkt); @@ -983,9 +963,6 @@ static enum net_verdict net_dhcpv4_input(struct net_conn *conn, dhcpv4_handle_reply(iface, msg_type); return NET_OK; - -drop: - return NET_DROP; } static void dhcpv4_iface_event_handler(struct net_mgmt_event_callback *cb, diff --git a/subsys/net/ip/dhcpv4.h b/subsys/net/ip/dhcpv4.h index 307b4efb13faa..31404d237b4e1 100644 --- a/subsys/net/ip/dhcpv4.h +++ b/subsys/net/ip/dhcpv4.h @@ -7,6 +7,7 @@ /* * Copyright (c) 2017 ARM Ltd. + * Copyright (c) 2018 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,8 +36,9 @@ struct dhcp_msg { u8_t chaddr[16]; /* Client hardware address */ } __packed; -#define SIZE_OF_SNAME 64 -#define SIZE_OF_FILE 128 +#define SIZE_OF_SNAME 64 +#define SIZE_OF_FILE 128 +#define SIZE_OF_MAGIC_COOKIE 4 #define DHCPV4_MSG_BROADCAST 0x8000 #define DHCPV4_MSG_UNICAST 0x0000 @@ -44,11 +46,11 @@ struct dhcp_msg { #define DHCPV4_MSG_BOOT_REQUEST 1 #define DHCPV4_MSG_BOOT_REPLY 2 -#define HARDWARE_ETHERNET_TYPE 1 -#define HARDWARE_ETHERNET_LEN 6 +#define HARDWARE_ETHERNET_TYPE 1 +#define HARDWARE_ETHERNET_LEN 6 -#define DHCPV4_SERVER_PORT 67 -#define DHCPV4_CLIENT_PORT 68 +#define DHCPV4_SERVER_PORT 67 +#define DHCPV4_CLIENT_PORT 68 /* These enumerations represent RFC2131 defined msy type codes, hence * they should not be renumbered. @@ -76,6 +78,21 @@ enum dhcpv4_msg_type { #define DHCPV4_OPTIONS_REBINDING 59 #define DHCPV4_OPTIONS_END 255 +/* Useful size macros */ +#define DHCPV4_OLV_MSG_REQ_IPADDR 6 +#define DHCPV4_OLV_MSG_TYPE_SIZE 3 +#define DHCPV4_OLV_MSG_SERVER_ID 6 +#define DHCPV4_OLV_MSG_REQ_LIST 5 + +#define DHCPV4_OLV_END_SIZE 1 + +#define DHCPV4_MESSAGE_SIZE (sizeof(struct dhcp_msg) + \ + SIZE_OF_SNAME + SIZE_OF_FILE + \ + SIZE_OF_MAGIC_COOKIE + \ + DHCPV4_OLV_MSG_TYPE_SIZE + \ + DHCPV4_OLV_END_SIZE) + + /* TODO: * 1) Support for UNICAST flag (some dhcpv4 servers will not reply if * DISCOVER message contains BROADCAST FLAG). From 5bd6cf681e281696d0fbccd355ecaf269012a673 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 3 Dec 2018 20:35:16 +0100 Subject: [PATCH 10/70] net: Adapt checksum calculation to new net_pkt API Let's just use the packet cursor relevantly. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/utils.c | 118 ++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 63 deletions(-) diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c index 27e9a2073bef3..92482389ebf85 100644 --- a/subsys/net/ip/utils.c +++ b/subsys/net/ip/utils.c @@ -390,24 +390,25 @@ int net_addr_pton(sa_family_t family, const char *src, return 0; } -static u16_t calc_chksum(u16_t sum, const u8_t *ptr, u16_t len) +static u16_t calc_chksum(u16_t sum, const u8_t *data, size_t len) { - u16_t tmp; const u8_t *end; + u16_t tmp; - end = ptr + len - 1; + end = data + len - 1; - while (ptr < end) { - tmp = (ptr[0] << 8) + ptr[1]; + while (data < end) { + tmp = (data[0] << 8) + data[1]; sum += tmp; if (sum < tmp) { sum++; } - ptr += 2; + + data += 2; } - if (ptr == end) { - tmp = ptr[0] << 8; + if (data == end) { + tmp = data[0] << 8; sum += tmp; if (sum < tmp) { sum++; @@ -417,50 +418,37 @@ static u16_t calc_chksum(u16_t sum, const u8_t *ptr, u16_t len) return sum; } -static inline u16_t calc_chksum_pkt(u16_t sum, struct net_pkt *pkt, - u16_t upper_layer_len) +static inline u16_t pkt_calc_chksum(struct net_pkt *pkt, u16_t sum) { - u16_t proto_len = net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt); - struct net_buf *frag; - u16_t offset; - s16_t len; - u8_t *ptr; - - ARG_UNUSED(upper_layer_len); - - frag = net_frag_skip(pkt->frags, proto_len, &offset, 0); - if (!frag) { - NET_DBG("Trying to read past pkt len (proto len %d)", - proto_len); - return 0; + struct net_pkt_cursor *cur = &pkt->cursor; + size_t len; + + if (!cur->buf || !cur->pos) { + return sum; } - NET_ASSERT(offset <= frag->len); + len = cur->buf->len - (cur->pos - cur->buf->data); - ptr = frag->data + offset; - len = frag->len - offset; + while (cur->buf) { + sum = calc_chksum(sum, cur->pos, len); - while (frag) { - sum = calc_chksum(sum, ptr, len); - frag = frag->frags; - if (!frag) { + cur->buf = cur->buf->frags; + if (!cur->buf || !cur->buf->len) { break; } - ptr = frag->data; + cur->pos = cur->buf->data; - /* Do we need to take first byte from next fragment */ if (len % 2) { - u16_t tmp = *ptr; - sum += tmp; - if (sum < tmp) { + sum += *cur->pos; + if (sum < *cur->pos) { sum++; } - len = frag->len - 1; - ptr++; + + cur->pos++; + len = cur->buf->len - 1; } else { - len = frag->len; + len = cur->buf->len; } } @@ -469,41 +457,45 @@ static inline u16_t calc_chksum_pkt(u16_t sum, struct net_pkt *pkt, u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto) { - u16_t upper_layer_len; + size_t len = 0U; u16_t sum = 0U; + struct net_pkt_cursor backup; - switch (net_pkt_family(pkt)) { -#if defined(CONFIG_NET_IPV4) - case AF_INET: - upper_layer_len = ntohs(NET_IPV4_HDR(pkt)->len) - - net_pkt_ipv6_ext_len(pkt) - - net_pkt_ip_hdr_len(pkt); + net_pkt_cursor_backup(pkt, &backup); + net_pkt_cursor_init(pkt); + + net_pkt_set_overwrite(pkt, true); + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_pkt_family(pkt) == AF_INET) { if (proto != IPPROTO_ICMP) { - sum = calc_chksum(upper_layer_len + proto, - (u8_t *)&NET_IPV4_HDR(pkt)->src, - 2 * sizeof(struct in_addr)); + len = 2 * sizeof(struct in_addr); + sum = net_pkt_get_len(pkt) - + net_pkt_ip_hdr_len(pkt) + proto; } - break; -#endif -#if defined(CONFIG_NET_IPV6) - case AF_INET6: - upper_layer_len = ntohs(NET_IPV6_HDR(pkt)->len) - - net_pkt_ipv6_ext_len(pkt); - sum = calc_chksum(upper_layer_len + proto, - (u8_t *)&NET_IPV6_HDR(pkt)->src, - 2 * sizeof(struct in6_addr)); - break; -#endif - default: + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6) { + len = 2 * sizeof(struct in6_addr); + sum = net_pkt_get_len(pkt) - + net_pkt_ip_hdr_len(pkt) - + net_pkt_ipv6_ext_len(pkt) + proto; + } else { NET_DBG("Unknown protocol family %d", net_pkt_family(pkt)); return 0; } - sum = calc_chksum_pkt(sum, pkt, upper_layer_len); + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) - len); + + sum = calc_chksum(sum, pkt->cursor.pos, len); + + net_pkt_skip(pkt, len + net_pkt_ipv6_ext_len(pkt)); + + sum = pkt_calc_chksum(pkt, sum); sum = (sum == 0) ? 0xffff : htons(sum); + net_pkt_cursor_restore(pkt, &backup); + return ~sum; } @@ -512,7 +504,7 @@ u16_t net_calc_chksum_ipv4(struct net_pkt *pkt) { u16_t sum; - sum = calc_chksum(0, (u8_t *)NET_IPV4_HDR(pkt), NET_IPV4H_LEN); + sum = calc_chksum(0, pkt->buffer->data, NET_IPV4H_LEN); sum = (sum == 0) ? 0xffff : htons(sum); From 04c3eb672e5ce718cc8c7e2d6afed43f9e004ff9 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 5 Dec 2018 13:58:58 +0100 Subject: [PATCH 11/70] net/core: Each and every received packet are being set to overwrite This will avoid new API's writing functions to modify the packet's content. For instance while checking its checksum etc... Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/dhcpv4.c | 1 - subsys/net/ip/net_core.c | 2 ++ subsys/net/ip/utils.c | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index 417c347639fe7..cb1eb76be0869 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -907,7 +907,6 @@ static enum net_verdict net_dhcpv4_input(struct net_conn *conn, } - net_pkt_set_overwrite(pkt, true); net_pkt_cursor_init(pkt); if (net_pkt_skip(pkt, NET_IPV4UDPH_LEN)) { diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index ee3b1af653dcd..97f218f52f99b 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -381,6 +381,8 @@ int net_recv_data(struct net_if *iface, struct net_pkt *pkt) return -ENETDOWN; } + net_pkt_set_overwrite(pkt, true); + NET_DBG("prio %d iface %p pkt %p len %zu", net_pkt_priority(pkt), iface, pkt, net_pkt_get_len(pkt)); diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c index 92482389ebf85..ff8ac6d509c82 100644 --- a/subsys/net/ip/utils.c +++ b/subsys/net/ip/utils.c @@ -460,12 +460,11 @@ u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto) size_t len = 0U; u16_t sum = 0U; struct net_pkt_cursor backup; + bool ow; net_pkt_cursor_backup(pkt, &backup); net_pkt_cursor_init(pkt); - net_pkt_set_overwrite(pkt, true); - if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { if (proto != IPPROTO_ICMP) { @@ -484,6 +483,9 @@ u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto) return 0; } + ow = net_pkt_is_being_overwritten(pkt); + net_pkt_set_overwrite(pkt, true); + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) - len); sum = calc_chksum(sum, pkt->cursor.pos, len); @@ -496,6 +498,8 @@ u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto) net_pkt_cursor_restore(pkt, &backup); + net_pkt_set_overwrite(pkt, ow); + return ~sum; } From b086db87f6df8336c48bf989e6ef5b9f52d12871 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 12 Dec 2018 09:49:06 +0100 Subject: [PATCH 12/70] net/core: Set cursor relevantly Newly received pkt can get their cursor intialized at net_recv_data() (most of the time, drivers won't mangle with the content before calling that function). Right after l2 (net_if_recv_data()) parsing as well. L2s pull the starting buffer after ll header. Instead of letting L2s updating the cursor, it's simpler to reinitialize it directly after such parsing. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/net_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 97f218f52f99b..0ccc718c4eb2d 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -102,6 +102,11 @@ static inline enum net_verdict process_data(struct net_pkt *pkt, } } + /* L2 has modified the buffer starting point, it is easier + * to re-initialize the cursor rather than updating it. + */ + net_pkt_cursor_init(pkt); + /* IP version and header length. */ switch (NET_IPV6_HDR(pkt)->vtc & 0xf0) { #if defined(CONFIG_NET_IPV6) @@ -296,6 +301,8 @@ int net_send_data(struct net_pkt *pkt) } #endif + net_pkt_cursor_init(pkt); + status = check_ip_addr(pkt); if (status < 0) { return status; @@ -382,6 +389,7 @@ int net_recv_data(struct net_if *iface, struct net_pkt *pkt) } net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_init(pkt); NET_DBG("prio %d iface %p pkt %p len %zu", net_pkt_priority(pkt), iface, pkt, net_pkt_get_len(pkt)); From b88b5fdea3d01e8c65c7193de38a3c6c7af1cbf0 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 11 Dec 2018 11:19:58 +0100 Subject: [PATCH 13/70] net/ipv4: Input headers are gathered through new API As before, such header is meant to be in a contiguous area (beginning of the buffer, only 20 bytes) Opportunistically chaning the function name to net_ipv4_input() (all will be create/finalize/input). Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv4.c | 22 ++++++++++++++++++---- subsys/net/ip/net_core.c | 4 +--- subsys/net/ip/net_private.h | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index 90458121ec2e3..a71c103908779 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -185,19 +185,29 @@ const struct in_addr *net_ipv4_broadcast_address(void) return &addr; } -enum net_verdict net_ipv4_process_pkt(struct net_pkt *pkt) +enum net_verdict net_ipv4_input(struct net_pkt *pkt) { - struct net_ipv4_hdr *hdr = NET_IPV4_HDR(pkt); + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr); int real_len = net_pkt_get_len(pkt); - int pkt_len = ntohs(hdr->len); enum net_verdict verdict = NET_DROP; + struct net_ipv4_hdr *hdr; + int pkt_len; + + net_stats_update_ipv4_recv(net_pkt_iface(pkt)); + hdr = (struct net_ipv4_hdr *)net_pkt_get_data_new(pkt, &ipv4_access); + if (!hdr) { + NET_DBG("DROP: no buffer"); + goto drop; + } + + pkt_len = ntohs(hdr->len); if (real_len < pkt_len) { NET_DBG("DROP: pkt len per hdr %d != pkt real len %d", pkt_len, real_len); goto drop; } else if (real_len > pkt_len) { - net_pkt_pull(pkt, pkt_len, real_len - pkt_len); + net_pkt_update_length(pkt, pkt_len); } if (net_ipv4_is_addr_mcast(&hdr->src)) { @@ -236,6 +246,10 @@ enum net_verdict net_ipv4_process_pkt(struct net_pkt *pkt) net_pkt_set_transport_proto(pkt, hdr->proto); + net_pkt_set_family(pkt, PF_INET); + + net_pkt_acknowledge_data(pkt, &ipv4_access); + switch (hdr->proto) { case IPPROTO_ICMP: verdict = net_icmpv4_input( diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 0ccc718c4eb2d..094e072b6b4f2 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -117,9 +117,7 @@ static inline enum net_verdict process_data(struct net_pkt *pkt, #endif #if defined(CONFIG_NET_IPV4) case 0x40: - net_stats_update_ipv4_recv(net_pkt_iface(pkt)); - net_pkt_set_family(pkt, PF_INET); - return net_ipv4_process_pkt(pkt); + return net_ipv4_input(pkt); #endif } diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 95bfbde54b148..a9cf41e70c780 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -43,7 +43,7 @@ extern void net_if_init(void); extern void net_if_post_init(void); extern void net_if_carrier_down(struct net_if *iface); extern void net_context_init(void); -enum net_verdict net_ipv4_process_pkt(struct net_pkt *pkt); +enum net_verdict net_ipv4_input(struct net_pkt *pkt); enum net_verdict net_ipv6_process_pkt(struct net_pkt *pkt, bool is_loopback); extern void net_tc_tx_init(void); extern void net_tc_rx_init(void); From 5e8133420dcaa95a36ee3c69028920156d93ba18 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 11 Dec 2018 11:51:50 +0100 Subject: [PATCH 14/70] net/icmpv4: Input headers are gathered through new API As before, such header is meant to be in a contiguous area. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv4.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 9f58a8020c8a7..0328f2e049ee3 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -356,10 +356,14 @@ void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler) enum net_verdict net_icmpv4_input(struct net_pkt *pkt, bool bcast) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; struct net_icmpv4_handler *cb; - struct net_icmp_hdr icmp_hdr; - if (net_icmpv4_get_hdr(pkt, &icmp_hdr) < 0) { + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, + &icmp_access); + if (!icmp_hdr) { NET_DBG("DROP: NULL ICMPv4 header"); return NET_DROP; } @@ -370,19 +374,21 @@ enum net_verdict net_icmpv4_input(struct net_pkt *pkt, bool bcast) } if (bcast && (!IS_ENABLED(CONFIG_NET_ICMPV4_ACCEPT_BROADCAST) || - icmp_hdr.type != NET_ICMPV4_ECHO_REQUEST)) { + icmp_hdr->type != NET_ICMPV4_ECHO_REQUEST)) { NET_DBG("DROP: broadcast pkt"); goto drop; } + net_pkt_acknowledge_data(pkt, &icmp_access); + NET_DBG("ICMPv4 packet received type %d code %d", - icmp_hdr.type, icmp_hdr.code); + icmp_hdr->type, icmp_hdr->code); net_stats_update_icmp_recv(net_pkt_iface(pkt)); SYS_SLIST_FOR_EACH_CONTAINER(&handlers, cb, node) { - if (cb->type == icmp_hdr.type && - (cb->code == icmp_hdr.code || cb->code == 0)) { + if (cb->type == icmp_hdr->type && + (cb->code == icmp_hdr->code || cb->code == 0)) { return cb->handler(pkt); } } From dca2c197d5959085d3b9c0d89492beb3b2654a97 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 11 Dec 2018 14:54:07 +0100 Subject: [PATCH 15/70] net/icmpv4: Add a new function to finalize the ICMPv4 packet Function names will be normalized then by the couple create/finalize. This one only sets the checksum. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv4.c | 17 +++++++++++++++++ subsys/net/ip/icmpv4.h | 1 + subsys/net/ip/ipv4.c | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 0328f2e049ee3..778daee50527a 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -95,6 +95,23 @@ int net_icmpv4_set_chksum(struct net_pkt *pkt) return 0; } +int net_icmpv4_finalize(struct net_pkt *pkt) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, + &icmpv4_access); + if (!icmp_hdr) { + return -ENOBUFS; + } + + icmp_hdr->chksum = net_calc_chksum_icmpv4(pkt); + + return net_pkt_set_data(pkt, &icmpv4_access); +} + static inline enum net_verdict icmpv4_handle_echo_request(struct net_pkt *pkt) { /* Note that we send the same data packets back and just swap diff --git a/subsys/net/ip/icmpv4.h b/subsys/net/ip/icmpv4.h index 63f2c75c10bdf..97f008e9bb4c8 100644 --- a/subsys/net/ip/icmpv4.h +++ b/subsys/net/ip/icmpv4.h @@ -75,6 +75,7 @@ int net_icmpv4_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); int net_icmpv4_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); int net_icmpv4_set_chksum(struct net_pkt *pkt); +int net_icmpv4_finalize(struct net_pkt *pkt); #if defined(CONFIG_NET_IPV4) void net_icmpv4_init(void); diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index a71c103908779..fbb88aefd2337 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -162,7 +162,7 @@ int net_ipv4_finalize_new(struct net_pkt *pkt, u8_t next_header_proto) next_header_proto == IPPROTO_TCP) { net_tcp_set_chksum(pkt, pkt->buffer); } else if (next_header_proto == IPPROTO_ICMP) { - net_icmpv4_set_chksum(pkt); + net_icmpv4_finalize(pkt); } } else { net_pkt_set_data(pkt, &ipv4_access); From 50e20592ba90bb7f7b554e589640b7eaa268f6a6 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 11 Dec 2018 15:23:57 +0100 Subject: [PATCH 16/70] net/icmpv4: Rework relevant signatures to pass ipv4 header pointer This is meant to remove the need for macro NET_IPV4_HDR(), since we don't know in future if accessing the header that way will be valid. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv4.c | 15 ++++++++++----- subsys/net/ip/icmpv4.h | 7 +++++-- subsys/net/ip/ipv4.c | 4 +--- subsys/net/ip/net_shell.c | 10 ++++++---- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 778daee50527a..c02bbf11a6b7d 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -112,7 +112,8 @@ int net_icmpv4_finalize(struct net_pkt *pkt) return net_pkt_set_data(pkt, &icmpv4_access); } -static inline enum net_verdict icmpv4_handle_echo_request(struct net_pkt *pkt) +static enum net_verdict icmpv4_handle_echo_request(struct net_pkt *pkt, + struct net_ipv4_hdr *ip_hdr) { /* Note that we send the same data packets back and just swap * the addresses etc. @@ -121,6 +122,8 @@ static inline enum net_verdict icmpv4_handle_echo_request(struct net_pkt *pkt) struct in_addr addr; int ret; + ARG_UNUSED(ip_hdr); + NET_DBG("Received Echo Request from %s to %s", log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->src)), log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst))); @@ -371,7 +374,8 @@ void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler) sys_slist_find_and_remove(&handlers, &handler->node); } -enum net_verdict net_icmpv4_input(struct net_pkt *pkt, bool bcast) +enum net_verdict net_icmpv4_input(struct net_pkt *pkt, + struct net_ipv4_hdr *ip_hdr) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, struct net_icmp_hdr); @@ -390,8 +394,9 @@ enum net_verdict net_icmpv4_input(struct net_pkt *pkt, bool bcast) goto drop; } - if (bcast && (!IS_ENABLED(CONFIG_NET_ICMPV4_ACCEPT_BROADCAST) || - icmp_hdr->type != NET_ICMPV4_ECHO_REQUEST)) { + if (net_ipv4_is_addr_bcast(net_pkt_iface(pkt), &ip_hdr->dst) && + (!IS_ENABLED(CONFIG_NET_ICMPV4_ACCEPT_BROADCAST) || + icmp_hdr->type != NET_ICMPV4_ECHO_REQUEST)) { NET_DBG("DROP: broadcast pkt"); goto drop; } @@ -406,7 +411,7 @@ enum net_verdict net_icmpv4_input(struct net_pkt *pkt, bool bcast) SYS_SLIST_FOR_EACH_CONTAINER(&handlers, cb, node) { if (cb->type == icmp_hdr->type && (cb->code == icmp_hdr->code || cb->code == 0)) { - return cb->handler(pkt); + return cb->handler(pkt, ip_hdr); } } diff --git a/subsys/net/ip/icmpv4.h b/subsys/net/ip/icmpv4.h index 97f008e9bb4c8..ac69c6b3a885e 100644 --- a/subsys/net/ip/icmpv4.h +++ b/subsys/net/ip/icmpv4.h @@ -30,7 +30,9 @@ struct net_icmpv4_echo_req { u16_t sequence; } __packed; -typedef enum net_verdict (*icmpv4_callback_handler_t)(struct net_pkt *pkt); +typedef enum net_verdict (*icmpv4_callback_handler_t)( + struct net_pkt *pkt, + struct net_ipv4_hdr *ip_hdr); struct net_icmpv4_handler { sys_snode_t node; @@ -69,7 +71,8 @@ void net_icmpv4_register_handler(struct net_icmpv4_handler *handler); void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler); -enum net_verdict net_icmpv4_input(struct net_pkt *pkt, bool bcast); +enum net_verdict net_icmpv4_input(struct net_pkt *pkt, + struct net_ipv4_hdr *ip_hdr); int net_icmpv4_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); int net_icmpv4_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index fbb88aefd2337..b10d9ff827bce 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -252,9 +252,7 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) switch (hdr->proto) { case IPPROTO_ICMP: - verdict = net_icmpv4_input( - pkt, net_ipv4_is_addr_bcast(net_pkt_iface(pkt), - &hdr->dst)); + verdict = net_icmpv4_input(pkt, hdr); break; case IPPROTO_TCP: /* Fall through */ diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index 8d17f1ac02f50..dacd97d309987 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -2814,7 +2814,8 @@ static int _ping_ipv6(const struct shell *shell, char *host) #if defined(CONFIG_NET_IPV4) -static enum net_verdict _handle_ipv4_echo_reply(struct net_pkt *pkt); +static enum net_verdict _handle_ipv4_echo_reply(struct net_pkt *pkt, + struct net_ipv4_hdr *ip_hdr); static struct net_icmpv4_handler ping4_handler = { .type = NET_ICMPV4_ECHO_REPLY, @@ -2827,11 +2828,12 @@ static inline void _remove_ipv4_ping_handler(void) net_icmpv4_unregister_handler(&ping4_handler); } -static enum net_verdict _handle_ipv4_echo_reply(struct net_pkt *pkt) +static enum net_verdict _handle_ipv4_echo_reply(struct net_pkt *pkt, + struct net_ipv4_hdr *ip_hdr) { PR_SHELL(shell_for_ping, "Received echo reply from %s to %s\n", - net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->src), - net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst)); + net_sprint_ipv4_addr(&ip_hdr->src), + net_sprint_ipv4_addr(&ip_hdr->dst)); k_sem_give(&ping_timeout); _remove_ipv4_ping_handler(); From fb4917e2f0c6ce4cb194d36790829ed0d51924e6 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 11 Dec 2018 15:46:01 +0100 Subject: [PATCH 17/70] net/icmpv4: Switch echo request handler to new API Unlike before, we allocate a new packet for the reply which is a modified clone of the request. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv4.c | 111 ++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 51 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index c02bbf11a6b7d..d5a7e4d655603 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -95,6 +95,26 @@ int net_icmpv4_set_chksum(struct net_pkt *pkt) return 0; } +static int icmpv4_create_new(struct net_pkt *pkt, u8_t icmp_type, + u8_t icmp_code) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, + &icmpv4_access); + if (!icmp_hdr) { + return -ENOBUFS; + } + + icmp_hdr->type = icmp_type; + icmp_hdr->code = icmp_code; + icmp_hdr->chksum = 0; + + return net_pkt_set_data(pkt, &icmpv4_access); +} + int net_icmpv4_finalize(struct net_pkt *pkt) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, @@ -115,55 +135,64 @@ int net_icmpv4_finalize(struct net_pkt *pkt) static enum net_verdict icmpv4_handle_echo_request(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr) { - /* Note that we send the same data packets back and just swap - * the addresses etc. - */ - struct net_icmp_hdr icmp_hdr; - struct in_addr addr; - int ret; + struct net_pkt *reply = NULL; - ARG_UNUSED(ip_hdr); - - NET_DBG("Received Echo Request from %s to %s", - log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->src)), - log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst))); - - net_ipaddr_copy(&addr, &NET_IPV4_HDR(pkt)->src); - net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src, - net_if_ipv4_select_src_addr(net_pkt_iface(pkt), - &addr)); /* If interface can not select src address based on dst addr * and src address is unspecified, drop the echo request. */ - if (net_ipv4_is_addr_unspecified(&NET_IPV4_HDR(pkt)->src)) { + if (net_ipv4_is_addr_unspecified(&ip_hdr->src)) { NET_DBG("DROP: src addr is unspecified"); - return NET_DROP; + goto drop; } - net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr); + NET_DBG("Received Echo Request from %s to %s", + log_strdup(net_sprint_ipv4_addr(&ip_hdr->src)), + log_strdup(net_sprint_ipv4_addr(&ip_hdr->dst))); - icmp_hdr.type = NET_ICMPV4_ECHO_REPLY; - icmp_hdr.code = 0; + net_pkt_cursor_init(pkt); - ret = net_icmpv4_set_hdr(pkt, &icmp_hdr); - if (ret < 0) { - return NET_DROP; + /* Cloning is faster here as echo request might come with data behind */ + reply = net_pkt_clone_new(pkt, PKT_WAIT_TIME); + if (!reply) { + NET_DBG("DROP: No buffer"); + goto drop; } - net_ipv4_finalize(pkt, IPPROTO_ICMP); + /* Let's keep the original data, + * we will only overwrite what is relevant + */ + net_pkt_set_overwrite(reply, true); + + if (net_ipv4_create_new(reply, &ip_hdr->dst, &ip_hdr->src) || + icmpv4_create_new(reply, NET_ICMPV4_ECHO_REPLY, 0)) { + NET_DBG("DROP: wrong buffer"); + goto drop; + } + + net_pkt_cursor_init(reply); + net_ipv4_finalize_new(reply, IPPROTO_ICMP); NET_DBG("Sending Echo Reply from %s to %s", - log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->src)), - log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst))); + log_strdup(net_sprint_ipv4_addr(&ip_hdr->dst)), + log_strdup(net_sprint_ipv4_addr(&ip_hdr->src))); - if (net_send_data(pkt) < 0) { - net_stats_update_icmp_drop(net_pkt_iface(pkt)); - return NET_DROP; + if (net_send_data(reply) < 0) { + goto drop; } - net_stats_update_icmp_sent(net_pkt_iface(pkt)); + net_stats_update_icmp_sent(net_pkt_iface(reply)); + + net_pkt_unref(pkt); return NET_OK; +drop: + if (reply) { + net_pkt_unref(reply); + } + + net_stats_update_icmp_drop(net_pkt_iface(pkt)); + + return NET_DROP; } static struct net_buf *icmpv4_create(struct net_pkt *pkt, u8_t icmp_type, @@ -181,26 +210,6 @@ static struct net_buf *icmpv4_create(struct net_pkt *pkt, u8_t icmp_type, return frag; } -static int icmpv4_create_new(struct net_pkt *pkt, u8_t icmp_type, - u8_t icmp_code) -{ - NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, - struct net_icmp_hdr); - struct net_icmp_hdr *icmp_hdr; - - icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, - &icmpv4_access); - if (!icmp_hdr) { - return -ENOBUFS; - } - - icmp_hdr->type = icmp_type; - icmp_hdr->code = icmp_code; - icmp_hdr->chksum = 0; - - return net_pkt_set_data(pkt, &icmpv4_access); -} - int net_icmpv4_send_echo_request(struct net_if *iface, struct in_addr *dst, u16_t identifier, From 33f82b0197b8f6edd39f7fccb512107558da7d7b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 11 Dec 2018 17:18:54 +0100 Subject: [PATCH 18/70] net/icmpv4: Switch error message to new API Logic does not change much, besides using new create/finalize functions etc... Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv4.c | 96 ++++++++++++++++++------------------------ subsys/net/ip/icmpv4.h | 2 + 2 files changed, 43 insertions(+), 55 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index d5a7e4d655603..52a26d1a00359 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -277,90 +277,75 @@ int net_icmpv4_send_echo_request(struct net_if *iface, return ret; } -#define append(pkt, type, value) \ - do { \ - if (!net_pkt_append_##type##_timeout(pkt, value, \ - PKT_WAIT_TIME)) { \ - err = -ENOMEM; \ - goto drop; \ - } \ - } while (0) - int net_icmpv4_send_error(struct net_pkt *orig, u8_t type, u8_t code) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr); int err = -EIO; + struct net_ipv4_hdr *ip_hdr; struct net_pkt *pkt; - struct net_buf *frag; - struct net_if *iface; size_t copy_len; - const struct in_addr *src, *dst; - - iface = net_pkt_iface(orig); - - if (NET_IPV4_HDR(orig)->proto == IPPROTO_ICMP) { - struct net_icmp_hdr icmp_hdr; - - err = net_icmpv4_get_hdr(orig, &icmp_hdr); - if (err < 0 || icmp_hdr.code < 8) { - /* We must not send ICMP errors back */ - goto drop_no_pkt; - } - } - dst = &NET_IPV4_HDR(orig)->src; - src = &NET_IPV4_HDR(orig)->dst; + net_pkt_cursor_init(orig); - pkt = net_pkt_get_reserve_tx(PKT_WAIT_TIME); - if (!pkt) { - err = -ENOMEM; + ip_hdr = (struct net_ipv4_hdr *)net_pkt_get_data_new(orig, + &ipv4_access); + if (!ip_hdr) { goto drop_no_pkt; } - net_pkt_set_iface(pkt, iface); - - if (!net_ipv4_create(pkt, src, dst, iface, IPPROTO_ICMP)) { - err = -ENOMEM; - goto drop; - } + if (ip_hdr->proto == IPPROTO_ICMP) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; - if (!icmpv4_create(pkt, type, code)) { - err = -ENOMEM; - goto drop; + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new( + orig, &icmpv4_access); + if (!icmp_hdr || icmp_hdr->code < 8) { + /* We must not send ICMP errors back */ + err = -EINVAL; + goto drop_no_pkt; + } } - /* Appending unused part, filled with 0s */ - append(pkt, be32, 0); - - if (NET_IPV4_HDR(orig)->proto == IPPROTO_UDP) { + if (ip_hdr->proto == IPPROTO_UDP) { copy_len = sizeof(struct net_ipv4_hdr) + sizeof(struct net_udp_hdr); - } else if (NET_IPV4_HDR(orig)->proto == IPPROTO_TCP) { - copy_len = sizeof(struct net_ipv4_hdr); - /* FIXME, add TCP header length too */ + } else if (ip_hdr->proto == IPPROTO_TCP) { + copy_len = sizeof(struct net_ipv4_hdr) + + sizeof(struct net_tcp_hdr); } else { copy_len = 0; } - frag = net_pkt_copy(orig, copy_len, 0, PKT_WAIT_TIME); - if (!frag) { - err = -ENOMEM; - goto drop; + pkt = net_pkt_alloc_with_buffer(net_pkt_iface(orig), + copy_len + NET_ICMPV4_UNUSED_LEN, + AF_INET, IPPROTO_ICMP, + PKT_WAIT_TIME); + if (!pkt) { + err = -ENOMEM; + goto drop_no_pkt; } - net_pkt_frag_add(pkt, frag); + if (net_ipv4_create_new(pkt, &ip_hdr->dst, &ip_hdr->src) || + icmpv4_create_new(pkt, type, code) || + net_pkt_memset(pkt, 0, NET_ICMPV4_UNUSED_LEN) || + net_pkt_copy_new(pkt, orig, copy_len)) { + goto drop; + } - net_ipv4_finalize(pkt, IPPROTO_ICMP); + net_pkt_cursor_init(pkt); + net_ipv4_finalize_new(pkt, IPPROTO_ICMP); net_pkt_lladdr_dst(pkt)->addr = net_pkt_lladdr_src(orig)->addr; net_pkt_lladdr_dst(pkt)->len = net_pkt_lladdr_src(orig)->len; NET_DBG("Sending ICMPv4 Error Message type %d code %d from %s to %s", type, code, - log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->src)), - log_strdup(net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst))); + log_strdup(net_sprint_ipv4_addr(&ip_hdr->src)), + log_strdup(net_sprint_ipv4_addr(&ip_hdr->dst))); if (net_send_data(pkt) >= 0) { - net_stats_update_icmp_sent(iface); + net_stats_update_icmp_sent(net_pkt_iface(orig)); return 0; } @@ -368,9 +353,10 @@ int net_icmpv4_send_error(struct net_pkt *orig, u8_t type, u8_t code) net_pkt_unref(pkt); drop_no_pkt: - net_stats_update_icmp_drop(iface); + net_stats_update_icmp_drop(net_pkt_iface(orig)); return err; + } void net_icmpv4_register_handler(struct net_icmpv4_handler *handler) diff --git a/subsys/net/ip/icmpv4.h b/subsys/net/ip/icmpv4.h index ac69c6b3a885e..58447d8567126 100644 --- a/subsys/net/ip/icmpv4.h +++ b/subsys/net/ip/icmpv4.h @@ -25,6 +25,8 @@ #define NET_ICMPV4_DST_UNREACH_NO_PROTO 2 /* Protocol not supported */ #define NET_ICMPV4_DST_UNREACH_NO_PORT 3 /* Port unreachable */ +#define NET_ICMPV4_UNUSED_LEN 4 + struct net_icmpv4_echo_req { u16_t identifier; u16_t sequence; From 574d58e9f0e2a1cd779194db3121510121ba1f09 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 11 Dec 2018 15:48:48 +0100 Subject: [PATCH 19/70] net/icmpv4: Remove useless create, get and set header functions These are not needed anymore. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv4.c | 54 ++++-------------------------------------- subsys/net/ip/icmpv4.h | 3 --- 2 files changed, 4 insertions(+), 53 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 52a26d1a00359..cf90da9775d10 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -25,36 +25,6 @@ LOG_MODULE_REGISTER(net_icmpv4, CONFIG_NET_ICMPV4_LOG_LEVEL); static sys_slist_t handlers; -int net_icmpv4_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - frag = net_pkt_write(pkt, pkt->frags, - net_pkt_ip_hdr_len(pkt), - &pos, sizeof(*hdr), (u8_t *)hdr, - PKT_WAIT_TIME); - if (pos > 0 && !frag) { - return -EINVAL; - } - - return 0; -} - -int net_icmpv4_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - frag = net_frag_read(pkt->frags, net_pkt_ip_hdr_len(pkt), &pos, - sizeof(*hdr), (u8_t *)hdr); - if (pos > 0 && !frag) { - return -EINVAL; - } - - return 0; -} - int net_icmpv4_set_chksum(struct net_pkt *pkt) { u16_t chksum = 0U; @@ -95,8 +65,7 @@ int net_icmpv4_set_chksum(struct net_pkt *pkt) return 0; } -static int icmpv4_create_new(struct net_pkt *pkt, u8_t icmp_type, - u8_t icmp_code) +static int icmpv4_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, struct net_icmp_hdr); @@ -164,7 +133,7 @@ static enum net_verdict icmpv4_handle_echo_request(struct net_pkt *pkt, net_pkt_set_overwrite(reply, true); if (net_ipv4_create_new(reply, &ip_hdr->dst, &ip_hdr->src) || - icmpv4_create_new(reply, NET_ICMPV4_ECHO_REPLY, 0)) { + icmpv4_create(reply, NET_ICMPV4_ECHO_REPLY, 0)) { NET_DBG("DROP: wrong buffer"); goto drop; } @@ -195,21 +164,6 @@ static enum net_verdict icmpv4_handle_echo_request(struct net_pkt *pkt, return NET_DROP; } -static struct net_buf *icmpv4_create(struct net_pkt *pkt, u8_t icmp_type, - u8_t icmp_code) -{ - struct net_buf *frag = pkt->frags; - u16_t pos; - - net_buf_add(frag, sizeof(struct net_icmp_hdr)); - - frag = net_pkt_write_u8_timeout(pkt, frag, net_pkt_ip_hdr_len(pkt), - &pos, icmp_type, PKT_WAIT_TIME); - frag = net_pkt_write_u8_timeout(pkt, frag, pos, &pos, icmp_code, - PKT_WAIT_TIME); - return frag; -} - int net_icmpv4_send_echo_request(struct net_if *iface, struct in_addr *dst, u16_t identifier, @@ -238,7 +192,7 @@ int net_icmpv4_send_echo_request(struct net_if *iface, } if (net_ipv4_create_new(pkt, src, dst) || - icmpv4_create_new(pkt, NET_ICMPV4_ECHO_REQUEST, 0)) { + icmpv4_create(pkt, NET_ICMPV4_ECHO_REQUEST, 0)) { goto drop; } @@ -327,7 +281,7 @@ int net_icmpv4_send_error(struct net_pkt *orig, u8_t type, u8_t code) } if (net_ipv4_create_new(pkt, &ip_hdr->dst, &ip_hdr->src) || - icmpv4_create_new(pkt, type, code) || + icmpv4_create(pkt, type, code) || net_pkt_memset(pkt, 0, NET_ICMPV4_UNUSED_LEN) || net_pkt_copy_new(pkt, orig, copy_len)) { goto drop; diff --git a/subsys/net/ip/icmpv4.h b/subsys/net/ip/icmpv4.h index 58447d8567126..71049f3e601d7 100644 --- a/subsys/net/ip/icmpv4.h +++ b/subsys/net/ip/icmpv4.h @@ -76,9 +76,6 @@ void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler); enum net_verdict net_icmpv4_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr); -int net_icmpv4_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); -int net_icmpv4_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); - int net_icmpv4_set_chksum(struct net_pkt *pkt); int net_icmpv4_finalize(struct net_pkt *pkt); From f63df4ed6a81bf1935b283ad9004d78b5de7e2f4 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 13 Dec 2018 14:05:21 +0100 Subject: [PATCH 20/70] net/context: Create new send sendto functions using new net_pkt API It's not anymore up to user to provide the pkt. Context will build the packet according to its metadata and provided buffer and length. It currently supports only IPv4 and UDP. Signed-off-by: Tomasz Bursztyka --- include/net/net_context.h | 75 ++++++++++++ subsys/net/ip/net_context.c | 234 ++++++++++++++++++++++++++++++++++++ 2 files changed, 309 insertions(+) diff --git a/include/net/net_context.h b/include/net/net_context.h index 6c809ee7df508..70a931289a7c9 100644 --- a/include/net/net_context.h +++ b/include/net/net_context.h @@ -747,6 +747,41 @@ int net_context_send(struct net_pkt *pkt, void *token, void *user_data); +/** + * @brief Send a network buffer to a peer. + * + * @details This function can be used to send network data to a peer + * connection. This function will return immediately if the timeout + * is set to K_NO_WAIT. If the timeout is set to K_FOREVER, the function + * will wait until the network buffer is sent. Timeout value > 0 will + * wait as many ms. After the network buffer is sent, + * a caller-supplied callback is called. The callback is called even + * if timeout was set to K_FOREVER, the callback is called + * before this function will return in this case. The callback is not + * called if the timeout expires. For context of type SOCK_DGRAM, + * the destination address must have been set by the call to + * net_context_connect(). + * This is similar as BSD send() function. + * + * @param context The network context to use. + * @param buf The data buffer to send + * @param len Length of the buffer + * @param cb Caller-supplied callback function. + * @param timeout Timeout for the connection. Possible values + * are K_FOREVER, K_NO_WAIT, >0. + * @param token Caller specified value that is passed as is to callback. + * @param user_data Caller-supplied user data. + * + * @return 0 if ok, < 0 if error + */ +int net_context_send_new(struct net_context *context, + const void *buf, + size_t len, + net_context_send_cb_t cb, + s32_t timeout, + void *token, + void *user_data); + /** * @brief Send a network buffer to a peer specified by address. * @@ -782,6 +817,46 @@ int net_context_sendto(struct net_pkt *pkt, void *token, void *user_data); + +/** + * @brief Send a network buffer to a peer specified by address. + * + * @details This function can be used to send network data to a peer + * specified by address. This variant can only be used for datagram + * connections of type SOCK_DGRAM. This function will return immediately + * if the timeout is set to K_NO_WAIT. If the timeout is set to K_FOREVER, + * the function will wait until the network buffer is sent. Timeout + * value > 0 will wait as many ms. After the network buffer + * is sent, a caller-supplied callback is called. The callback is called + * even if timeout was set to K_FOREVER, the callback is called + * before this function will return. The callback is not called if the + * timeout expires. + * This is similar as BSD sendto() function. + * + * @param context The network context to use. + * @param buf The data buffer to send + * @param len Length of the buffer + * @param dst_addr Destination address. This will override the address + * already set in network buffer. + * @param addrlen Length of the address. + * @param cb Caller-supplied callback function. + * @param timeout Timeout for the connection. Possible values + * are K_FOREVER, K_NO_WAIT, >0. + * @param token Caller specified value that is passed as is to callback. + * @param user_data Caller-supplied user data. + * + * @return numbers of bytes sent on success, a negative errno otherwise + */ +int net_context_sendto_new(struct net_context *context, + const void *buf, + size_t len, + const struct sockaddr *dst_addr, + socklen_t addrlen, + net_context_send_cb_t cb, + s32_t timeout, + void *token, + void *user_data); + /** * @brief Receive network data from a peer specified by context. * diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 353f9425238bb..c15263dd327de 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -40,6 +40,8 @@ LOG_MODULE_REGISTER(net_ctx, CONFIG_NET_CONTEXT_LOG_LEVEL); #define EPFNOSUPPORT EPROTONOSUPPORT #endif +#define PKT_WAIT_TIME K_SECONDS(1) + #define NET_MAX_CONTEXT CONFIG_NET_MAX_CONTEXTS static struct net_context contexts[NET_MAX_CONTEXT]; @@ -676,6 +678,33 @@ struct net_pkt *net_context_create_ipv4(struct net_context *context, net_context_get_iface(context), net_context_get_ip_proto(context)); } + +static int context_create_ipv4_new(struct net_context *context, + struct net_pkt *pkt, + const struct in_addr *src, + const struct in_addr *dst) +{ + NET_ASSERT(((struct sockaddr_in_ptr *)&context->local)->sin_addr); + + if (!src) { + src = ((struct sockaddr_in_ptr *)&context->local)->sin_addr; + } + + if (net_ipv4_is_addr_unspecified(src) + || net_ipv4_is_addr_mcast(src)) { + src = net_if_ipv4_select_src_addr(net_pkt_iface(pkt), + (struct in_addr *)dst); + /* If src address is still unspecified, do not create pkt */ + if (net_ipv4_is_addr_unspecified(src)) { + NET_DBG("DROP: src addr is unspecified"); + return -EINVAL; + } + } + + return net_ipv4_create_new(pkt, src, dst); +} +#else +#define context_create_ipv4_new(...) -1 #endif /* CONFIG_NET_IPV4 */ #if defined(CONFIG_NET_IPV6) @@ -1196,6 +1225,211 @@ int net_context_sendto(struct net_pkt *pkt, return ret; } +static int context_setup_udp_packet(struct net_context *context, + struct net_pkt *pkt, + const void *buf, + size_t len, + const struct sockaddr *dst_addr, + socklen_t addrlen) +{ + int ret = -EINVAL; + size_t written; + u16_t dst_port; + + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_context_get_family(context) == AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *)dst_addr; + + dst_port = addr4->sin_port; + + ret = context_create_ipv4_new(context, pkt, + NULL, &addr4->sin_addr); + } + + if (ret < 0) { + return ret; + } + + ret = bind_default(context); + if (ret) { + return ret; + } + + ret = net_udp_create(pkt, + net_sin((struct sockaddr *) + &context->local)->sin_port, + dst_port); + if (ret) { + return ret; + } + + written = net_pkt_available_buffer(pkt); + if (written > len) { + written = len; + } + + ret = net_pkt_write_new(pkt, buf, written); + if (ret) { + return ret; + } + + return written; +} + +static void context_finalize_packet(struct net_context *context, + struct net_pkt *pkt) +{ + /* This function is meant to be temporary: once all moved to new + * API, it will be up to net_send_data() to finalize the packet. + */ + + net_pkt_cursor_init(pkt); + + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_context_get_family(context) == AF_INET) { + net_ipv4_finalize_new(pkt, + net_context_get_ip_proto(context)); + } +} + +static int context_sendto_new(struct net_context *context, + const void *buf, + size_t len, + const struct sockaddr *dst_addr, + socklen_t addrlen, + net_context_send_cb_t cb, + s32_t timeout, + void *token, + void *user_data) +{ + int sent = 0; + struct net_pkt *pkt; + int ret; + + NET_ASSERT(PART_OF_ARRAY(contexts, context)); + + if (!net_context_is_used(context)) { + return -EBADF; + } + + if (net_context_get_ip_proto(context) == IPPROTO_TCP) { + return -ENOTSUP; + } + + if (!dst_addr) { + return -EDESTADDRREQ; + } + + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_context_get_family(context) == AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *)dst_addr; + + if (addrlen < sizeof(struct sockaddr_in)) { + return -EINVAL; + } + + if (!addr4->sin_addr.s_addr) { + return -EDESTADDRREQ; + } + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_context_get_family(context) == AF_INET6) { + return -ENOTSUP; + } else { + NET_DBG("Invalid protocol family %d", + net_context_get_family(context)); + return -EINVAL; + } + + pkt = net_pkt_alloc_with_buffer(net_context_get_iface(context), len, + net_context_get_family(context), + net_context_get_ip_proto(context), + PKT_WAIT_TIME); + if (!pkt) { + return -ENOMEM; + } + + net_pkt_set_context(pkt, context); + context->send_cb = cb; + context->user_data = user_data; + net_pkt_set_token(pkt, token); + + if (IS_ENABLED(CONFIG_NET_UDP) && + net_context_get_ip_proto(context) == IPPROTO_UDP) { + ret = context_setup_udp_packet(context, pkt, buf, len, + dst_addr, addrlen); + if (ret < 0) { + goto fail; + } + + context_finalize_packet(context, pkt); + + sent = ret; + ret = net_send_data(pkt); + } else if (IS_ENABLED(CONFIG_NET_TCP) && + net_context_get_ip_proto(context) == IPPROTO_TCP) { + /* TCP is not supported yet to work on new net_pkt API */ + ret = -ENOTSUP; + } else { + NET_DBG("Unknown protocol while sending packet: %d", + net_context_get_ip_proto(context)); + ret = -EPROTONOSUPPORT; + } + + if (ret < 0) { + goto fail; + } + + return sent; +fail: + net_pkt_unref(pkt); + + return ret; +} + +int net_context_send_new(struct net_context *context, + const void *buf, + size_t len, + net_context_send_cb_t cb, + s32_t timeout, + void *token, + void *user_data) +{ + socklen_t addrlen; + + if (!(context->flags & NET_CONTEXT_REMOTE_ADDR_SET) || + !net_sin(&context->remote)->sin_port) { + return -EDESTADDRREQ; + } + + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_context_get_family(context) == AF_INET) { + addrlen = sizeof(struct sockaddr_in); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_context_get_family(context) == AF_INET6) { + addrlen = sizeof(struct sockaddr_in6); + } else { + addrlen = 0; + } + + return context_sendto_new(context, buf, len, &context->remote, + addrlen, cb, timeout, token, user_data); +} + + +int net_context_sendto_new(struct net_context *context, + const void *buf, + size_t len, + const struct sockaddr *dst_addr, + socklen_t addrlen, + net_context_send_cb_t cb, + s32_t timeout, + void *token, + void *user_data) +{ + return context_sendto_new(context, buf, len, dst_addr, addrlen, + cb, timeout, token, user_data); +} + enum net_verdict net_context_packet_received(struct net_conn *conn, struct net_pkt *pkt, void *user_data) From cef38c41ef14660241ac1e8cb264f8d1daed5334 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 14 Dec 2018 13:50:08 +0100 Subject: [PATCH 21/70] net/sockets: Use the new send/sendto from net_context It's now up to net_context to build the net_pkt and send it. This will become the default. Signed-off-by: Tomasz Bursztyka --- subsys/net/lib/sockets/sockets.c | 39 +++++++++++--------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index d57ac07fb49eb..7fa07dc09b68b 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -392,51 +392,38 @@ ssize_t zsock_sendto_ctx(struct net_context *ctx, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { - int err; - struct net_pkt *send_pkt; s32_t timeout = K_FOREVER; + int status; if ((flags & ZSOCK_MSG_DONTWAIT) || sock_is_nonblock(ctx)) { timeout = K_NO_WAIT; } - send_pkt = net_pkt_get_tx(ctx, timeout); - if (!send_pkt) { - errno = EAGAIN; - return -1; - } - - len = net_pkt_append(send_pkt, len, buf, timeout); - if (!len) { - net_pkt_unref(send_pkt); - errno = EAGAIN; - return -1; - } - /* Register the callback before sending in order to receive the response * from the peer. */ - err = net_context_recv(ctx, zsock_received_cb, K_NO_WAIT, ctx->user_data); - if (err < 0) { - net_pkt_unref(send_pkt); - errno = -err; + status = net_context_recv(ctx, zsock_received_cb, + K_NO_WAIT, ctx->user_data); + if (status < 0) { + errno = -status; return -1; } if (dest_addr) { - err = net_context_sendto(send_pkt, dest_addr, addrlen, NULL, - timeout, NULL, ctx->user_data); + status = net_context_sendto_new(ctx, buf, len, dest_addr, + addrlen, NULL, timeout, + NULL, ctx->user_data); } else { - err = net_context_send(send_pkt, NULL, timeout, NULL, ctx->user_data); + status = net_context_send_new(ctx, buf, len, NULL, timeout, + NULL, ctx->user_data); } - if (err < 0) { - net_pkt_unref(send_pkt); - errno = -err; + if (status < 0) { + errno = -status; return -1; } - return len; + return status; } ssize_t _impl_zsock_sendto(int sock, const void *buf, size_t len, int flags, From 6d40a8d140dd8fd6b397e8e4ff887e4c76a553fc Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 13 Dec 2018 21:36:57 +0100 Subject: [PATCH 22/70] net/udp: Add an input function This will be the place where UDP header is parsed: its checksum verified and src/dst ports grabbed. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/udp.c | 23 +++++++++++++++++++++++ subsys/net/ip/udp_internal.h | 13 +++++++++++++ 2 files changed, 36 insertions(+) diff --git a/subsys/net/ip/udp.c b/subsys/net/ip/udp.c index 2d3a1408b1bd8..66f2db2fdd4fd 100644 --- a/subsys/net/ip/udp.c +++ b/subsys/net/ip/udp.c @@ -13,6 +13,7 @@ LOG_MODULE_REGISTER(net_udp, CONFIG_NET_UDP_LOG_LEVEL); #include "net_private.h" #include "udp_internal.h" +#include "net_stats.h" #define PKT_WAIT_TIME K_SECONDS(1) @@ -261,3 +262,25 @@ int net_udp_unregister(struct net_conn_handle *handle) { return net_conn_unregister(handle); } + +struct net_udp_hdr *net_udp_input(struct net_pkt *pkt, + struct net_pkt_data_access *udp_access) +{ + struct net_udp_hdr *udp_hdr; + + if (IS_ENABLED(CONFIG_NET_UDP_CHECKSUM) && + net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) && + net_calc_chksum_udp(pkt) != 0) { + NET_DBG("DROP: checksum mismatch"); + goto drop; + } + + udp_hdr = (struct net_udp_hdr *)net_pkt_get_data_new(pkt, udp_access); + if (udp_hdr && !net_pkt_set_data(pkt, udp_access)) { + return udp_hdr; + } + +drop: + net_stats_update_udp_chkerr(net_pkt_iface(pkt)); + return NULL; +} diff --git a/subsys/net/ip/udp_internal.h b/subsys/net/ip/udp_internal.h index 29ac4ec21b979..4a4873ec4ad65 100644 --- a/subsys/net/ip/udp_internal.h +++ b/subsys/net/ip/udp_internal.h @@ -92,6 +92,9 @@ int net_udp_create(struct net_pkt *pkt, u16_t src_port, u16_t dst_port); */ int net_udp_finalize(struct net_pkt *pkt); +struct net_udp_hdr *net_udp_input(struct net_pkt *pkt, + struct net_pkt_data_access *udp_access); + #else #define net_udp_insert(pkt, offset, src_port, dst_port) (pkt) #define net_udp_get_chksum(pkt, frag) (0) @@ -114,6 +117,16 @@ static inline int net_udp_finalize(struct net_pkt *pkt) return 0; } +static inline +struct net_udp_hdr *net_udp_input(struct net_pkt *pkt, + struct net_pkt_data_access *udp_access) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(udp_access); + + return NULL; +} + #endif /* CONFIG_NET_UDP */ /** From f37507588426a592e25973e757907fcd37c80fd6 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 13 Dec 2018 21:38:07 +0100 Subject: [PATCH 23/70] net/tcp: Add an input function for pre-validation This will quickly verify the header, its checksum and grab src/dst ports. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/tcp.c | 22 ++++++++++++++++++++++ subsys/net/ip/tcp_internal.h | 13 +++++++++++++ 2 files changed, 35 insertions(+) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 62ce461d574e5..497283f17d38d 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -2670,3 +2670,25 @@ int net_tcp_connect(struct net_context *context, return 0; } + +struct net_tcp_hdr *net_tcp_input(struct net_pkt *pkt, + struct net_pkt_data_access *tcp_access) +{ + struct net_tcp_hdr *tcp_hdr; + + if (IS_ENABLED(CONFIG_NET_TCP_CHECKSUM) && + net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) && + net_calc_chksum_tcp(pkt) != 0) { + NET_DBG("DROP: checksum mismatch"); + goto drop; + } + + tcp_hdr = (struct net_tcp_hdr *)net_pkt_get_data_new(pkt, tcp_access); + if (tcp_hdr && !net_pkt_set_data(pkt, tcp_access)) { + return tcp_hdr; + } + +drop: + net_stats_update_tcp_seg_chkerr(net_pkt_iface(pkt)); + return NULL; +} diff --git a/subsys/net/ip/tcp_internal.h b/subsys/net/ip/tcp_internal.h index 48e61ba554b6a..1afaf4e5abf3a 100644 --- a/subsys/net/ip/tcp_internal.h +++ b/subsys/net/ip/tcp_internal.h @@ -547,6 +547,9 @@ int net_tcp_connect(struct net_context *context, net_context_connect_cb_t cb, void *user_data); +struct net_tcp_hdr *net_tcp_input(struct net_pkt *pkt, + struct net_pkt_data_access *tcp_access); + #else static inline struct net_tcp *net_tcp_alloc(struct net_context *context) { @@ -774,6 +777,16 @@ static inline int net_tcp_connect(struct net_context *context, return -EPROTONOSUPPORT; } +static inline +struct net_tcp_hdr *net_tcp_input(struct net_pkt *pkt, + struct net_pkt_data_access *tcp_access) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(tcp_access); + + return NULL; +} + #endif #if defined(CONFIG_NET_TCP) From 8b3ca29320295e01b7839c3056200cfffcf1e5aa Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 13 Dec 2018 21:39:06 +0100 Subject: [PATCH 24/70] net/connection: Modify input function Verifying udp/tcp checksum should be done before calling this function. Also, up to ipv4 and ipv6 to provide a pointer to their respective header. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/connection.c | 227 ++++++++++++------------------------- subsys/net/ip/connection.h | 19 +++- 2 files changed, 90 insertions(+), 156 deletions(-) diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index 11b63bee830c4..b81c1e352f1dc 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -204,39 +204,24 @@ static s32_t check_hash(enum net_ip_protocol proto, return -ENOENT; } -static inline s32_t get_conn(enum net_ip_protocol proto, - sa_family_t family, - struct net_pkt *pkt, +static inline s32_t get_conn(struct net_pkt *pkt, + union ip_header *hdr, + enum net_ip_protocol proto, + u16_t src_port, + u16_t dst_port, 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, - udp_hdr->src_port, - udp_hdr->dst_port, - cache_value); + if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { + return check_hash(proto, net_pkt_family(pkt), + &hdr->ipv4->src, &hdr->ipv4->dst, + src_port, dst_port, cache_value); } -#endif -#if defined(CONFIG_NET_IPV6) - if (family == AF_INET6) { - return check_hash(proto, family, - &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst, - udp_hdr->src_port, - udp_hdr->dst_port, - cache_value); + if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) { + return check_hash(proto, net_pkt_family(pkt), + &hdr->ipv6->src, &hdr->ipv6->dst, + src_port, dst_port, cache_value); } -#endif return -1; } @@ -282,30 +267,24 @@ static void cache_clear(void) } } -static inline enum net_verdict cache_check(enum net_ip_protocol proto, - struct net_pkt *pkt, +static inline enum net_verdict cache_check(struct net_pkt *pkt, + union ip_header *hdr, + enum net_ip_protocol proto, + u16_t src_port, + u16_t dst_port, u32_t *cache_value, s32_t *pos) { - *pos = get_conn(proto, net_pkt_family(pkt), pkt, cache_value); + *pos = get_conn(pkt, hdr, proto, src_port, dst_port, cache_value); if (*pos >= 0) { 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]; + struct net_conn *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(udp_hdr->src_port), - ntohs(udp_hdr->dst_port), + src_port, dst_port, net_pkt_family(pkt), *pos, conn_cache[*pos].value); @@ -704,6 +683,7 @@ int net_conn_register(enum net_ip_protocol proto, } static bool check_addr(struct net_pkt *pkt, + union ip_header *hdr, struct sockaddr *addr, bool is_remote) { @@ -716,9 +696,9 @@ static bool check_addr(struct net_pkt *pkt, struct in6_addr *addr6; if (is_remote) { - addr6 = &NET_IPV6_HDR(pkt)->src; + addr6 = &hdr->ipv6->src; } else { - addr6 = &NET_IPV6_HDR(pkt)->dst; + addr6 = &hdr->ipv6->dst; } if (!net_ipv6_is_addr_unspecified( @@ -738,9 +718,9 @@ static bool check_addr(struct net_pkt *pkt, struct in_addr *addr4; if (is_remote) { - addr4 = &NET_IPV4_HDR(pkt)->src; + addr4 = &hdr->ipv4->src; } else { - addr4 = &NET_IPV4_HDR(pkt)->dst; + addr4 = &hdr->ipv4->dst; } if (net_sin(addr)->sin_addr.s_addr) { @@ -773,105 +753,71 @@ static inline void send_icmp_error(struct net_pkt *pkt) } static bool is_invalid_packet(struct net_pkt *pkt, - u16_t src_port, - u16_t dst_port) + union ip_header *hdr, + u16_t src_port, + u16_t dst_port) { - bool my_src_addr = false; + if (src_port != dst_port) { + return false; + } - switch (NET_IPV6_HDR(pkt)->vtc & 0xf0) { -#if defined(CONFIG_NET_IPV6) - case 0x60: - if (net_ipv6_is_my_addr(&NET_IPV6_HDR(pkt)->src)) { - my_src_addr = true; + if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { + if (net_ipv4_addr_cmp(&hdr->ipv4->src, &hdr->ipv4->dst) || + net_ipv4_is_my_addr(&hdr->ipv4->src)) { + return true; } - break; -#endif -#if defined(CONFIG_NET_IPV4) - case 0x40: - if (net_ipv4_is_my_addr(&NET_IPV4_HDR(pkt)->src)) { - my_src_addr = true; + } + + if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) { + if (net_ipv6_addr_cmp(&hdr->ipv6->src, &hdr->ipv6->dst) || + net_ipv6_is_my_addr(&hdr->ipv6->src)) { + return true; } - break; -#endif } - return my_src_addr && (src_port == dst_port); + return true; } -enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) +enum net_verdict net_conn_input(struct net_pkt *pkt, union ip_header *ip_hdr, + u8_t proto, union proto_header *proto_hdr) { + struct net_if *pkt_iface = net_pkt_iface(pkt); int i, best_match = -1; s16_t best_rank = -1; - u16_t src_port, dst_port; - struct net_if *pkt_iface = net_pkt_iface(pkt); - + u16_t src_port; + u16_t dst_port; #if defined(CONFIG_NET_CONN_CACHE) enum net_verdict verdict; u32_t cache_value = 0U; s32_t pos; - - verdict = cache_check(proto, pkt, &cache_value, &pos); - if (verdict != NET_CONTINUE) { - return verdict; - } #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. - */ if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) { - struct net_udp_hdr hdr, *udp_hdr; - - ARG_UNUSED(hdr); - - udp_hdr = net_udp_get_hdr(pkt, &hdr); - if (!udp_hdr) { - return NET_DROP; - } - - src_port = udp_hdr->src_port; - dst_port = udp_hdr->dst_port; + src_port = proto_hdr->udp->src_port; + dst_port = proto_hdr->udp->dst_port; } else if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) { - struct net_tcp_hdr hdr, *tcp_hdr; - - ARG_UNUSED(hdr); - - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return NET_DROP; - } - - src_port = tcp_hdr->src_port; - dst_port = tcp_hdr->dst_port; + src_port = proto_hdr->tcp->src_port; + dst_port = proto_hdr->tcp->dst_port; } else { - NET_DBG("No UDP or TCP configured, dropping packet."); return NET_DROP; } - if (is_invalid_packet(pkt, src_port, dst_port)) { + if (is_invalid_packet(pkt, ip_hdr, src_port, dst_port)) { NET_DBG("Dropping invalid packet"); return NET_DROP; } - if (CONFIG_NET_CONN_LOG_LEVEL >= LOG_LEVEL_DBG) { - int data_len = -1; - - if (IS_ENABLED(CONFIG_NET_IPV4) && - net_pkt_family(pkt) == AF_INET) { - data_len = ntohs(NET_IPV4_HDR(pkt)->len); - } else if (IS_ENABLED(CONFIG_NET_IPV6) && - net_pkt_family(pkt) == AF_INET6) { - data_len = ntohs(NET_IPV6_HDR(pkt)->len); - } - - NET_DBG("Check %s listener for pkt %p src port %u dst port %u " - "family %d len %d", net_proto2str(proto), - pkt, - ntohs(src_port), - ntohs(dst_port), - net_pkt_family(pkt), data_len); +#if defined(CONFIG_NET_CONN_CACHE) + verdict = cache_check(pkt, ip_hdr, proto, src_port, dst_port, + &cache_value, &pos); + if (verdict != NET_CONTINUE) { + return verdict; } +#endif + + NET_DBG("Check %s listener for pkt %p src port %u dst port %u" + " family %d", net_proto2str(proto), pkt, + ntohs(src_port), ntohs(dst_port), net_pkt_family(pkt)); for (i = 0; i < CONFIG_NET_MAX_CONN; i++) { if (!(conns[i].flags & NET_CONN_IN_USE)) { @@ -897,13 +843,15 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) } if (conns[i].flags & NET_CONN_REMOTE_ADDR_SET) { - if (!check_addr(pkt, &conns[i].remote_addr, true)) { + if (!check_addr(pkt, ip_hdr, + &conns[i].remote_addr, true)) { continue; } } if (conns[i].flags & NET_CONN_LOCAL_ADDR_SET) { - if (!check_addr(pkt, &conns[i].local_addr, false)) { + if (!check_addr(pkt, ip_hdr, + &conns[i].local_addr, false)) { continue; } } @@ -924,27 +872,6 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) } if (best_match >= 0) { - - /* If packet has a listener configured, then check also the - * protocol checksum if that checking is enabled. - * If the checksum calculation fails, then discard the message. - */ - if (IS_ENABLED(CONFIG_NET_UDP_CHECKSUM) && - proto == IPPROTO_UDP && - net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) && - net_calc_chksum_udp(pkt) != 0) { - net_stats_update_udp_chkerr(net_pkt_iface(pkt)); - NET_DBG("DROP: UDP checksum mismatch"); - goto drop; - } else if (IS_ENABLED(CONFIG_NET_TCP_CHECKSUM) && - proto == IPPROTO_TCP && - net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) && - net_calc_chksum_tcp(pkt) != 0) { - net_stats_update_tcp_seg_chkerr(net_pkt_iface(pkt)); - NET_DBG("DROP: TCP checksum mismatch"); - goto drop; - } - #if defined(CONFIG_NET_CONN_CACHE) NET_DBG("[%d] match found cb %p ud %p rank 0x%02x cache 0x%x", best_match, @@ -978,22 +905,18 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt) cache_add_neg(cache_value); -#if defined(CONFIG_NET_IPV6) /* If the destination address is multicast address, - * we do not send ICMP error as that makes no sense. + * we will not send an ICMP error as that makes no sense. */ - if (net_pkt_family(pkt) == AF_INET6 && - net_ipv6_is_addr_mcast(&NET_IPV6_HDR(pkt)->dst)) { + if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6 && + net_ipv6_is_addr_mcast(&ip_hdr->ipv6->dst)) { ; - } else -#endif -#if defined(CONFIG_NET_IPV4) - if (net_pkt_family(pkt) == AF_INET && - net_ipv4_is_addr_mcast(&NET_IPV4_HDR(pkt)->dst)) { + } else if (IS_ENABLED(CONFIG_NET_IPV4) && + net_pkt_family(pkt) == AF_INET && + net_ipv4_is_addr_mcast(&ip_hdr->ipv4->dst)) { ; - } else -#endif - { + } else { send_icmp_error(pkt); if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) { diff --git a/subsys/net/ip/connection.h b/subsys/net/ip/connection.h index 266b1dc5d6fc1..aa3cf721939fa 100644 --- a/subsys/net/ip/connection.h +++ b/subsys/net/ip/connection.h @@ -29,6 +29,16 @@ struct net_conn; struct net_conn_handle; +union ip_header { + struct net_ipv4_hdr *ipv4; + struct net_ipv6_hdr *ipv6; +}; + +union proto_header { + struct net_udp_hdr *udp; + struct net_tcp_hdr *tcp; +}; + /** * @brief Function that is called by connection subsystem when UDP/TCP * packet is received and which matches local and remote IP address @@ -133,11 +143,12 @@ int net_conn_change_callback(struct net_conn_handle *handle, * disabled, the function will always return NET_DROP. */ #if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) -enum net_verdict net_conn_input(enum net_ip_protocol proto, - struct net_pkt *pkt); +enum net_verdict net_conn_input(struct net_pkt *pkt, union ip_header *ip_hdr, + u8_t proto, union proto_header *proto_hdr); #else -static inline enum net_verdict net_conn_input(enum net_ip_protocol proto, - struct net_pkt *pkt) +static inline enum net_verdict net_conn_input(struct net_pkt *pkt, + union ip_header *hdr, u8_t proto, + union proto_header *proto_hdr) { return NET_DROP; } From 8a75403a3f4643a93db196ca7170036f2b57898b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 13 Dec 2018 21:41:23 +0100 Subject: [PATCH 25/70] net/ipv4: Rework input function Use udp/tcp input functions relevantly, and call net_conn_input afterwards. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv4.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index b10d9ff827bce..a2fa4f77b77ae 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -188,9 +188,13 @@ const struct in_addr *net_ipv4_broadcast_address(void) enum net_verdict net_ipv4_input(struct net_pkt *pkt) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr); + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); int real_len = net_pkt_get_len(pkt); enum net_verdict verdict = NET_DROP; + union proto_header proto_hdr; struct net_ipv4_hdr *hdr; + union ip_header ip; int pkt_len; net_stats_update_ipv4_recv(net_pkt_iface(pkt)); @@ -255,16 +259,31 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) verdict = net_icmpv4_input(pkt, hdr); break; case IPPROTO_TCP: - /* Fall through */ + proto_hdr.tcp = net_tcp_input(pkt, &tcp_access); + if (proto_hdr.tcp) { + verdict = NET_OK; + } + break; case IPPROTO_UDP: - verdict = net_conn_input(hdr->proto, pkt); + proto_hdr.udp = net_udp_input(pkt, &udp_access); + if (proto_hdr.udp) { + verdict = NET_OK; + } break; } - if (verdict != NET_DROP) { + if (verdict == NET_DROP) { + goto drop; + } else if (hdr->proto == IPPROTO_ICMP) { return verdict; } + ip.ipv4 = hdr; + + verdict = net_conn_input(pkt, &ip, hdr->proto, &proto_hdr); + if (verdict != NET_DROP) { + return verdict; + } drop: net_stats_update_ipv4_drop(net_pkt_iface(pkt)); return NET_DROP; From c5601df5ec204f2f2f98e0a948a4393848164ac8 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 17 Dec 2018 13:12:39 +0100 Subject: [PATCH 26/70] tests/net: Avoid using net_udp_get_chksum() checksum_offload is now the only one using that function, let's get rid of such usage. Signed-off-by: Tomasz Bursztyka --- tests/net/checksum_offload/src/main.c | 33 +++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/net/checksum_offload/src/main.c b/tests/net/checksum_offload/src/main.c index a348a644f48f3..da6a0e7a77573 100644 --- a/tests/net/checksum_offload/src/main.c +++ b/tests/net/checksum_offload/src/main.c @@ -108,6 +108,33 @@ static void eth_iface_init(struct net_if *iface) ethernet_init(iface); } +static u16_t get_udp_chksum(struct net_pkt *pkt) +{ + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + struct net_udp_hdr *udp_hdr; + struct net_pkt_cursor backup; + + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_backup(pkt, &backup); + net_pkt_cursor_init(pkt); + + /* Let's move the cursor to UDP header */ + if (net_pkt_skip(pkt, sizeof(struct net_eth_hdr) + + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt))) { + return 0; + } + + udp_hdr = (struct net_udp_hdr *)net_pkt_get_data_new(pkt, &udp_access); + if (!udp_hdr) { + return 0; + } + + net_pkt_cursor_restore(pkt, &backup); + + return udp_hdr->chksum; +} + static int eth_tx_offloading_disabled(struct device *dev, struct net_pkt *pkt) { struct eth_context *context = dev->driver_data; @@ -177,8 +204,7 @@ static int eth_tx_offloading_disabled(struct device *dev, struct net_pkt *pkt) if (test_started) { u16_t chksum; - /* First frag is always ethernet header, let's skip it */ - chksum = net_udp_get_chksum(pkt, pkt->frags->frags); + chksum = get_udp_chksum(pkt); DBG("Chksum 0x%x offloading disabled\n", chksum); @@ -206,8 +232,7 @@ static int eth_tx_offloading_enabled(struct device *dev, struct net_pkt *pkt) if (test_started) { u16_t chksum; - /* First frag is always ethernet header, let's skip it */ - chksum = net_udp_get_chksum(pkt, pkt->frags->frags); + chksum = get_udp_chksum(pkt); DBG("Chksum 0x%x offloading enabled\n", chksum); From 5069768cdfdef928863b7eec9a429573d10fa484 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 17 Dec 2018 13:15:19 +0100 Subject: [PATCH 27/70] net/udp: Remove now useless net_udp_get_chksum function It's not used anywhere. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/udp.c | 21 --------------------- subsys/net/ip/udp_internal.h | 12 ------------ 2 files changed, 33 deletions(-) diff --git a/subsys/net/ip/udp.c b/subsys/net/ip/udp.c index 66f2db2fdd4fd..5f7b9bc552c80 100644 --- a/subsys/net/ip/udp.c +++ b/subsys/net/ip/udp.c @@ -165,27 +165,6 @@ struct net_buf *net_udp_set_chksum(struct net_pkt *pkt, struct net_buf *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) { diff --git a/subsys/net/ip/udp_internal.h b/subsys/net/ip/udp_internal.h index 4a4873ec4ad65..10a471f079c44 100644 --- a/subsys/net/ip/udp_internal.h +++ b/subsys/net/ip/udp_internal.h @@ -40,17 +40,6 @@ extern "C" { */ 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 Insert UDP packet into net_pkt after specific offset. * @@ -97,7 +86,6 @@ struct net_udp_hdr *net_udp_input(struct net_pkt *pkt, #else #define net_udp_insert(pkt, offset, src_port, dst_port) (pkt) -#define net_udp_get_chksum(pkt, frag) (0) #define net_udp_set_chksum(pkt, frag) NULL static inline int net_udp_create(struct net_pkt *pkt, From 48d6cb5b97bb341eb3d6074742f82c9c95d71407 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 17 Dec 2018 15:34:00 +0100 Subject: [PATCH 28/70] net/icmpv6: Add a new function to finalize the ICMPv6 packet Function names will be normalized then by the couple create/finalize. This one only sets the checksum. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.c | 17 +++++++++++++++++ subsys/net/ip/icmpv6.h | 1 + 2 files changed, 18 insertions(+) diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index c6fbac16a6f78..5b5fee67fe5a0 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -140,6 +140,23 @@ int net_icmpv6_set_chksum(struct net_pkt *pkt) return 0; } +int net_icmpv6_finalize(struct net_pkt *pkt) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, + &icmp_access); + if (!icmp_hdr) { + return -ENOBUFS; + } + + icmp_hdr->chksum = net_calc_chksum_icmpv6(pkt); + + return net_pkt_set_data(pkt, &icmp_access); +} + int net_icmpv6_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr) { struct net_buf *frag; diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index 155e3a92700f7..a0d82a86d2a8a 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -176,6 +176,7 @@ int net_icmpv6_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); int net_icmpv6_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); int net_icmpv6_set_chksum(struct net_pkt *pkt); +int net_icmpv6_finalize(struct net_pkt *pkt); int net_icmpv6_get_ns_hdr(struct net_pkt *pkt, struct net_icmpv6_ns_hdr *hdr); int net_icmpv6_set_ns_hdr(struct net_pkt *pkt, struct net_icmpv6_ns_hdr *hdr); From f5bfaffc98b03f56732795a1ed47e6d4f429ab7d Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 17 Dec 2018 15:10:13 +0100 Subject: [PATCH 29/70] net/ipv6: Add new API to create/finalize IPv6 headers. This API is meant to work with pre-allocated net_pkt. It assumes net_pkt's buffer cursor is at the right position where to create the IPv6 header. Once done, the cursor will be placed right after the newly created IPv6 header. Finalizing assumes the same. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ subsys/net/ip/ipv6.h | 28 ++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 20998b419ac5a..c80a589e92447 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -135,6 +135,76 @@ int net_ipv6_finalize(struct net_pkt *pkt, u8_t next_header_proto) return 0; } +int net_ipv6_create_new(struct net_pkt *pkt, + const struct in6_addr *src, + const struct in6_addr *dst) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr); + struct net_ipv6_hdr *ipv6_hdr; + + ipv6_hdr = (struct net_ipv6_hdr *)net_pkt_get_data_new(pkt, + &ipv6_access); + if (!ipv6_hdr) { + return -ENOBUFS; + } + + ipv6_hdr->vtc = 0x60; + ipv6_hdr->tcflow = 0; + ipv6_hdr->flow = 0; + ipv6_hdr->len = 0; + ipv6_hdr->nexthdr = 0; + + /* User can tweak the default hop limit if needed */ + ipv6_hdr->hop_limit = net_pkt_ipv6_hop_limit(pkt); + if (ipv6_hdr->hop_limit == 0) { + ipv6_hdr->hop_limit = + net_if_ipv6_get_hop_limit(net_pkt_iface(pkt)); + } + + net_ipaddr_copy(&ipv6_hdr->dst, dst); + net_ipaddr_copy(&ipv6_hdr->src, src); + + net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); + net_pkt_set_ipv6_ext_len(pkt, 0); + + return net_pkt_set_data(pkt, &ipv6_access); +} + +int net_ipv6_finalize_new(struct net_pkt *pkt, u8_t next_header_proto) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr); + struct net_ipv6_hdr *ipv6_hdr; + + net_pkt_set_overwrite(pkt, true); + + ipv6_hdr = (struct net_ipv6_hdr *)net_pkt_get_data_new(pkt, + &ipv6_access); + if (!ipv6_hdr) { + return -ENOBUFS; + } + + ipv6_hdr->len = htons(net_pkt_get_len(pkt) - + sizeof(struct net_ipv6_hdr)); + ipv6_hdr->nexthdr = next_header_proto; + + net_pkt_set_data(pkt, &ipv6_access); + + if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt)) || + next_header_proto == IPPROTO_ICMPV6) { + if (IS_ENABLED(CONFIG_NET_UDP) && + next_header_proto == IPPROTO_UDP) { + net_udp_finalize(pkt); + } else if (IS_ENABLED(CONFIG_NET_TCP) && + next_header_proto == IPPROTO_TCP) { + net_tcp_set_chksum(pkt, pkt->buffer); + } else if (next_header_proto == IPPROTO_ICMPV6) { + return net_icmpv6_finalize(pkt); + } + } + + return 0; +} + static inline struct net_pkt *check_unknown_option(struct net_pkt *pkt, u8_t opt_type, u16_t length) diff --git a/subsys/net/ip/ipv6.h b/subsys/net/ip/ipv6.h index 7ae6901ab5be0..9e8d4855b282e 100644 --- a/subsys/net/ip/ipv6.h +++ b/subsys/net/ip/ipv6.h @@ -159,6 +159,34 @@ struct net_pkt *net_ipv6_create(struct net_pkt *pkt, */ int net_ipv6_finalize(struct net_pkt *pkt, u8_t next_header_proto); + +/** + * @brief Create IPv6 packet in provided net_pkt. + * + * @param pkt Network packet + * @param src Source IPv6 address + * @param dst Destination IPv6 address + * + * @return 0 on success, negative errno otherwise. + */ +int net_ipv6_create_new(struct net_pkt *pkt, + const struct in6_addr *src, + const struct in6_addr *dst); + +/** + * @brief Finalize IPv6 packet. It should be called right before + * sending the packet and after all the data has been added into + * the packet. This function will set the length of the + * packet and calculate the higher protocol checksum if needed. + * + * @param pkt Network packet + * @param next_header_proto Protocol type of the next header after IPv6 header. + * + * @return 0 on success, negative errno otherwise. + */ +int net_ipv6_finalize_new(struct net_pkt *pkt, u8_t next_header_proto); + + #if defined(CONFIG_NET_IPV6_MLD) /** * @brief Join a given multicast group. From e87cb7dfa3f21ea099b1c623939a110d5e1c9ec9 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 25 Jan 2019 20:40:07 +0100 Subject: [PATCH 30/70] net/pkt: Use next_hdr field only for IPv6 Also, store the actual next_hdr value and not it's position. This permits to reduce net_pkt from some bytes. Such field was unused until now, but it will be soon. Signed-off-by: Tomasz Bursztyka --- include/net/net_pkt.h | 35 ++++++++++++++++++++++++----------- subsys/net/ip/ipv6.c | 2 +- subsys/net/ip/net_pkt.c | 5 +++-- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index fa75032ccffc4..ac6eb7461e47e 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -96,7 +96,6 @@ struct net_pkt { #endif u8_t *appdata; /* application data starts here */ - u8_t *next_hdr; /* where is the next header */ /** Reference counter */ atomic_t atomic_ref; @@ -196,6 +195,7 @@ struct net_pkt { #endif /* CONFIG_NET_IPV6_FRAGMENT */ u8_t ipv6_ext_opt_len; /* IPv6 ND option length */ + u8_t ipv6_next_hdr; /* What is the very first next header */ #endif /* CONFIG_NET_IPV6 */ #if defined(CONFIG_IEEE802154) @@ -313,16 +313,6 @@ static inline void net_pkt_set_transport_proto(struct net_pkt *pkt, u8_t proto) pkt->transport_proto = proto; } -static inline u8_t *net_pkt_next_hdr(struct net_pkt *pkt) -{ - return pkt->next_hdr; -} - -static inline void net_pkt_set_next_hdr(struct net_pkt *pkt, u8_t *hdr) -{ - pkt->next_hdr = hdr; -} - static inline u8_t net_pkt_sent(struct net_pkt *pkt) { return pkt->sent_or_eof; @@ -411,6 +401,16 @@ static inline void net_pkt_set_ipv6_ext_opt_len(struct net_pkt *pkt, pkt->ipv6_ext_opt_len = len; } +static inline u8_t net_pkt_ipv6_next_hdr(struct net_pkt *pkt) +{ + return pkt->ipv6_next_hdr; +} + +static inline void net_pkt_set_ipv6_next_hdr(struct net_pkt *pkt, u8_t next_hdr) +{ + pkt->ipv6_next_hdr = next_hdr; +} + static inline u16_t net_pkt_ipv6_ext_len(struct net_pkt *pkt) { return pkt->ipv6_ext_len; @@ -457,6 +457,19 @@ static inline void net_pkt_set_ipv6_ext_opt_len(struct net_pkt *pkt, ARG_UNUSED(len); } +static inline u8_t net_pkt_ipv6_next_hdr(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return 0; +} + +static inline void net_pkt_set_ipv6_next_hdr(struct net_pkt *pkt, u8_t next_hdr) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(next_hdr); +} + static inline u16_t net_pkt_ipv6_ext_len(struct net_pkt *pkt) { ARG_UNUSED(pkt); diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index c80a589e92447..1dc1fcd9908c2 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -497,7 +497,7 @@ enum net_verdict net_ipv6_process_pkt(struct net_pkt *pkt, bool is_loopback) } /* Check extension headers */ - net_pkt_set_next_hdr(pkt, &hdr->nexthdr); + net_pkt_set_ipv6_next_hdr(pkt, hdr->nexthdr); net_pkt_set_ipv6_ext_len(pkt, 0); net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_HDR(pkt)->hop_limit); diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 68dae1e4b084d..088e34c0d3c02 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -2175,7 +2175,6 @@ struct net_pkt *net_pkt_clone(struct net_pkt *pkt, s32_t timeout) sizeof(clone->lladdr_dst)); } - net_pkt_set_next_hdr(clone, NULL); net_pkt_set_ip_hdr_len(clone, net_pkt_ip_hdr_len(pkt)); net_pkt_set_vlan_tag(clone, net_pkt_vlan_tag(pkt)); net_pkt_set_appdatalen(clone, net_pkt_appdatalen(pkt)); @@ -2187,6 +2186,7 @@ struct net_pkt *net_pkt_clone(struct net_pkt *pkt, s32_t timeout) clone->ipv6_ext_len = pkt->ipv6_ext_len; clone->ipv6_ext_opt_len = pkt->ipv6_ext_opt_len; clone->ipv6_prev_hdr_start = pkt->ipv6_prev_hdr_start; + net_pkt_set_ipv6_next_hdr(clone, net_pkt_ipv6_next_hdr(pkt)); #endif NET_DBG("Cloned %p to %p", pkt, clone); @@ -2939,7 +2939,6 @@ struct net_pkt *net_pkt_clone_new(struct net_pkt *pkt, s32_t timeout) net_pkt_set_family(clone_pkt, net_pkt_family(pkt)); net_pkt_set_context(clone_pkt, net_pkt_context(pkt)); net_pkt_set_token(clone_pkt, net_pkt_token(pkt)); - net_pkt_set_next_hdr(clone_pkt, NULL); net_pkt_set_ip_hdr_len(clone_pkt, net_pkt_ip_hdr_len(pkt)); net_pkt_set_vlan_tag(clone_pkt, net_pkt_vlan_tag(pkt)); net_pkt_set_timestamp(clone_pkt, net_pkt_timestamp(pkt)); @@ -2957,6 +2956,8 @@ struct net_pkt *net_pkt_clone_new(struct net_pkt *pkt, s32_t timeout) net_pkt_ipv6_ext_opt_len(pkt)); net_pkt_set_ipv6_hdr_prev(clone_pkt, net_pkt_ipv6_hdr_prev(pkt)); + net_pkt_set_ipv6_next_hdr(clone_pkt, + net_pkt_ipv6_next_hdr(pkt)); } net_pkt_cursor_init(clone_pkt); From 895d91a6c23b6553caaa1ef46a3f142c20f6925d Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 28 Jan 2019 10:01:34 +0100 Subject: [PATCH 31/70] net/ipv6: Account for extension headers when finalizing Extension headers are specific and use nexthdr attribute from net_pkt. next_header_proto is the user protocol (if any) that might require finalization too (calculating the checksum). However, if there are extension header, we need to skip those and jump to the position where the user protocol starts. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6.c | 16 +++++++++++++--- subsys/net/ip/net_pkt.c | 4 ++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 1dc1fcd9908c2..cb3dabbf01a55 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -183,12 +183,22 @@ int net_ipv6_finalize_new(struct net_pkt *pkt, u8_t next_header_proto) return -ENOBUFS; } - ipv6_hdr->len = htons(net_pkt_get_len(pkt) - - sizeof(struct net_ipv6_hdr)); - ipv6_hdr->nexthdr = next_header_proto; + ipv6_hdr->len = htons(net_pkt_get_len(pkt) - + sizeof(struct net_ipv6_hdr)); + + if (net_pkt_ipv6_next_hdr(pkt) != 255) { + ipv6_hdr->nexthdr = net_pkt_ipv6_next_hdr(pkt); + } else { + ipv6_hdr->nexthdr = next_header_proto; + } net_pkt_set_data(pkt, &ipv6_access); + if (net_pkt_ipv6_next_hdr(pkt) != 255 && + net_pkt_skip(pkt, net_pkt_ipv6_ext_len(pkt))) { + return -ENOBUFS; + } + if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt)) || next_header_proto == IPPROTO_ICMPV6) { if (IS_ENABLED(CONFIG_NET_UDP) && diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 088e34c0d3c02..a2766dcdb4635 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -2456,6 +2456,10 @@ static struct net_pkt *pkt_alloc(struct k_mem_slab *slab, s32_t timeout) pkt->atomic_ref = ATOMIC_INIT(1); pkt->slab = slab; + if (IS_ENABLED(CONFIG_NET_IPV6)) { + net_pkt_set_ipv6_next_hdr(pkt, 255); + } + #if NET_LOG_LEVEL >= LOG_LEVEL_DBG net_pkt_alloc_add(pkt, true, caller, line); #endif From 2ffabb25090a84be26a0ea5741552079a0bf07f2 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 17 Dec 2018 15:28:21 +0100 Subject: [PATCH 32/70] net/icmpv6: Switch echo request to new net pkt allocator and API This is pretty much the same as in ICMPv4. Actually, when it comes to the ICMP header, it could probably be put in a common places for both ICMPv4 and ICMPv6. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.c | 69 +++++++++++++++++++++++++----------------- subsys/net/ip/icmpv6.h | 5 +++ 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index 5b5fee67fe5a0..437724a0da423 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -529,68 +529,81 @@ int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, return err; } -#define append(pkt, type, value) \ - do { \ - if (!net_pkt_append_##type##_timeout(pkt, value, \ - PKT_WAIT_TIME)) { \ - ret = -ENOMEM; \ - goto drop; \ - } \ - } while (0) +static int icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, + &icmp_access); + if (!icmp_hdr) { + return -ENOBUFS; + } + + icmp_hdr->type = icmp_type; + icmp_hdr->code = icmp_code; + icmp_hdr->chksum = 0; + + return net_pkt_set_data(pkt, &icmp_access); +} int net_icmpv6_send_echo_request(struct net_if *iface, struct in6_addr *dst, u16_t identifier, u16_t sequence) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv6_access, + struct net_icmpv6_echo_req); + int ret = -ENOBUFS; + struct net_icmpv6_echo_req *echo_req; const struct in6_addr *src; struct net_pkt *pkt; - int ret; src = net_if_ipv6_select_src_addr(iface, dst); - pkt = net_pkt_get_reserve_tx(PKT_WAIT_TIME); + pkt = net_pkt_alloc_with_buffer(iface, + sizeof(struct net_icmpv6_echo_req), + AF_INET6, IPPROTO_ICMPV6, + PKT_WAIT_TIME); if (!pkt) { return -ENOMEM; } - if (!net_ipv6_create(pkt, src, dst, iface, IPPROTO_ICMPV6)) { - ret = -ENOMEM; + if (net_ipv6_create_new(pkt, src, dst) || + icmpv6_create(pkt, NET_ICMPV6_ECHO_REQUEST, 0)) { goto drop; } - net_pkt_set_family(pkt, AF_INET6); - net_pkt_set_iface(pkt, iface); + echo_req = (struct net_icmpv6_echo_req *)net_pkt_get_data_new( + pkt, &icmpv6_access); + if (!echo_req) { + goto drop; + } - append(pkt, u8, NET_ICMPV6_ECHO_REQUEST); - append(pkt, u8, 0); /* code */ - append(pkt, be16, 0); /* checksum */ - append(pkt, be16, identifier); - append(pkt, be16, sequence); + echo_req->identifier = htons(identifier); + echo_req->sequence = htons(sequence); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, src); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, dst); + net_pkt_set_data(pkt, &icmpv6_access); - if (net_ipv6_finalize(pkt, IPPROTO_ICMPV6) < 0) { - ret = -ENOMEM; - goto drop; - } + net_ipv6_finalize_new(pkt, IPPROTO_ICMPV6); NET_DBG("Sending ICMPv6 Echo Request type %d from %s to %s", NET_ICMPV6_ECHO_REQUEST, - log_strdup(net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->src)), - log_strdup(net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->dst))); + log_strdup(net_sprint_ipv6_addr(src)), + log_strdup(net_sprint_ipv6_addr(dst))); if (net_send_data(pkt) >= 0) { net_stats_update_icmp_sent(iface); return 0; } + net_stats_update_icmp_drop(iface); + ret = -EIO; drop: net_pkt_unref(pkt); - net_stats_update_icmp_drop(iface); return ret; } diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index a0d82a86d2a8a..740c6de6b9a30 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -75,6 +75,11 @@ struct net_icmpv6_nd_opt_6co { struct in6_addr prefix; } __packed; +struct net_icmpv6_echo_req { + u16_t identifier; + u16_t sequence; +} __packed; + #define NET_ICMPV6_ND_O_FLAG(flag) ((flag) & 0x40) #define NET_ICMPV6_ND_M_FLAG(flag) ((flag) & 0x80) From ed2d19ae9cccc90b81732ecf586f295975fdaf3e Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 18 Dec 2018 09:18:12 +0100 Subject: [PATCH 33/70] net/ipv6: Rework input function Use the new net_pkt API to proceed through IPv6 header and all the extension header as well. Use udp/tcp input functions relevantly, and call net_conn_input afterwards. Note: This commit temporarly disable IPv6 fragmentation support in the code directly. Which support will be re-enabled afterwards. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6.c | 392 ++++++++++++++++-------------------- subsys/net/ip/net_core.c | 4 +- subsys/net/ip/net_private.h | 2 +- tests/net/ipv6/src/main.c | 4 +- 4 files changed, 177 insertions(+), 225 deletions(-) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index cb3dabbf01a55..1d2a4789f412f 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -215,9 +215,10 @@ int net_ipv6_finalize_new(struct net_pkt *pkt, u8_t next_header_proto) return 0; } -static inline struct net_pkt *check_unknown_option(struct net_pkt *pkt, - u8_t opt_type, - u16_t length) +static inline bool ipv6_drop_on_unknown_option(struct net_pkt *pkt, + struct net_ipv6_hdr *hdr, + u8_t opt_type, + u16_t length) { /* RFC 2460 chapter 4.2 tells how to handle the unknown * options by the two highest order bits of the option: @@ -233,63 +234,64 @@ static inline struct net_pkt *check_unknown_option(struct net_pkt *pkt, * Problem, Code 2, message to the packet's Source Address, * pointing to the unrecognized Option Type. */ - NET_DBG("Unknown option %d (0x%02x) MSB %d", opt_type, opt_type, - opt_type >> 6); + NET_DBG("Unknown option %d (0x%02x) MSB %d - 0x%02x", + opt_type, opt_type, opt_type >> 6, opt_type & 0xc0); switch (opt_type & 0xc0) { case 0x00: - break; + return false; case 0x40: - return NULL; + break; case 0xc0: - if (net_ipv6_is_addr_mcast(&NET_IPV6_HDR(pkt)->dst)) { - return NULL; + if (net_ipv6_is_addr_mcast(&hdr->dst)) { + break; } + /* passthrough */ case 0x80: net_icmpv6_send_error(pkt, NET_ICMPV6_PARAM_PROBLEM, NET_ICMPV6_PARAM_PROB_OPTION, (u32_t)length); - return NULL; + break; } - return pkt; + return true; } -static inline struct net_buf *handle_ext_hdr_options(struct net_pkt *pkt, - struct net_buf *frag, - int total_len, - u16_t len, - u16_t offset, - u16_t *pos, - enum net_verdict *verdict) +static inline int ipv6_handle_ext_hdr_options(struct net_pkt *pkt, + struct net_ipv6_hdr *hdr, + u16_t pkt_len) { - u8_t opt_type, opt_len; - u16_t length = 0U, loc; + u16_t exthdr_len = 0U; + u16_t length = 0U; - if (len > total_len) { + if (net_pkt_read_u8_new(pkt, (u8_t *)&exthdr_len)) { + return -ENOBUFS; + } + + exthdr_len = exthdr_len * 8 + 8; + if (exthdr_len > pkt_len) { NET_DBG("Corrupted packet, extension header %d too long " - "(max %d bytes)", len, total_len); - *verdict = NET_DROP; - return NULL; + "(max %d bytes)", exthdr_len, pkt_len); + return -EINVAL; } length += 2; - /* Each extension option has type and length */ - frag = net_frag_read_u8(frag, offset, &loc, &opt_type); - if (!frag && loc == 0xffff) { - goto drop; - } + while (length < exthdr_len) { + u8_t opt_type, opt_len; - if (opt_type != NET_IPV6_EXT_HDR_OPT_PAD1) { - frag = net_frag_read_u8(frag, loc, &loc, &opt_len); - if (!frag && loc == 0xffff) { - goto drop; + /* Each extension option has type and length */ + if (net_pkt_read_u8_new(pkt, &opt_type)) { + return -ENOBUFS; + } + + if (opt_type != NET_IPV6_EXT_HDR_OPT_PAD1) { + if (net_pkt_read_u8_new(pkt, &opt_len)) { + return -ENOBUFS; + } } - } - while (frag && (length < len)) { switch (opt_type) { case NET_IPV6_EXT_HDR_OPT_PAD1: length++; @@ -297,55 +299,28 @@ static inline struct net_buf *handle_ext_hdr_options(struct net_pkt *pkt, case NET_IPV6_EXT_HDR_OPT_PADN: NET_DBG("PADN option"); length += opt_len + 2; - loc += opt_len + 2; + break; default: - if (!check_unknown_option(pkt, opt_type, length)) { - goto drop; + if (ipv6_drop_on_unknown_option(pkt, hdr, + opt_type, length)) { + return -ENOTSUP; } - length += opt_len + 2; - - /* No need to +2 here as loc already contains option - * header len. - */ - loc += opt_len; + if (net_pkt_skip(pkt, opt_len)) { + return -ENOBUFS; + } - break; - } + length += opt_len + 2; - if (length >= len) { break; } - - frag = net_frag_read_u8(frag, loc, &loc, &opt_type); - if (!frag && loc == 0xffff) { - goto drop; - } - - if (opt_type != NET_IPV6_EXT_HDR_OPT_PAD1) { - frag = net_frag_read_u8(frag, loc, &loc, &opt_len); - if (!frag && loc == 0xffff) { - goto drop; - } - } } - if (length != len) { - goto drop; - } - - *pos = loc; - - *verdict = NET_CONTINUE; - return frag; - -drop: - *verdict = NET_DROP; - return NULL; + return exthdr_len; } -static inline bool is_upper_layer_protocol_header(u8_t proto) +static inline bool ipv6_nexthdr_is_upper_layer(u8_t proto) { return (proto == IPPROTO_ICMPV6 || proto == IPPROTO_UDP || proto == IPPROTO_TCP); @@ -372,9 +347,9 @@ static struct net_route_entry *add_route(struct net_if *iface, } #endif /* CONFIG_NET_ROUTE */ -static void no_route_info(struct net_pkt *pkt, - struct in6_addr *src, - struct in6_addr *dst) +static void ipv6_no_route_info(struct net_pkt *pkt, + struct in6_addr *src, + struct in6_addr *dst) { NET_DBG("Will not route pkt %p ll src %s to dst %s between interfaces", pkt, log_strdup(net_sprint_ipv6_addr(src)), @@ -382,7 +357,7 @@ static void no_route_info(struct net_pkt *pkt, } #if defined(CONFIG_NET_ROUTE) -static enum net_verdict route_ipv6_packet(struct net_pkt *pkt, +static enum net_verdict ipv6_route_packet(struct net_pkt *pkt, struct net_ipv6_hdr *hdr) { struct net_route_entry *route; @@ -405,7 +380,7 @@ static enum net_verdict route_ipv6_packet(struct net_pkt *pkt, (net_ipv6_is_ll_addr(&hdr->src) || net_ipv6_is_ll_addr(&hdr->dst))) { /* RFC 4291 ch 2.5.6 */ - no_route_info(pkt, &hdr->src, &hdr->dst); + ipv6_no_route_info(pkt, &hdr->src, &hdr->dst); goto drop; } @@ -428,8 +403,7 @@ static enum net_verdict route_ipv6_packet(struct net_pkt *pkt, pkt, net_pkt_orig_iface(pkt), net_pkt_iface(pkt)); - add_route(net_pkt_orig_iface(pkt), - &NET_IPV6_HDR(pkt)->src, 128); + add_route(net_pkt_orig_iface(pkt), &hdr->src, 128); } ret = net_route_packet(pkt, nexthop); @@ -449,59 +423,75 @@ static enum net_verdict route_ipv6_packet(struct net_pkt *pkt, drop: return NET_DROP; } +#else +static inline enum net_verdict ipv6_route_packet(struct net_pkt *pkt, + struct net_ipv6_hdr *hdr) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(hdr); + + NET_DBG("DROP: Packet %p not for me", pkt); + + return NET_DROP; +} + #endif /* CONFIG_NET_ROUTE */ -enum net_verdict net_ipv6_process_pkt(struct net_pkt *pkt, bool is_loopback) +enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) { - struct net_ipv6_hdr *hdr = NET_IPV6_HDR(pkt); + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr); + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); + enum net_verdict verdict = NET_DROP; int real_len = net_pkt_get_len(pkt); - int pkt_len = ntohs(hdr->len) + sizeof(*hdr); - struct net_buf *frag; - u8_t start_of_ext, prev_hdr; - u8_t next, next_hdr; - u8_t first_option; - u16_t offset; - u16_t length; - u16_t total_len = 0U; - u8_t ext_bitmap; + u8_t ext_bitmap = 0U; + u16_t ext_len = 0U; + u8_t nexthdr, next_nexthdr; + union proto_header proto_hdr; + struct net_ipv6_hdr *hdr; + union ip_header ip; + int pkt_len; + + net_stats_update_ipv6_recv(net_pkt_iface(pkt)); + + hdr = (struct net_ipv6_hdr *)net_pkt_get_data_new(pkt, &ipv6_access); + if (!hdr) { + NET_DBG("DROP: no buffer"); + goto drop; + } + pkt_len = ntohs(hdr->len) + sizeof(struct net_ipv6_hdr); if (real_len < pkt_len) { - NET_DBG("IPv6 packet size %d pkt len %d", pkt_len, real_len); - net_stats_update_ipv6_drop(net_pkt_iface(pkt)); + NET_DBG("DROP: pkt len per hdr %d != pkt real len %d", + pkt_len, real_len); goto drop; } else if (real_len > pkt_len) { - net_pkt_pull(pkt, pkt_len, real_len - pkt_len); - real_len = net_pkt_get_len(pkt); + net_pkt_update_length(pkt, pkt_len); } - NET_DBG("IPv6 packet len %d received from %s to %s", real_len, + NET_DBG("IPv6 packet len %d received from %s to %s", pkt_len, log_strdup(net_sprint_ipv6_addr(&hdr->src)), log_strdup(net_sprint_ipv6_addr(&hdr->dst))); - if (!is_loopback && (net_ipv6_is_addr_loopback(&hdr->dst) || - net_ipv6_is_addr_loopback(&hdr->src))) { - NET_DBG("Dropping ::1 packet"); - net_stats_update_ipv6_drop(net_pkt_iface(pkt)); - goto drop; - } - if (net_ipv6_is_addr_mcast(&hdr->src) || net_ipv6_is_addr_mcast_scope(&hdr->dst, 0)) { - NET_DBG("Dropping multicast packet"); - net_stats_update_ipv6_drop(net_pkt_iface(pkt)); + NET_DBG("DROP: multicast packet"); goto drop; } if (!is_loopback) { - bool is_empty_group = net_ipv6_is_addr_mcast_group( - &hdr->dst, net_ipv6_unspecified_address()); + if (net_ipv6_is_addr_loopback(&hdr->dst) || + net_ipv6_is_addr_loopback(&hdr->src)) { + NET_DBG("DROP: ::1 packet"); + goto drop; + } if (net_ipv6_is_addr_mcast_iface(&hdr->dst) || - (is_empty_group && + (net_ipv6_is_addr_mcast_group( + &hdr->dst, net_ipv6_unspecified_address()) && (net_ipv6_is_addr_mcast_site(&hdr->dst) || net_ipv6_is_addr_mcast_org(&hdr->dst)))) { - NET_DBG("Dropping invalid scope multicast packet"); - net_stats_update_ipv6_drop(net_pkt_iface(pkt)); + NET_DBG("DROP: invalid scope multicast packet"); goto drop; } } @@ -515,18 +505,10 @@ enum net_verdict net_ipv6_process_pkt(struct net_pkt *pkt, bool is_loopback) if (!net_ipv6_is_my_addr(&hdr->dst) && !net_ipv6_is_my_maddr(&hdr->dst) && !net_ipv6_is_addr_mcast(&hdr->dst)) { -#if defined(CONFIG_NET_ROUTE) - enum net_verdict verdict; - - verdict = route_ipv6_packet(pkt, hdr); - if (verdict == NET_OK) { + if (ipv6_route_packet(pkt, hdr) == NET_OK) { return NET_OK; } -#else /* CONFIG_NET_ROUTE */ - NET_DBG("IPv6 packet in pkt %p not for me", pkt); -#endif /* CONFIG_NET_ROUTE */ - net_stats_update_ipv6_drop(net_pkt_iface(pkt)); goto drop; } @@ -539,155 +521,125 @@ enum net_verdict net_ipv6_process_pkt(struct net_pkt *pkt, bool is_loopback) !net_ipv6_is_addr_mcast(&hdr->dst) && !net_if_ipv6_addr_lookup_by_iface(net_pkt_iface(pkt), &hdr->dst)) { - no_route_info(pkt, &hdr->src, &hdr->dst); - - net_stats_update_ipv6_drop(net_pkt_iface(pkt)); + ipv6_no_route_info(pkt, &hdr->src, &hdr->dst); goto drop; } - /* Fast path for main upper layer protocols. The handling of extension - * headers can be slow so do this checking here. There cannot - * be any extension headers after the upper layer protocol header. - */ - next = *(net_pkt_next_hdr(pkt)); - if (is_upper_layer_protocol_header(next)) { - goto upper_proto; - } + net_pkt_acknowledge_data(pkt, &ipv6_access); - /* Go through the extensions */ - frag = pkt->frags; - next = hdr->nexthdr; - first_option = next; - length = 0U; - ext_bitmap = 0U; - start_of_ext = 0U; - offset = sizeof(struct net_ipv6_hdr); - prev_hdr = &NET_IPV6_HDR(pkt)->nexthdr - &NET_IPV6_HDR(pkt)->vtc; - - while (frag) { - enum net_verdict verdict; - - if (is_upper_layer_protocol_header(next)) { - NET_DBG("IPv6 next header %d", next); - goto upper_proto; - } + nexthdr = hdr->nexthdr; + while (!ipv6_nexthdr_is_upper_layer(nexthdr)) { + u16_t exthdr_len; - if (!start_of_ext) { - start_of_ext = offset; - } + NET_DBG("IPv6 next header %d", nexthdr); - frag = net_frag_read_u8(frag, offset, &offset, &next_hdr); - if (!frag) { + if (net_pkt_read_u8_new(pkt, &next_nexthdr)) { goto drop; } - verdict = NET_OK; - - NET_DBG("IPv6 next header %d", next); - - switch (next) { - case NET_IPV6_NEXTHDR_NONE: - /* There is nothing after this header (see RFC 2460, - * ch 4.7), so we can drop the packet now. - * This is not an error case so do not update drop - * statistics. - */ - goto drop; - - case NET_IPV6_NEXTHDR_DESTO: - frag = net_frag_read_u8(frag, offset, &offset, - (u8_t *)&length); - if (!frag) { - goto drop; - } - length = length * 8 + 8; - total_len += length; - - ext_bitmap |= NET_IPV6_NEXTHDR_DESTO; - - frag = handle_ext_hdr_options(pkt, frag, real_len, - length, offset, &offset, - &verdict); - break; - + switch (nexthdr) { case NET_IPV6_NEXTHDR_HBHO: if (ext_bitmap & NET_IPV6_EXT_HDR_BITMAP_HBHO) { - NET_ERR("Dropping packet with multiple HBHO"); + NET_ERR("DROP: multiple hop-by-hop"); goto drop; } - frag = net_frag_read_u8(frag, offset, &offset, - (u8_t *)&length); - if (!frag) { - goto drop; + /* HBH option needs to be the first one */ + if (nexthdr != hdr->nexthdr) { + goto bad_hdr; } - length = length * 8 + 8; - total_len += length; + ext_bitmap |= NET_IPV6_EXT_HDR_BITMAP_HBHO; - /* HBH option needs to be the first one */ - if (first_option != NET_IPV6_NEXTHDR_HBHO) { + break; + + case NET_IPV6_NEXTHDR_DESTO: + if (ext_bitmap & NET_IPV6_EXT_HDR_BITMAP_DESTO2) { + /* DESTO option cannot appear more than twice */ goto bad_hdr; } - ext_bitmap |= NET_IPV6_EXT_HDR_BITMAP_HBHO; + if (ext_bitmap & NET_IPV6_EXT_HDR_BITMAP_DESTO1) { + ext_bitmap |= NET_IPV6_EXT_HDR_BITMAP_DESTO2; + } else { + ext_bitmap |= NET_IPV6_EXT_HDR_BITMAP_DESTO1; + } - frag = handle_ext_hdr_options(pkt, frag, real_len, - length, offset, &offset, - &verdict); break; -#if defined(CONFIG_NET_IPV6_FRAGMENT) case NET_IPV6_NEXTHDR_FRAG: - net_pkt_set_ipv6_hdr_prev(pkt, prev_hdr); + /* Temporarly unsupported */ + goto bad_hdr; - net_pkt_set_ipv6_fragment_start(pkt, - sizeof(struct - net_ipv6_hdr) + - total_len); + case NET_IPV6_NEXTHDR_NONE: + /* There is nothing after this header (see RFC 2460, + * ch 4.7), so we can drop the packet now. + * This is not an error case so do not update drop + * statistics. + */ + return NET_DROP; - total_len += 8; - return net_ipv6_handle_fragment_hdr(pkt, frag, real_len, - offset, &offset, - next_hdr); -#endif default: goto bad_hdr; } - if (verdict == NET_DROP) { + exthdr_len = ipv6_handle_ext_hdr_options(pkt, hdr, pkt_len); + if (exthdr_len < 0) { goto drop; } - prev_hdr = start_of_ext; - next = next_hdr; + ext_len += exthdr_len; + nexthdr = next_nexthdr; } -upper_proto: + net_pkt_set_ipv6_ext_len(pkt, ext_len); + net_pkt_set_transport_proto(pkt, nexthdr); + net_pkt_set_family(pkt, PF_INET6); - net_pkt_set_ipv6_ext_len(pkt, total_len); - net_pkt_set_transport_proto(pkt, next); - - switch (next) { + switch (nexthdr) { case IPPROTO_ICMPV6: - return net_icmpv6_input(pkt); - case IPPROTO_UDP: - /* Fall through */ + verdict = net_icmpv6_input(pkt); + break; case IPPROTO_TCP: - return net_conn_input(next, pkt); + proto_hdr.tcp = net_tcp_input(pkt, &tcp_access); + if (proto_hdr.tcp) { + verdict = NET_OK; + } + break; + case IPPROTO_UDP: + proto_hdr.udp = net_udp_input(pkt, &udp_access); + if (proto_hdr.udp) { + verdict = NET_OK; + } + break; + } + + if (verdict == NET_DROP) { + if (nexthdr == IPPROTO_ICMPV6) { + return verdict; + } + + goto drop; + } + + ip.ipv6 = hdr; + + verdict = net_conn_input(pkt, &ip, nexthdr, &proto_hdr); + if (verdict != NET_DROP) { + return verdict; } drop: + net_stats_update_ipv6_drop(net_pkt_iface(pkt)); return NET_DROP; bad_hdr: - /* Send error message about parameter problem (RFC 2460) - */ + /* Send error message about parameter problem (RFC 2460) */ net_icmpv6_send_error(pkt, NET_ICMPV6_PARAM_PROBLEM, NET_ICMPV6_PARAM_PROB_NEXTHEADER, - offset - 1); + net_pkt_get_current_offset(pkt) - 1); - NET_DBG("Unknown next header type"); + NET_DBG("DROP: Unknown/wrong nexthdr type"); net_stats_update_ip_errors_protoerr(net_pkt_iface(pkt)); return NET_DROP; diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 094e072b6b4f2..31b69bcb76026 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -111,9 +111,7 @@ static inline enum net_verdict process_data(struct net_pkt *pkt, switch (NET_IPV6_HDR(pkt)->vtc & 0xf0) { #if defined(CONFIG_NET_IPV6) case 0x60: - net_stats_update_ipv6_recv(net_pkt_iface(pkt)); - net_pkt_set_family(pkt, PF_INET6); - return net_ipv6_process_pkt(pkt, is_loopback); + return net_ipv6_input(pkt, is_loopback); #endif #if defined(CONFIG_NET_IPV4) case 0x40: diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index a9cf41e70c780..bd2e33cbd635e 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -44,7 +44,7 @@ extern void net_if_post_init(void); extern void net_if_carrier_down(struct net_if *iface); extern void net_context_init(void); enum net_verdict net_ipv4_input(struct net_pkt *pkt); -enum net_verdict net_ipv6_process_pkt(struct net_pkt *pkt, bool is_loopback); +enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback); extern void net_tc_tx_init(void); extern void net_tc_rx_init(void); extern void net_tc_submit_to_tx_queue(u8_t tc, struct net_pkt *pkt); diff --git a/tests/net/ipv6/src/main.c b/tests/net/ipv6/src/main.c index 7987f702a4aaa..980554141a5c1 100644 --- a/tests/net/ipv6/src/main.c +++ b/tests/net/ipv6/src/main.c @@ -1166,10 +1166,12 @@ static enum net_verdict recv_msg(struct in6_addr *src, struct in6_addr *dst) setup_ipv6_udp(pkt, src, dst, 4242, 4321); + net_pkt_cursor_init(pkt); + /* We by-pass the normal packet receiving flow in this case in order * to simplify the testing. */ - return net_ipv6_process_pkt(pkt, false); + return net_ipv6_input(pkt, false); } static int send_msg(struct in6_addr *src, struct in6_addr *dst) From 6be52d21418d9a2a541f883a15ef15b1288c2d2a Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 18 Dec 2018 15:28:40 +0100 Subject: [PATCH 34/70] net/icmpv6: Rework relevant signatures to pass ipv6 header pointer This is meant to remove the need for macro NET_IPV6_HDR(), since we don't know in future if accessing the header that way will be valid. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.c | 46 ++++++++++-------- subsys/net/ip/icmpv6.h | 7 ++- subsys/net/ip/ipv6.c | 2 +- subsys/net/ip/ipv6_mld.c | 11 ++--- subsys/net/ip/ipv6_nbr.c | 96 ++++++++++++++++--------------------- subsys/net/ip/net_shell.c | 10 ++-- tests/net/icmpv6/src/main.c | 25 ++++++++-- tests/net/mld/src/main.c | 3 +- 8 files changed, 106 insertions(+), 94 deletions(-) diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index 437724a0da423..fa5b3fd39626d 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -302,7 +302,8 @@ int net_icmpv6_get_ra_hdr(struct net_pkt *pkt, struct net_icmpv6_ra_hdr *hdr) return 0; } -static enum net_verdict handle_echo_request(struct net_pkt *orig) +static enum net_verdict handle_echo_request(struct net_pkt *orig, + struct net_ipv6_hdr *ip_hdr) { struct net_icmp_hdr icmp_hdr; struct net_pkt *pkt; @@ -312,12 +313,12 @@ static enum net_verdict handle_echo_request(struct net_pkt *orig) int ret; NET_DBG("Received Echo Request from %s to %s", - log_strdup(net_sprint_ipv6_addr(&NET_IPV6_HDR(orig)->src)), - log_strdup(net_sprint_ipv6_addr(&NET_IPV6_HDR(orig)->dst))); + log_strdup(net_sprint_ipv6_addr(&ip_hdr->src)), + log_strdup(net_sprint_ipv6_addr(&ip_hdr->dst))); iface = net_pkt_iface(orig); - payload_len = ntohs(NET_IPV6_HDR(orig)->len) - + payload_len = ntohs(ip_hdr->len) - net_pkt_ipv6_ext_len(orig) - NET_ICMPH_LEN; if (payload_len < NET_ICMPV6_UNUSED_LEN) { /* No identifier or sequence number present */ @@ -353,17 +354,17 @@ static enum net_verdict handle_echo_request(struct net_pkt *orig) if (net_ipv6_is_addr_mcast(&NET_IPV6_HDR(pkt)->dst)) { net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, - &NET_IPV6_HDR(orig)->src); + &ip_hdr->src); net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, net_if_ipv6_select_src_addr(iface, - &NET_IPV6_HDR(orig)->dst)); + &ip_hdr->dst)); } else { struct in6_addr addr; - net_ipaddr_copy(&addr, &NET_IPV6_HDR(orig)->src); + net_ipaddr_copy(&addr, &ip_hdr->src); net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(orig)->dst); + &ip_hdr->dst); net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &addr); } @@ -608,31 +609,36 @@ int net_icmpv6_send_echo_request(struct net_if *iface, return ret; } -enum net_verdict net_icmpv6_input(struct net_pkt *pkt) +enum net_verdict net_icmpv6_input(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; struct net_icmpv6_handler *cb; - struct net_icmp_hdr icmp_hdr; - if (net_calc_chksum_icmpv6(pkt) != 0) { - NET_DBG("DROP: invalid checksum"); - goto drop; + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, + &icmp_access); + if (!icmp_hdr) { + NET_DBG("DROP: NULL ICMPv6 header"); + return NET_DROP; } - if (net_icmpv6_get_hdr(pkt, &icmp_hdr)) { - NET_DBG("DROP: NULL ICMPv6 header"); + if (net_calc_chksum_icmpv6(pkt) != 0) { + NET_DBG("DROP: invalid checksum"); goto drop; } NET_DBG("ICMPv6 %s received type %d code %d", - net_icmpv6_type2str(icmp_hdr.type), - icmp_hdr.type, icmp_hdr.code); + net_icmpv6_type2str(icmp_hdr->type), + icmp_hdr->type, icmp_hdr->code); net_stats_update_icmp_recv(net_pkt_iface(pkt)); SYS_SLIST_FOR_EACH_CONTAINER(&handlers, cb, node) { - if (cb->type == icmp_hdr.type && - (cb->code == icmp_hdr.code || cb->code == 0)) { - return cb->handler(pkt); + if (cb->type == icmp_hdr->type && + (cb->code == icmp_hdr->code || cb->code == 0)) { + return cb->handler(pkt, ip_hdr); } } drop: diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index 740c6de6b9a30..15b4dec35a433 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -132,7 +132,9 @@ struct net_icmpv6_echo_req { /* ICMPv6 header has 4 unused bytes that must be zero, RFC 4443 ch 3.1 */ #define NET_ICMPV6_UNUSED_LEN 4 -typedef enum net_verdict (*icmpv6_callback_handler_t)(struct net_pkt *pkt); +typedef enum net_verdict (*icmpv6_callback_handler_t)( + struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr); const char *net_icmpv6_type2str(int icmpv6_type); @@ -175,7 +177,8 @@ int net_icmpv6_send_echo_request(struct net_if *iface, void net_icmpv6_register_handler(struct net_icmpv6_handler *handler); void net_icmpv6_unregister_handler(struct net_icmpv6_handler *handler); -enum net_verdict net_icmpv6_input(struct net_pkt *pkt); +enum net_verdict net_icmpv6_input(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr); int net_icmpv6_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); int net_icmpv6_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 1d2a4789f412f..6633654822125 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -598,7 +598,7 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) switch (nexthdr) { case IPPROTO_ICMPV6: - verdict = net_icmpv6_input(pkt); + verdict = net_icmpv6_input(pkt, hdr); break; case IPPROTO_TCP: proto_hdr.tcp = net_tcp_input(pkt, &tcp_access); diff --git a/subsys/net/ip/ipv6_mld.c b/subsys/net/ip/ipv6_mld.c index d480c6c9f7229..ebb19c57814ea 100644 --- a/subsys/net/ip/ipv6_mld.c +++ b/subsys/net/ip/ipv6_mld.c @@ -298,7 +298,8 @@ static void send_mld_report(struct net_if *iface) #define dbg_addr_recv(pkt_str, src, dst) \ dbg_addr("Received", pkt_str, src, dst) -static enum net_verdict handle_mld_query(struct net_pkt *pkt) +static enum net_verdict handle_mld_query(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) { u16_t total_len = net_pkt_get_len(pkt); struct in6_addr mcast; @@ -307,9 +308,7 @@ static enum net_verdict handle_mld_query(struct net_pkt *pkt) struct net_buf *frag; int ret; - dbg_addr_recv("Multicast Listener Query", - &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst); + dbg_addr_recv("Multicast Listener Query", &ip_hdr->src, &ip_hdr->dst); net_stats_update_ipv6_mld_recv(net_pkt_iface(pkt)); @@ -334,14 +333,14 @@ static enum net_verdict handle_mld_query(struct net_pkt *pkt) sizeof(struct in6_addr) * num_src; if ((total_len < pkt_len || pkt_len > NET_IPV6_MTU || - (NET_IPV6_HDR(pkt)->hop_limit != 1))) { + (ip_hdr->hop_limit != 1))) { struct net_icmp_hdr icmp_hdr; ret = net_icmpv6_get_hdr(pkt, &icmp_hdr); if (ret < 0 || icmp_hdr.code != 0) { NET_DBG("Preliminary check failed %u/%u, code %u, " "hop %u", total_len, pkt_len, - icmp_hdr.code, NET_IPV6_HDR(pkt)->hop_limit); + icmp_hdr.code, ip_hdr->hop_limit); goto drop; } } diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 7166dd79b846a..c1b655da47550 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1085,7 +1085,8 @@ static void ns_routing_info(struct net_pkt *pkt, } } -static enum net_verdict handle_ns_input(struct net_pkt *pkt) +static enum net_verdict handle_ns_input(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) { u16_t total_len = net_pkt_get_len(pkt); u8_t prev_opt_len = 0U; @@ -1106,16 +1107,14 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) } dbg_addr_recv_tgt("Neighbor Solicitation", - &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst, - &ns_hdr.tgt); + &ip_hdr->src, &ip_hdr->dst, &ns_hdr.tgt); net_stats_update_ipv6_nd_recv(net_pkt_iface(pkt)); if ((total_len < (sizeof(struct net_ipv6_hdr) + sizeof(struct net_icmp_hdr) + sizeof(struct net_icmpv6_ns_hdr))) || - (NET_IPV6_HDR(pkt)->hop_limit != NET_IPV6_ND_HOP_LIMIT)) { + (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT)) { if (net_ipv6_is_addr_mcast(&ns_hdr.tgt)) { struct net_icmp_hdr icmp_hdr; @@ -1127,8 +1126,7 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) (sizeof(struct net_ipv6_hdr) + sizeof(struct net_icmp_hdr) + sizeof(struct net_icmpv6_ns_hdr)), - icmp_hdr.code, - NET_IPV6_HDR(pkt)->hop_limit); + icmp_hdr.code, ip_hdr->hop_limit); goto drop; } } @@ -1148,8 +1146,7 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) switch (nd_opt_hdr.type) { case NET_ICMPV6_ND_OPT_SLLAO: - if (net_ipv6_is_addr_unspecified( - &NET_IPV6_HDR(pkt)->src)) { + if (net_ipv6_is_addr_unspecified(&ip_hdr->src)) { goto drop; } @@ -1214,14 +1211,13 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) * received. */ src = net_if_ipv6_select_src_addr( - net_pkt_iface(pkt), - &NET_IPV6_HDR(pkt)->src); + net_pkt_iface(pkt), &ip_hdr->src); if (!src) { NET_DBG("No interface address for " "dst %s iface %p", log_strdup( net_sprint_ipv6_addr( - &NET_IPV6_HDR(pkt)->src)), + &ip_hdr->src)), net_pkt_iface(pkt)); goto drop; } @@ -1240,25 +1236,24 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) /* As we swap the addresses later, the source will correctly * have our address. */ - src = &NET_IPV6_HDR(pkt)->src; + src = &ip_hdr->src; } nexthop_found: #if !defined(CONFIG_NET_IPV6_DAD) - if (net_ipv6_is_addr_unspecified(&NET_IPV6_HDR(pkt)->src)) { + if (net_ipv6_is_addr_unspecified(&ip_hdr->src)) { goto drop; } #else /* CONFIG_NET_IPV6_DAD */ /* Do DAD */ - if (net_ipv6_is_addr_unspecified(&NET_IPV6_HDR(pkt)->src)) { + if (net_ipv6_is_addr_unspecified(&ip_hdr->src)) { - if (!net_ipv6_is_addr_solicited_node(&NET_IPV6_HDR(pkt)->dst)) { + if (!net_ipv6_is_addr_solicited_node(&ip_hdr->dst)) { NET_DBG("Not solicited node addr %s", - log_strdup(net_sprint_ipv6_addr( - &NET_IPV6_HDR(pkt)->dst))); + log_strdup(net_sprint_ipv6_addr(&ip_hdr->dst))); goto drop; } @@ -1274,27 +1269,25 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) } /* We reuse the received packet to send the NA */ - net_ipv6_addr_create_ll_allnodes_mcast(&NET_IPV6_HDR(pkt)->dst); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, + net_ipv6_addr_create_ll_allnodes_mcast(&ip_hdr->dst); + net_ipaddr_copy(&ip_hdr->src, net_if_ipv6_select_src_addr(net_pkt_iface(pkt), - &NET_IPV6_HDR(pkt)->dst)); + &ip_hdr->dst)); flags = NET_ICMPV6_NA_FLAG_OVERRIDE; goto send_na; } #endif /* CONFIG_NET_IPV6_DAD */ - if (net_ipv6_is_my_addr(&NET_IPV6_HDR(pkt)->src)) { + if (net_ipv6_is_my_addr(&ip_hdr->src)) { NET_DBG("Duplicate IPv6 %s address", - log_strdup(net_sprint_ipv6_addr( - &NET_IPV6_HDR(pkt)->src))); + log_strdup(net_sprint_ipv6_addr(&ip_hdr->src))); goto drop; } /* Address resolution */ - if (net_ipv6_is_addr_solicited_node(&NET_IPV6_HDR(pkt)->dst)) { - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, - &NET_IPV6_HDR(pkt)->src); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, &ns_hdr.tgt); + if (net_ipv6_is_addr_solicited_node(&ip_hdr->dst)) { + net_ipaddr_copy(&ip_hdr->dst, &ip_hdr->src); + net_ipaddr_copy(&ip_hdr->src, &ns_hdr.tgt); flags = NET_ICMPV6_NA_FLAG_SOLICITED | NET_ICMPV6_NA_FLAG_OVERRIDE; goto send_na; @@ -1307,18 +1300,16 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) /* Neighbor Unreachability Detection (NUD) */ if (IS_ENABLED(CONFIG_NET_ROUTING)) { - ifaddr = net_if_ipv6_addr_lookup(&NET_IPV6_HDR(pkt)->dst, - NULL); + ifaddr = net_if_ipv6_addr_lookup(&ip_hdr->dst, NULL); } else { ifaddr = net_if_ipv6_addr_lookup_by_iface(net_pkt_iface(pkt), - &NET_IPV6_HDR(pkt)->dst); + &ip_hdr->dst); } if (ifaddr) { - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, - &NET_IPV6_HDR(pkt)->src); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, &ns_hdr.tgt); - src = &NET_IPV6_HDR(pkt)->src; + net_ipaddr_copy(&ip_hdr->dst, &ip_hdr->src); + net_ipaddr_copy(&ip_hdr->src, &ns_hdr.tgt); + src = &ip_hdr->src; tgt = &ifaddr->address.in6_addr; flags = NET_ICMPV6_NA_FLAG_SOLICITED | NET_ICMPV6_NA_FLAG_OVERRIDE; @@ -1329,11 +1320,8 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) } send_na: - ret = net_ipv6_send_na(net_pkt_iface(pkt), - src, - &NET_IPV6_HDR(pkt)->dst, - tgt, - flags); + ret = net_ipv6_send_na(net_pkt_iface(pkt), src, + &ip_hdr->dst, tgt, flags); if (!ret) { net_pkt_unref(pkt); return NET_OK; @@ -1685,7 +1673,8 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, return true; } -static enum net_verdict handle_na_input(struct net_pkt *pkt) +static enum net_verdict handle_na_input(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) { u16_t total_len = net_pkt_get_len(pkt); u16_t tllao_offset = 0U; @@ -1703,9 +1692,7 @@ static enum net_verdict handle_na_input(struct net_pkt *pkt) } dbg_addr_recv_tgt("Neighbor Advertisement", - &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst, - &na_hdr.tgt); + &ip_hdr->src, &ip_hdr->dst, &na_hdr.tgt); net_stats_update_ipv6_nd_recv(net_pkt_iface(pkt)); @@ -1713,10 +1700,10 @@ static enum net_verdict handle_na_input(struct net_pkt *pkt) sizeof(struct net_icmp_hdr) + sizeof(struct net_icmpv6_na_hdr) + sizeof(struct net_icmpv6_nd_opt_hdr))) || - (NET_IPV6_HDR(pkt)->hop_limit != NET_IPV6_ND_HOP_LIMIT) || + (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT) || net_ipv6_is_addr_mcast(&na_hdr.tgt) || (net_is_solicited(pkt) && - net_ipv6_is_addr_mcast(&NET_IPV6_HDR(pkt)->dst))) { + net_ipv6_is_addr_mcast(&ip_hdr->dst))) { struct net_icmp_hdr icmp_hdr; ret = net_icmpv6_get_hdr(pkt, &icmp_hdr); @@ -2333,7 +2320,8 @@ static inline struct net_buf *handle_ra_6co(struct net_pkt *pkt, } #endif -static enum net_verdict handle_ra_input(struct net_pkt *pkt) +static enum net_verdict handle_ra_input(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) { u16_t total_len = net_pkt_get_len(pkt); struct net_nbr *nbr = NULL; @@ -2350,9 +2338,7 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt) u32_t mtu; int ret; - dbg_addr_recv("Router Advertisement", - &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst); + dbg_addr_recv("Router Advertisement", &ip_hdr->src, &ip_hdr->dst); net_stats_update_ipv6_nd_recv(net_pkt_iface(pkt)); @@ -2360,8 +2346,8 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt) sizeof(struct net_icmp_hdr) + sizeof(struct net_icmpv6_ra_hdr) + sizeof(struct net_icmpv6_nd_opt_hdr))) || - (NET_IPV6_HDR(pkt)->hop_limit != NET_IPV6_ND_HOP_LIMIT) || - !net_ipv6_is_ll_addr(&NET_IPV6_HDR(pkt)->src)) { + (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT) || + !net_ipv6_is_ll_addr(&ip_hdr->src)) { struct net_icmp_hdr icmp_hdr; ret = net_icmpv6_get_hdr(pkt, &icmp_hdr); @@ -2499,8 +2485,7 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt) } } - router = net_if_ipv6_router_lookup(net_pkt_iface(pkt), - &NET_IPV6_HDR(pkt)->src); + router = net_if_ipv6_router_lookup(net_pkt_iface(pkt), &ip_hdr->src); if (router) { if (!router_lifetime) { /* TODO: Start rs_timer on iface if no routers @@ -2517,8 +2502,7 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt) } } else { net_if_ipv6_router_add(net_pkt_iface(pkt), - &NET_IPV6_HDR(pkt)->src, - router_lifetime); + &ip_hdr->src, router_lifetime); } if (nbr && net_ipv6_nbr_data(nbr)->pending) { diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index dacd97d309987..176330ea7bd9c 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -2741,7 +2741,8 @@ static const struct shell *shell_for_ping; #if defined(CONFIG_NET_IPV6) -static enum net_verdict _handle_ipv6_echo_reply(struct net_pkt *pkt); +static enum net_verdict _handle_ipv6_echo_reply(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr); static struct net_icmpv6_handler ping6_handler = { .type = NET_ICMPV6_ECHO_REPLY, @@ -2754,11 +2755,12 @@ static inline void _remove_ipv6_ping_handler(void) net_icmpv6_unregister_handler(&ping6_handler); } -static enum net_verdict _handle_ipv6_echo_reply(struct net_pkt *pkt) +static enum net_verdict _handle_ipv6_echo_reply(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) { PR_SHELL(shell_for_ping, "Received echo reply from %s to %s\n", - net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->src), - net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->dst)); + net_sprint_ipv6_addr(&ip_hdr->src), + net_sprint_ipv6_addr(&ip_hdr->dst)); k_sem_give(&ping_timeout); _remove_ipv6_ping_handler(); diff --git a/tests/net/icmpv6/src/main.c b/tests/net/icmpv6/src/main.c index 6e453b7043a00..a671b6259b1d5 100644 --- a/tests/net/icmpv6/src/main.c +++ b/tests/net/icmpv6/src/main.c @@ -60,7 +60,8 @@ static char icmpv6_inval_chksum[] = NET_PKT_TX_SLAB_DEFINE(pkts_slab, 2); NET_BUF_POOL_DEFINE(data_pool, 2, 128, 0, NULL); -static enum net_verdict handle_test_msg(struct net_pkt *pkt) +static enum net_verdict handle_test_msg(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) { struct net_buf *last = net_buf_frag_last(pkt->frags); enum net_verdict ret; @@ -94,6 +95,7 @@ void test_icmpv6(void) { k_thread_priority_set(k_current_get(), K_PRIO_COOP(7)); + struct net_ipv6_hdr *hdr; struct net_pkt *pkt; struct net_buf *frag; int ret; @@ -115,7 +117,12 @@ void test_icmpv6(void) memcpy(net_buf_add(frag, sizeof(icmpv6_inval_chksum)), icmpv6_inval_chksum, sizeof(icmpv6_inval_chksum)); - ret = net_icmpv6_input(pkt); + hdr = (struct net_ipv6_hdr *)pkt->buffer->data; + net_pkt_cursor_init(pkt); + net_pkt_set_overwrite(pkt, true); + net_pkt_skip(pkt, sizeof(struct net_ipv6_hdr)); + + ret = net_icmpv6_input(pkt, hdr); /**TESTPOINT: Check input*/ zassert_true(ret == NET_DROP, "Callback not called properly"); @@ -126,7 +133,12 @@ void test_icmpv6(void) memcpy(net_buf_add(frag, sizeof(icmpv6_echo_rep)), icmpv6_echo_rep, sizeof(icmpv6_echo_rep)); - ret = net_icmpv6_input(pkt); + hdr = (struct net_ipv6_hdr *)pkt->buffer->data; + net_pkt_cursor_init(pkt); + net_pkt_set_overwrite(pkt, true); + net_pkt_skip(pkt, sizeof(struct net_ipv6_hdr)); + + ret = net_icmpv6_input(pkt, hdr); /**TESTPOINT: Check input*/ zassert_true(!(ret == NET_DROP || handler_status != 0), @@ -138,7 +150,12 @@ void test_icmpv6(void) memcpy(net_buf_add(frag, sizeof(icmpv6_echo_req)), icmpv6_echo_req, sizeof(icmpv6_echo_req)); - ret = net_icmpv6_input(pkt); + hdr = (struct net_ipv6_hdr *)pkt->buffer->data; + net_pkt_cursor_init(pkt); + net_pkt_set_overwrite(pkt, true); + net_pkt_skip(pkt, sizeof(struct net_ipv6_hdr)); + + ret = net_icmpv6_input(pkt, hdr); /**TESTPOINT: Check input*/ zassert_true(!(ret == NET_DROP || handler_status != 0), diff --git a/tests/net/mld/src/main.c b/tests/net/mld/src/main.c index 3f155a2d4542e..68f580cac7166 100644 --- a/tests/net/mld/src/main.c +++ b/tests/net/mld/src/main.c @@ -367,7 +367,8 @@ static void send_query(struct net_if *iface) } /* We are not really interested to parse the query at this point */ -static enum net_verdict handle_mld_query(struct net_pkt *pkt) +static enum net_verdict handle_mld_query(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) { is_query_received = true; From 49aaaa33aa5f21a224b601d1b7b0c047873a8841 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 18 Dec 2018 15:46:05 +0100 Subject: [PATCH 35/70] net/icmpv6: Switch echo request handler to new API Unlike before, we allocate a new packet for the reply which is a modified clone of the request. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.c | 148 +++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 88 deletions(-) diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index fa5b3fd39626d..d0ea6c8e7b410 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -302,110 +302,99 @@ int net_icmpv6_get_ra_hdr(struct net_pkt *pkt, struct net_icmpv6_ra_hdr *hdr) return 0; } -static enum net_verdict handle_echo_request(struct net_pkt *orig, - struct net_ipv6_hdr *ip_hdr) +static int icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code) { - struct net_icmp_hdr icmp_hdr; - struct net_pkt *pkt; - struct net_buf *frag; - struct net_if *iface; + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, + &icmp_access); + if (!icmp_hdr) { + return -ENOBUFS; + } + + icmp_hdr->type = icmp_type; + icmp_hdr->code = icmp_code; + icmp_hdr->chksum = 0; + + return net_pkt_set_data(pkt, &icmp_access); +} + +static enum net_verdict icmpv6_handle_echo_request(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr) +{ + struct net_pkt *reply = NULL; + const struct in6_addr *src; s16_t payload_len; - int ret; NET_DBG("Received Echo Request from %s to %s", log_strdup(net_sprint_ipv6_addr(&ip_hdr->src)), log_strdup(net_sprint_ipv6_addr(&ip_hdr->dst))); - iface = net_pkt_iface(orig); - payload_len = ntohs(ip_hdr->len) - - net_pkt_ipv6_ext_len(orig) - NET_ICMPH_LEN; + net_pkt_ipv6_ext_len(pkt) - NET_ICMPH_LEN; if (payload_len < NET_ICMPV6_UNUSED_LEN) { /* No identifier or sequence number present */ - goto drop_no_pkt; - } - - pkt = net_pkt_get_reserve_tx(PKT_WAIT_TIME); - if (!pkt) { - goto drop_no_pkt; + goto drop; } - frag = net_pkt_copy_all(orig, 0, PKT_WAIT_TIME); - if (!frag) { + reply = net_pkt_alloc_with_buffer(net_pkt_iface(pkt), payload_len, + AF_INET6, IPPROTO_ICMPV6, + PKT_WAIT_TIME); + if (!reply) { + NET_DBG("DROP: No buffer"); goto drop; } - net_pkt_frag_add(pkt, frag); - net_pkt_set_family(pkt, AF_INET6); - net_pkt_set_iface(pkt, iface); - net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); - - if (net_pkt_ipv6_ext_len(orig)) { - net_pkt_set_ipv6_ext_len(pkt, net_pkt_ipv6_ext_len(orig)); + if (net_ipv6_is_addr_mcast(&ip_hdr->dst)) { + src = net_if_ipv6_select_src_addr(net_pkt_iface(pkt), + &ip_hdr->dst); } else { - net_pkt_set_ipv6_ext_len(pkt, 0); + src = &ip_hdr->dst; } - /* Set up IPv6 Header fields */ - NET_IPV6_HDR(pkt)->vtc = 0x60; - NET_IPV6_HDR(pkt)->tcflow = 0; - NET_IPV6_HDR(pkt)->flow = 0; - NET_IPV6_HDR(pkt)->hop_limit = net_if_ipv6_get_hop_limit(iface); - - if (net_ipv6_is_addr_mcast(&NET_IPV6_HDR(pkt)->dst)) { - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, - &ip_hdr->src); - - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, - net_if_ipv6_select_src_addr(iface, - &ip_hdr->dst)); - } else { - struct in6_addr addr; - - net_ipaddr_copy(&addr, &ip_hdr->src); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, - &ip_hdr->dst); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &addr); - } - - net_pkt_lladdr_src(pkt)->addr = net_pkt_lladdr_dst(orig)->addr; - net_pkt_lladdr_src(pkt)->len = net_pkt_lladdr_dst(orig)->len; - /* We must not set the destination ll address here but trust * that it is set properly using a value from neighbor cache. + * Same for source as it points to original pkt ll src address. */ - net_pkt_lladdr_dst(pkt)->addr = NULL; + net_pkt_lladdr_dst(reply)->addr = NULL; + net_pkt_lladdr_src(reply)->addr = NULL; + + if (net_ipv6_create_new(reply, src, &ip_hdr->src)) { + NET_DBG("DROP: wrong buffer"); + goto drop; + } - /* ICMPv6 fields */ - ret = net_icmpv6_get_hdr(pkt, &icmp_hdr); - if (ret < 0) { + if (icmpv6_create(reply, NET_ICMPV6_ECHO_REPLY, 0) || + net_pkt_copy_new(reply, pkt, payload_len)) { + NET_DBG("DROP: wrong buffer"); goto drop; } - icmp_hdr.type = NET_ICMPV6_ECHO_REPLY; - icmp_hdr.code = 0; - icmp_hdr.chksum = 0; - net_icmpv6_set_hdr(pkt, &icmp_hdr); - net_icmpv6_set_chksum(pkt); + net_pkt_cursor_init(reply); + net_ipv6_finalize_new(reply, IPPROTO_ICMPV6); NET_DBG("Sending Echo Reply from %s to %s", - log_strdup(net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->src)), - log_strdup(net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->dst))); + log_strdup(net_sprint_ipv6_addr(src)), + log_strdup(net_sprint_ipv6_addr(&ip_hdr->src))); - if (net_send_data(pkt) < 0) { + if (net_send_data(reply) < 0) { goto drop; } - net_pkt_unref(orig); - net_stats_update_icmp_sent(iface); + net_stats_update_icmp_sent(net_pkt_iface(reply)); + + net_pkt_unref(pkt); return NET_OK; drop: - net_pkt_unref(pkt); + if (reply) { + net_pkt_unref(reply); + } -drop_no_pkt: - net_stats_update_icmp_drop(iface); + net_stats_update_icmp_drop(net_pkt_iface(pkt)); return NET_DROP; } @@ -530,25 +519,6 @@ int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, return err; } -static int icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code) -{ - NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, - struct net_icmp_hdr); - struct net_icmp_hdr *icmp_hdr; - - icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new(pkt, - &icmp_access); - if (!icmp_hdr) { - return -ENOBUFS; - } - - icmp_hdr->type = icmp_type; - icmp_hdr->code = icmp_code; - icmp_hdr->chksum = 0; - - return net_pkt_set_data(pkt, &icmp_access); -} - int net_icmpv6_send_echo_request(struct net_if *iface, struct in6_addr *dst, u16_t identifier, @@ -629,6 +599,8 @@ enum net_verdict net_icmpv6_input(struct net_pkt *pkt, goto drop; } + net_pkt_acknowledge_data(pkt, &icmp_access); + NET_DBG("ICMPv6 %s received type %d code %d", net_icmpv6_type2str(icmp_hdr->type), icmp_hdr->type, icmp_hdr->code); @@ -650,7 +622,7 @@ enum net_verdict net_icmpv6_input(struct net_pkt *pkt, static struct net_icmpv6_handler echo_request_handler = { .type = NET_ICMPV6_ECHO_REQUEST, .code = 0, - .handler = handle_echo_request, + .handler = icmpv6_handle_echo_request, }; void net_icmpv6_init(void) From 67fa056f2f73309f7b82543c7466f948685a2878 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 19 Dec 2018 13:10:40 +0100 Subject: [PATCH 36/70] net/icmpv6: Switch error message to new API Logic does not change much, besides using new create/finalize functions etc... Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.c | 157 ++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 98 deletions(-) diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index d0ea6c8e7b410..62d48cebe16c5 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -68,36 +68,6 @@ void net_icmpv6_unregister_handler(struct net_icmpv6_handler *handler) sys_slist_find_and_remove(&handlers, &handler->node); } -static inline void setup_ipv6_header(struct net_pkt *pkt, u16_t extra_len, - u8_t hop_limit, u8_t icmp_type, - u8_t icmp_code) -{ - struct net_buf *frag = pkt->frags; - const u32_t unused = 0U; - u16_t pos; - - NET_IPV6_HDR(pkt)->vtc = 0x60; - NET_IPV6_HDR(pkt)->tcflow = 0; - NET_IPV6_HDR(pkt)->flow = 0; - - NET_IPV6_HDR(pkt)->len = htons(NET_ICMPH_LEN + extra_len + - NET_ICMPV6_UNUSED_LEN); - - NET_IPV6_HDR(pkt)->nexthdr = IPPROTO_ICMPV6; - NET_IPV6_HDR(pkt)->hop_limit = hop_limit; - - net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); - - frag = net_pkt_write(pkt, frag, net_pkt_ip_hdr_len(pkt), &pos, - sizeof(icmp_type), &icmp_type, PKT_WAIT_TIME); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(icmp_code), - &icmp_code, PKT_WAIT_TIME); - - /* ICMPv6 header has 4 unused bytes that must be zero, RFC 4443 ch 3.1 - */ - net_pkt_write(pkt, frag, pos, &pos, 4, (u8_t *)&unused, PKT_WAIT_TIME); -} - int net_icmpv6_set_chksum(struct net_pkt *pkt) { u16_t chksum = 0U; @@ -402,91 +372,85 @@ static enum net_verdict icmpv6_handle_echo_request(struct net_pkt *pkt, int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, u32_t param) { - struct net_pkt *pkt; - struct net_buf *frag; - struct net_if *iface = net_pkt_iface(orig); - size_t extra_len, reserve; + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr); int err = -EIO; + struct net_ipv6_hdr *ip_hdr; + const struct in6_addr *src; + struct net_pkt *pkt; + size_t copy_len; + + net_pkt_cursor_init(orig); - if (NET_IPV6_HDR(orig)->nexthdr == IPPROTO_ICMPV6) { - struct net_icmp_hdr icmp_hdr[1]; + ip_hdr = (struct net_ipv6_hdr *)net_pkt_get_data_new(orig, + &ipv6_access); + if (!ip_hdr) { + goto drop_no_pkt; + } - if (!net_icmpv6_get_hdr(orig, icmp_hdr) || - icmp_hdr->code < 128) { + if (ip_hdr->nexthdr == IPPROTO_ICMPV6) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv6_access, + struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + + net_pkt_acknowledge_data(orig, &ipv6_access); + + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data_new( + orig, &icmpv6_access); + if (!icmp_hdr || icmp_hdr->code < 128) { /* We must not send ICMP errors back */ err = -EINVAL; goto drop_no_pkt; } - } - pkt = net_pkt_get_reserve_tx(PKT_WAIT_TIME); - if (!pkt) { - err = -ENOMEM; - goto drop_no_pkt; + net_pkt_cursor_init(orig); } - /* There is unsed part in ICMPv6 error msg header what we might need - * to store the param variable. - */ - reserve = sizeof(struct net_ipv6_hdr) + sizeof(struct net_icmp_hdr) + - NET_ICMPV6_UNUSED_LEN; - - if (NET_IPV6_HDR(orig)->nexthdr == IPPROTO_UDP) { - extra_len = sizeof(struct net_ipv6_hdr) + + if (ip_hdr->nexthdr == IPPROTO_UDP) { + copy_len = sizeof(struct net_ipv6_hdr) + sizeof(struct net_udp_hdr); - } else if (NET_IPV6_HDR(orig)->nexthdr == IPPROTO_TCP) { - extra_len = sizeof(struct net_ipv6_hdr) + + } else if (ip_hdr->nexthdr == IPPROTO_TCP) { + copy_len = sizeof(struct net_ipv6_hdr) + sizeof(struct net_tcp_hdr); - } else if (NET_IPV6_HDR(orig)->nexthdr == NET_IPV6_NEXTHDR_FRAG) { - extra_len = net_pkt_get_len(orig); } else { - size_t space = CONFIG_NET_BUF_DATA_SIZE; - - if (reserve > space) { - extra_len = 0; - } else { - extra_len = space - reserve; - } + copy_len = net_pkt_get_len(orig); } - /* We only copy minimal IPv6 + next header from original message. - * This is so that the memory pressure is minimized. - */ - frag = net_pkt_copy(orig, extra_len, reserve, PKT_WAIT_TIME); - if (!frag) { + pkt = net_pkt_alloc_with_buffer(net_pkt_iface(orig), + copy_len + NET_ICMPV6_UNUSED_LEN, + AF_INET6, IPPROTO_ICMPV6, + PKT_WAIT_TIME); + if (!pkt) { err = -ENOMEM; - goto drop; + goto drop_no_pkt; } - net_pkt_frag_add(pkt, frag); - net_pkt_set_family(pkt, AF_INET6); - net_pkt_set_iface(pkt, iface); - net_pkt_set_ipv6_ext_len(pkt, 0); + if (net_ipv6_is_addr_mcast(&ip_hdr->dst)) { + src = net_if_ipv6_select_src_addr(net_pkt_iface(pkt), + &ip_hdr->dst); + } else { + src = &ip_hdr->dst; + } - setup_ipv6_header(pkt, extra_len, net_if_ipv6_get_hop_limit(iface), - type, code); + if (net_ipv6_create_new(pkt, src, &ip_hdr->src) || + icmpv6_create(pkt, type, code)) { + goto drop; + } /* Depending on error option, we store the param into the ICMP message. */ if (type == NET_ICMPV6_PARAM_PROBLEM) { - sys_put_be32(param, (u8_t *)net_pkt_icmp_data(pkt) + - sizeof(struct net_icmp_hdr)); + err = net_pkt_write_be32_new(pkt, param); + } else { + err = net_pkt_memset(pkt, 0, NET_ICMPV6_UNUSED_LEN); } - if (net_ipv6_is_addr_mcast(&NET_IPV6_HDR(orig)->dst)) { - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, - &NET_IPV6_HDR(orig)->src); - - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, - net_if_ipv6_select_src_addr(iface, - &NET_IPV6_HDR(orig)->dst)); - } else { - struct in6_addr addr; + /* Allocator might not have been able to allocate all requested space, + * so let's copy as much as we can. + */ + copy_len = net_pkt_available_buffer(pkt); - net_ipaddr_copy(&addr, &NET_IPV6_HDR(orig)->src); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(orig)->dst); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &addr); + if (err || net_pkt_copy_new(pkt, orig, copy_len)) { + goto drop; } net_pkt_lladdr_src(pkt)->addr = net_pkt_lladdr_dst(orig)->addr; @@ -494,19 +458,16 @@ int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, net_pkt_lladdr_dst(pkt)->addr = net_pkt_lladdr_src(orig)->addr; net_pkt_lladdr_dst(pkt)->len = net_pkt_lladdr_src(orig)->len; - /* Clear and then set the chksum */ - err = net_icmpv6_set_chksum(pkt); - if (err < 0) { - goto drop; - } + net_pkt_cursor_init(pkt); + net_ipv6_finalize_new(pkt, IPPROTO_ICMPV6); NET_DBG("Sending ICMPv6 Error Message type %d code %d param %d" " from %s to %s", type, code, param, - log_strdup(net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->src)), - log_strdup(net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->dst))); + log_strdup(net_sprint_ipv6_addr(src)), + log_strdup(net_sprint_ipv6_addr(&ip_hdr->src))); if (net_send_data(pkt) >= 0) { - net_stats_update_icmp_sent(iface); + net_stats_update_icmp_sent(net_pkt_iface(pkt)); return 0; } @@ -514,7 +475,7 @@ int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, net_pkt_unref(pkt); drop_no_pkt: - net_stats_update_icmp_drop(iface); + net_stats_update_icmp_drop(net_pkt_iface(orig)); return err; } From 071ac16d4b57157f8e4300a54e19bf98506f2c7f Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 19 Dec 2018 15:30:00 +0100 Subject: [PATCH 37/70] net/context: Add support for IPv6 on the new send/sendto functions It can now use the new IPv6 function to create IPv6 header. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/net_context.c | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index c15263dd327de..b7f3032682daa 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -731,6 +731,28 @@ struct net_pkt *net_context_create_ipv6(struct net_context *context, net_context_get_iface(context), net_context_get_ip_proto(context)); } + +static int context_create_ipv6_new(struct net_context *context, + struct net_pkt *pkt, + const struct in6_addr *src, + const struct in6_addr *dst) +{ + NET_ASSERT(((struct sockaddr_in6_ptr *)&context->local)->sin6_addr); + + if (!src) { + src = ((struct sockaddr_in6_ptr *)&context->local)->sin6_addr; + } + + if (net_ipv6_is_addr_unspecified(src) + || net_ipv6_is_addr_mcast(src)) { + src = net_if_ipv6_select_src_addr(net_pkt_iface(pkt), + (struct in6_addr *)dst); + } + + return net_ipv6_create_new(pkt, src, dst); +} +#else +#define context_create_ipv6_new(...) -1 #endif /* CONFIG_NET_IPV6 */ int net_context_connect(struct net_context *context, @@ -1244,6 +1266,14 @@ static int context_setup_udp_packet(struct net_context *context, ret = context_create_ipv4_new(context, pkt, NULL, &addr4->sin_addr); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_context_get_family(context) == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)dst_addr; + + dst_port = addr6->sin6_port; + + ret = context_create_ipv6_new(context, pkt, + NULL, &addr6->sin6_addr); } if (ret < 0) { @@ -1289,6 +1319,10 @@ static void context_finalize_packet(struct net_context *context, net_context_get_family(context) == AF_INET) { net_ipv4_finalize_new(pkt, net_context_get_ip_proto(context)); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_context_get_family(context) == AF_INET6) { + net_ipv6_finalize_new(pkt, + net_context_get_ip_proto(context)); } } @@ -1333,7 +1367,15 @@ static int context_sendto_new(struct net_context *context, } } else if (IS_ENABLED(CONFIG_NET_IPV6) && net_context_get_family(context) == AF_INET6) { - return -ENOTSUP; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)dst_addr; + + if (addrlen < sizeof(struct sockaddr_in6)) { + return -EINVAL; + } + + if (net_ipv6_is_addr_unspecified(&addr6->sin6_addr)) { + return -EDESTADDRREQ; + } } else { NET_DBG("Invalid protocol family %d", net_context_get_family(context)); From 49d8bdd2da9809565830c788944c7f4e86b4b9a3 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 10:32:24 +0100 Subject: [PATCH 38/70] net/icmpv6: Make header creation function public This will be used in ipv6_nbr, ipv6_mld and so on... Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.c | 8 ++++---- subsys/net/ip/icmpv6.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index 62d48cebe16c5..a27ba333debcb 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -272,7 +272,7 @@ int net_icmpv6_get_ra_hdr(struct net_pkt *pkt, struct net_icmpv6_ra_hdr *hdr) return 0; } -static int icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code) +int net_icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, struct net_icmp_hdr); @@ -336,7 +336,7 @@ static enum net_verdict icmpv6_handle_echo_request(struct net_pkt *pkt, goto drop; } - if (icmpv6_create(reply, NET_ICMPV6_ECHO_REPLY, 0) || + if (net_icmpv6_create(reply, NET_ICMPV6_ECHO_REPLY, 0) || net_pkt_copy_new(reply, pkt, payload_len)) { NET_DBG("DROP: wrong buffer"); goto drop; @@ -432,7 +432,7 @@ int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, } if (net_ipv6_create_new(pkt, src, &ip_hdr->src) || - icmpv6_create(pkt, type, code)) { + net_icmpv6_create(pkt, type, code)) { goto drop; } @@ -503,7 +503,7 @@ int net_icmpv6_send_echo_request(struct net_if *iface, } if (net_ipv6_create_new(pkt, src, dst) || - icmpv6_create(pkt, NET_ICMPV6_ECHO_REQUEST, 0)) { + net_icmpv6_create(pkt, NET_ICMPV6_ECHO_REQUEST, 0)) { goto drop; } diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index 15b4dec35a433..ca951f8df7874 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -184,6 +184,7 @@ int net_icmpv6_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); int net_icmpv6_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); int net_icmpv6_set_chksum(struct net_pkt *pkt); +int net_icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code); int net_icmpv6_finalize(struct net_pkt *pkt); int net_icmpv6_get_ns_hdr(struct net_pkt *pkt, struct net_icmpv6_ns_hdr *hdr); From b5f140afa436d14d5e0b4cdd42639c9828d7ddfd Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 10:33:35 +0100 Subject: [PATCH 39/70] net/ipv6: Switch NA msg sending to new net_pkt API And let's use net_ipv6_create, net_icmpv6_create, net_ipv6_finalize to factorize the code better. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6_nbr.c | 106 +++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index c1b655da47550..50e7ae3d33912 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -915,6 +915,25 @@ static inline u8_t get_llao_len(struct net_if *iface) return 0; } +static inline bool set_llao_new(struct net_pkt *pkt, + struct net_linkaddr *lladdr, + u8_t llao_len, u8_t type) +{ + struct net_icmpv6_nd_opt_hdr opt_hdr = { + .type = type, + .len = llao_len >> 3, + }; + + if (net_pkt_write_new(pkt, &opt_hdr, + sizeof(struct net_icmpv6_nd_opt_hdr)) || + net_pkt_write_new(pkt, lladdr->addr, lladdr->len) || + net_pkt_memset(pkt, 0, llao_len - lladdr->len - 2)) { + return false; + } + + return true; +} + static inline void set_llao(struct net_linkaddr *lladdr, u8_t *llao, u8_t llao_len, u8_t type) { @@ -985,81 +1004,72 @@ int net_ipv6_send_na(struct net_if *iface, const struct in6_addr *src, const struct in6_addr *dst, const struct in6_addr *tgt, u8_t flags) { - struct net_icmpv6_na_hdr na_hdr; + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(na_access, + struct net_icmpv6_na_hdr); + int ret = -ENOBUFS; + struct net_icmpv6_na_hdr *na_hdr; struct net_pkt *pkt; - struct net_buf *frag; u8_t llao_len; - int ret; - pkt = net_pkt_get_reserve_tx(ND_NET_BUF_TIMEOUT); - if (!pkt) { - return -ENOMEM; - } + llao_len = get_llao_len(iface); - frag = net_pkt_get_frag(pkt, ND_NET_BUF_TIMEOUT); - if (!frag) { - net_pkt_unref(pkt); + pkt = net_pkt_alloc_with_buffer(iface, + sizeof(struct net_icmpv6_na_hdr) + + llao_len, + AF_INET6, IPPROTO_ICMPV6, + ND_NET_BUF_TIMEOUT); + if (!pkt) { return -ENOMEM; } - net_pkt_frag_add(pkt, frag); - - net_pkt_set_iface(pkt, iface); - net_pkt_set_family(pkt, AF_INET6); - net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); + net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_ND_HOP_LIMIT); - llao_len = get_llao_len(iface); - - net_pkt_set_ipv6_ext_len(pkt, 0); - - setup_headers(pkt, sizeof(struct net_icmpv6_na_hdr) + llao_len, - NET_ICMPV6_NA); + if (net_ipv6_create_new(pkt, src, dst) || + net_icmpv6_create(pkt, NET_ICMPV6_NA, 0)) { + goto drop; + } - net_buf_add(frag, sizeof(struct net_icmpv6_na_hdr) + llao_len); + na_hdr = (struct net_icmpv6_na_hdr *)net_pkt_get_data_new(pkt, + &na_access); + if (!na_hdr) { + goto drop; + } - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, src); - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, dst); - net_ipaddr_copy(&na_hdr.tgt, tgt); + /* Let's make sure reserved part is full of 0 */ + memset(na_hdr, 0, sizeof(struct net_icmpv6_na_hdr)); - set_llao(net_if_get_link_addr(net_pkt_iface(pkt)), - (u8_t *)net_pkt_icmp_data(pkt) + sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_na_hdr), - llao_len, NET_ICMPV6_ND_OPT_TLLAO); + na_hdr->flags = flags; + net_ipaddr_copy(&na_hdr->tgt, tgt); - na_hdr.flags = flags; - ret = net_icmpv6_set_na_hdr(pkt, &na_hdr); - if (ret < 0) { - net_pkt_unref(pkt); - return ret; + if (net_pkt_set_data(pkt, &na_access)) { + goto drop; } - pkt->frags->len = NET_IPV6ICMPH_LEN + - sizeof(struct net_icmpv6_na_hdr) + llao_len; - - ret = net_icmpv6_set_chksum(pkt); - if (ret < 0) { - net_pkt_unref(pkt); - return ret; + if (!set_llao_new(pkt, net_if_get_link_addr(iface), + llao_len, NET_ICMPV6_ND_OPT_TLLAO)) { + goto drop; } - dbg_addr_sent_tgt("Neighbor Advertisement", - &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst, - &na_hdr.tgt); + net_pkt_cursor_init(pkt); + net_ipv6_finalize_new(pkt, IPPROTO_ICMPV6); + + dbg_addr_sent_tgt("Neighbor Advertisement", src, dst, &na_hdr->tgt); if (net_send_data(pkt) < 0) { + net_stats_update_ipv6_nd_drop(iface); + ret = -EINVAL; + goto drop; } - net_stats_update_ipv6_nd_sent(net_pkt_iface(pkt)); + net_stats_update_ipv6_nd_sent(iface); return 0; drop: - net_stats_update_ipv6_nd_drop(net_pkt_iface(pkt)); net_pkt_unref(pkt); - return -EINVAL; + return ret; } static void ns_routing_info(struct net_pkt *pkt, From b3aa0941e4d68069737f51db6dc15c958c73f0ec Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 11:08:14 +0100 Subject: [PATCH 40/70] net/ipv6: Switch NS msg sending to new net_pkt API And let's use net_ipv6_create, net_icmpv6_create, net_ipv6_finalize to factorize the code better. De-clutter the code by reordering where src/dst are evaluated. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6.h | 4 +- subsys/net/ip/ipv6_nbr.c | 152 ++++++++++++++++++--------------------- 2 files changed, 71 insertions(+), 85 deletions(-) diff --git a/subsys/net/ip/ipv6.h b/subsys/net/ip/ipv6.h index 9e8d4855b282e..2734e1630b118 100644 --- a/subsys/net/ip/ipv6.h +++ b/subsys/net/ip/ipv6.h @@ -118,8 +118,8 @@ int net_ipv6_start_dad(struct net_if *iface, struct net_if_addr *ifaddr); #endif int net_ipv6_send_ns(struct net_if *iface, struct net_pkt *pending, - struct in6_addr *src, struct in6_addr *dst, - struct in6_addr *tgt, bool is_my_address); + const struct in6_addr *src, const struct in6_addr *dst, + const struct in6_addr *tgt, bool is_my_address); int net_ipv6_send_rs(struct net_if *iface); int net_ipv6_start_rs(struct net_if *iface); diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 50e7ae3d33912..ebb411a43493e 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1795,110 +1795,92 @@ static enum net_verdict handle_na_input(struct net_pkt *pkt, int net_ipv6_send_ns(struct net_if *iface, struct net_pkt *pending, - struct in6_addr *src, - struct in6_addr *dst, - struct in6_addr *tgt, + const struct in6_addr *src, + const struct in6_addr *dst, + const struct in6_addr *tgt, bool is_my_address) { - struct net_icmpv6_ns_hdr ns_hdr; - struct net_pkt *pkt; - struct net_buf *frag; + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ns_access, + struct net_icmpv6_ns_hdr); + struct net_pkt *pkt = NULL; + int ret = -ENOBUFS; + struct net_icmpv6_ns_hdr *ns_hdr; + struct in6_addr node_dst; struct net_nbr *nbr; u8_t llao_len; - int ret; - pkt = net_pkt_get_reserve_tx(ND_NET_BUF_TIMEOUT); - if (!pkt) { - return -ENOMEM; + if (!dst) { + net_ipv6_addr_create_solicited_node(tgt, &node_dst); + dst = &node_dst; } - frag = net_pkt_get_frag(pkt, ND_NET_BUF_TIMEOUT); - if (!frag) { - net_pkt_unref(pkt); - return -ENOMEM; - } + llao_len = get_llao_len(iface); - net_pkt_frag_add(pkt, frag); + if (is_my_address) { + src = net_ipv6_unspecified_address(); + llao_len = 0; + } else { + if (!src) { + src = net_if_ipv6_select_src_addr(iface, dst); + } - net_pkt_set_iface(pkt, iface); - net_pkt_set_family(pkt, AF_INET6); - net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); - net_pkt_set_ipv6_ext_len(pkt, 0); + if (net_ipv6_is_addr_unspecified(src)) { + NET_DBG("No source address for NS"); + ret = -EINVAL; - llao_len = get_llao_len(net_pkt_iface(pkt)); + goto drop; + } + } - setup_headers(pkt, sizeof(struct net_icmpv6_ns_hdr) + llao_len, - NET_ICMPV6_NS); + pkt = net_pkt_alloc_with_buffer(iface, + sizeof(struct net_icmpv6_ns_hdr) + + llao_len, + AF_INET6, IPPROTO_ICMPV6, + ND_NET_BUF_TIMEOUT); + if (!pkt) { + ret = -ENOMEM; + goto drop; + } - net_buf_add(frag, sizeof(struct net_icmpv6_ns_hdr)); + net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_ND_HOP_LIMIT); - if (!dst) { - net_ipv6_addr_create_solicited_node(tgt, - &NET_IPV6_HDR(pkt)->dst); - } else { - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, dst); + if (net_ipv6_create_new(pkt, src, dst) || + net_icmpv6_create(pkt, NET_ICMPV6_NS, 0)) { + goto drop; } - net_ipaddr_copy(&ns_hdr.tgt, tgt); - ret = net_icmpv6_set_ns_hdr(pkt, &ns_hdr); - if (ret < 0) { - net_pkt_unref(pkt); - return ret; + ns_hdr = (struct net_icmpv6_ns_hdr *)net_pkt_get_data_new(pkt, + &ns_access); + if (!ns_hdr) { + goto drop; } - if (is_my_address) { - u16_t len = ntohs(NET_IPV6_HDR(pkt)->len); - /* DAD */ - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, - net_ipv6_unspecified_address()); - NET_IPV6_HDR(pkt)->len = htons(len - llao_len); - } else { - if (src) { - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, src); - } else { - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, - net_if_ipv6_select_src_addr( - net_pkt_iface(pkt), - &NET_IPV6_HDR(pkt)->dst)); - } + ns_hdr->reserved = 0; + net_ipaddr_copy(&ns_hdr->tgt, tgt); - if (net_ipv6_is_addr_unspecified(&NET_IPV6_HDR(pkt)->src)) { - NET_DBG("No source address for NS"); - if (pending) { - net_pkt_unref(pending); - } + if (net_pkt_set_data(pkt, &ns_access)) { + goto drop; + } + if (!is_my_address) { + if (!set_llao_new(pkt, net_if_get_link_addr(iface), + llao_len, NET_ICMPV6_ND_OPT_SLLAO)) { goto drop; } - - net_buf_add(frag, llao_len); - - set_llao(net_if_get_link_addr(net_pkt_iface(pkt)), - (u8_t *)net_pkt_icmp_data(pkt) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_ns_hdr), - llao_len, NET_ICMPV6_ND_OPT_SLLAO); } - ret = net_icmpv6_set_chksum(pkt); - if (ret < 0) { - net_pkt_unref(pkt); - return ret; - } + net_pkt_cursor_init(pkt); + net_ipv6_finalize_new(pkt, IPPROTO_ICMPV6); - nbr = nbr_lookup(&net_neighbor.table, net_pkt_iface(pkt), &ns_hdr.tgt); + nbr = nbr_lookup(&net_neighbor.table, iface, &ns_hdr->tgt); if (!nbr) { nbr_print(); - nbr = nbr_new(net_pkt_iface(pkt), &ns_hdr.tgt, false, + nbr = nbr_new(iface, &ns_hdr->tgt, false, NET_IPV6_NBR_STATE_INCOMPLETE); if (!nbr) { NET_DBG("Could not create new neighbor %s", - log_strdup(net_sprint_ipv6_addr(&ns_hdr.tgt))); - if (pending) { - net_pkt_unref(pending); - } - + log_strdup(net_sprint_ipv6_addr(&ns_hdr->tgt))); goto drop; } } @@ -1910,7 +1892,6 @@ int net_ipv6_send_ns(struct net_if *iface, NET_DBG("Packet %p already pending for " "operation. Discarding pending %p and pkt %p", net_ipv6_nbr_data(nbr)->pending, pending, pkt); - net_pkt_unref(pending); goto drop; } @@ -1925,30 +1906,35 @@ int net_ipv6_send_ns(struct net_if *iface, } } - dbg_addr_sent_tgt("Neighbor Solicitation", - &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst, - &ns_hdr.tgt); + dbg_addr_sent_tgt("Neighbor Solicitation", src, dst, &ns_hdr->tgt); if (net_send_data(pkt) < 0) { NET_DBG("Cannot send NS %p (pending %p)", pkt, pending); if (pending) { nbr_clear_ns_pending(net_ipv6_nbr_data(nbr)); + pending = NULL; } goto drop; } - net_stats_update_ipv6_nd_sent(net_pkt_iface(pkt)); + net_stats_update_ipv6_nd_sent(iface); return 0; drop: - net_stats_update_ipv6_nd_drop(net_pkt_iface(pkt)); - net_pkt_unref(pkt); + if (pending) { + net_pkt_unref(pending); + } - return -EINVAL; + if (pkt) { + net_pkt_unref(pkt); + } + + net_stats_update_ipv6_nd_drop(iface); + + return ret; } #endif /* CONFIG_NET_IPV6_NBR_CACHE */ From d2dba81cfc92f7854a2f2623470bdca9a4f7556c Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 11:24:13 +0100 Subject: [PATCH 41/70] net/ipv6: Switch RS msg sending to new net_pkt API And let's use net_ipv6_create, net_icmpv6_create, net_ipv6_finalize to factorize the code better. Removing useless setup_headers private function now. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6_nbr.c | 129 ++++++++++++--------------------------- 1 file changed, 40 insertions(+), 89 deletions(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index ebb411a43493e..370a264d9801c 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -915,9 +915,9 @@ static inline u8_t get_llao_len(struct net_if *iface) return 0; } -static inline bool set_llao_new(struct net_pkt *pkt, - struct net_linkaddr *lladdr, - u8_t llao_len, u8_t type) +static inline bool set_llao(struct net_pkt *pkt, + struct net_linkaddr *lladdr, + u8_t llao_len, u8_t type) { struct net_icmpv6_nd_opt_hdr opt_hdr = { .type = type, @@ -934,40 +934,6 @@ static inline bool set_llao_new(struct net_pkt *pkt, return true; } -static inline void set_llao(struct net_linkaddr *lladdr, - u8_t *llao, u8_t llao_len, u8_t type) -{ - llao[NET_ICMPV6_OPT_TYPE_OFFSET] = type; - llao[NET_ICMPV6_OPT_LEN_OFFSET] = llao_len >> 3; - - memcpy(&llao[NET_ICMPV6_OPT_DATA_OFFSET], lladdr->addr, lladdr->len); - - (void)memset(&llao[NET_ICMPV6_OPT_DATA_OFFSET + lladdr->len], 0, - llao_len - lladdr->len - 2); -} - -static void setup_headers(struct net_pkt *pkt, u8_t nd6_len, - u8_t icmp_type) -{ - net_buf_add(pkt->frags, - sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr)); - - NET_IPV6_HDR(pkt)->vtc = 0x60; - NET_IPV6_HDR(pkt)->tcflow = 0; - NET_IPV6_HDR(pkt)->flow = 0; - NET_IPV6_HDR(pkt)->len = htons(NET_ICMPH_LEN + nd6_len); - - NET_IPV6_HDR(pkt)->nexthdr = IPPROTO_ICMPV6; - NET_IPV6_HDR(pkt)->hop_limit = NET_IPV6_ND_HOP_LIMIT; - - /* In this special case where we know there are no long extension - * headers, so we can use this header cast. - */ - net_pkt_icmp_data(pkt)->type = icmp_type; - net_pkt_icmp_data(pkt)->code = 0; -} - static inline struct net_nbr *handle_ns_neighbor(struct net_pkt *pkt, u8_t ll_len, u16_t sllao_offset) @@ -1045,8 +1011,8 @@ int net_ipv6_send_na(struct net_if *iface, const struct in6_addr *src, goto drop; } - if (!set_llao_new(pkt, net_if_get_link_addr(iface), - llao_len, NET_ICMPV6_ND_OPT_TLLAO)) { + if (!set_llao(pkt, net_if_get_link_addr(iface), + llao_len, NET_ICMPV6_ND_OPT_TLLAO)) { goto drop; } @@ -1863,8 +1829,8 @@ int net_ipv6_send_ns(struct net_if *iface, } if (!is_my_address) { - if (!set_llao_new(pkt, net_if_get_link_addr(iface), - llao_len, NET_ICMPV6_ND_OPT_SLLAO)) { + if (!set_llao(pkt, net_if_get_link_addr(iface), + llao_len, NET_ICMPV6_ND_OPT_SLLAO)) { goto drop; } } @@ -1941,78 +1907,63 @@ int net_ipv6_send_ns(struct net_if *iface, #if defined(CONFIG_NET_IPV6_ND) int net_ipv6_send_rs(struct net_if *iface) { - struct net_pkt *pkt; - struct net_buf *frag; - bool unspec_src; u8_t llao_len = 0U; - int ret; + int ret = -ENOBUFS; + const struct in6_addr *src; + struct in6_addr dst; + struct net_pkt *pkt; - pkt = net_pkt_get_reserve_tx(ND_NET_BUF_TIMEOUT); - if (!pkt) { - return -ENOMEM; + net_ipv6_addr_create_ll_allnodes_mcast(&dst); + src = net_if_ipv6_select_src_addr(iface, &dst); + + if (!net_ipv6_is_addr_unspecified(src)) { + llao_len = get_llao_len(iface); } - frag = net_pkt_get_frag(pkt, ND_NET_BUF_TIMEOUT); - if (!frag) { - net_pkt_unref(pkt); + pkt = net_pkt_alloc_with_buffer(iface, + sizeof(struct net_icmpv6_rs_hdr) + + llao_len, + AF_INET6, IPPROTO_ICMPV6, + ND_NET_BUF_TIMEOUT); + if (!pkt) { return -ENOMEM; } - net_pkt_frag_add(pkt, frag); - - net_pkt_set_iface(pkt, iface); - net_pkt_set_family(pkt, AF_INET6); - net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); - - net_ipv6_addr_create_ll_allnodes_mcast(&NET_IPV6_HDR(pkt)->dst); - - net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, - net_if_ipv6_select_src_addr(iface, - &NET_IPV6_HDR(pkt)->dst)); + net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_ND_HOP_LIMIT); - unspec_src = net_ipv6_is_addr_unspecified(&NET_IPV6_HDR(pkt)->src); - if (!unspec_src) { - llao_len = get_llao_len(net_pkt_iface(pkt)); + if (net_ipv6_create_new(pkt, src, &dst) || + net_icmpv6_create(pkt, NET_ICMPV6_RS, 0) || + net_pkt_memset(pkt, 0, sizeof(struct net_icmpv6_rs_hdr))) { + goto drop; } - setup_headers(pkt, sizeof(struct net_icmpv6_rs_hdr) + llao_len, - NET_ICMPV6_RS); - - net_buf_add(frag, sizeof(struct net_icmpv6_rs_hdr)); - - if (!unspec_src) { - net_buf_add(frag, llao_len); - - set_llao(net_if_get_link_addr(net_pkt_iface(pkt)), - (u8_t *)net_pkt_icmp_data(pkt) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_rs_hdr), - llao_len, NET_ICMPV6_ND_OPT_SLLAO); + if (llao_len > 0) { + if (!set_llao(pkt, net_if_get_link_addr(iface), + llao_len, NET_ICMPV6_ND_OPT_SLLAO)) { + goto drop; + } } - ret = net_icmpv6_set_chksum(pkt); - if (ret < 0) { - net_pkt_unref(pkt); - return ret; - } + net_pkt_cursor_init(pkt); + net_ipv6_finalize_new(pkt, IPPROTO_ICMPV6); - dbg_addr_sent("Router Solicitation", - &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst); + dbg_addr_sent("Router Solicitation", src, &dst); if (net_send_data(pkt) < 0) { + net_stats_update_ipv6_nd_drop(iface); + ret = -EINVAL; + goto drop; } - net_stats_update_ipv6_nd_sent(net_pkt_iface(pkt)); + net_stats_update_ipv6_nd_sent(iface); return 0; drop: - net_stats_update_ipv6_nd_drop(net_pkt_iface(pkt)); net_pkt_unref(pkt); - return -EINVAL; + return ret; } int net_ipv6_start_rs(struct net_if *iface) From d7d344e3ef35c270227c51b04df10191e82ce745 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 12:47:20 +0100 Subject: [PATCH 42/70] net/ipv6: Removing useless macros in nbr code append/append_all are unused anywhere. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6_nbr.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 370a264d9801c..8224739c5c411 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -2479,24 +2479,6 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt, } #endif /* CONFIG_NET_IPV6_ND */ -#define append(pkt, type, value) \ - do { \ - if (!net_pkt_append_##type##_timeout(pkt, value, \ - NET_BUF_TIMEOUT)) { \ - ret = -ENOMEM; \ - goto drop; \ - } \ - } while (0) - -#define append_all(pkt, size, value) \ - do { \ - if (!net_pkt_append_all(pkt, size, value, \ - NET_BUF_TIMEOUT)) { \ - ret = -ENOMEM; \ - goto drop; \ - } \ - } while (0) - #if defined(CONFIG_NET_IPV6_NBR_CACHE) static struct net_icmpv6_handler ns_input_handler = { .type = NET_ICMPV6_NS, From 103f453fd590b227252e8f8edb71c48b15727ffd Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 12:59:56 +0100 Subject: [PATCH 43/70] net/icmpv6: Improve callback signature to pass icmp header In nbr part, this is a useful information. Since net_icmpv6_input has already parsed the icmpv6 header, let's get pass it, instead of retrieving/parsing it again in various handler functions. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.c | 10 +++++++--- subsys/net/ip/icmpv6.h | 3 ++- subsys/net/ip/ipv6_mld.c | 3 ++- subsys/net/ip/ipv6_nbr.c | 9 ++++++--- subsys/net/ip/net_shell.c | 8 ++++++-- tests/net/icmpv6/src/main.c | 3 ++- tests/net/mld/src/main.c | 3 ++- 7 files changed, 27 insertions(+), 12 deletions(-) diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index a27ba333debcb..ce6a065e86ebd 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -291,13 +291,17 @@ int net_icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code) return net_pkt_set_data(pkt, &icmp_access); } -static enum net_verdict icmpv6_handle_echo_request(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr) +static +enum net_verdict icmpv6_handle_echo_request(struct net_pkt *pkt, + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr) { struct net_pkt *reply = NULL; const struct in6_addr *src; s16_t payload_len; + ARG_UNUSED(icmp_hdr); + NET_DBG("Received Echo Request from %s to %s", log_strdup(net_sprint_ipv6_addr(&ip_hdr->src)), log_strdup(net_sprint_ipv6_addr(&ip_hdr->dst))); @@ -571,7 +575,7 @@ enum net_verdict net_icmpv6_input(struct net_pkt *pkt, SYS_SLIST_FOR_EACH_CONTAINER(&handlers, cb, node) { if (cb->type == icmp_hdr->type && (cb->code == icmp_hdr->code || cb->code == 0)) { - return cb->handler(pkt, ip_hdr); + return cb->handler(pkt, ip_hdr, icmp_hdr); } } drop: diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index ca951f8df7874..0b7096b003dbe 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -134,7 +134,8 @@ struct net_icmpv6_echo_req { typedef enum net_verdict (*icmpv6_callback_handler_t)( struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr); + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr); const char *net_icmpv6_type2str(int icmpv6_type); diff --git a/subsys/net/ip/ipv6_mld.c b/subsys/net/ip/ipv6_mld.c index ebb19c57814ea..204788d63ea4e 100644 --- a/subsys/net/ip/ipv6_mld.c +++ b/subsys/net/ip/ipv6_mld.c @@ -299,7 +299,8 @@ static void send_mld_report(struct net_if *iface) dbg_addr("Received", pkt_str, src, dst) static enum net_verdict handle_mld_query(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr) + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr) { u16_t total_len = net_pkt_get_len(pkt); struct in6_addr mcast; diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 8224739c5c411..3f92348d60329 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1062,7 +1062,8 @@ static void ns_routing_info(struct net_pkt *pkt, } static enum net_verdict handle_ns_input(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr) + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr) { u16_t total_len = net_pkt_get_len(pkt); u8_t prev_opt_len = 0U; @@ -1650,7 +1651,8 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, } static enum net_verdict handle_na_input(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr) + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr) { u16_t total_len = net_pkt_get_len(pkt); u16_t tllao_offset = 0U; @@ -2268,7 +2270,8 @@ static inline struct net_buf *handle_ra_6co(struct net_pkt *pkt, #endif static enum net_verdict handle_ra_input(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr) + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr) { u16_t total_len = net_pkt_get_len(pkt); struct net_nbr *nbr = NULL; diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index 176330ea7bd9c..abc0a9c53bee6 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -2742,7 +2742,8 @@ static const struct shell *shell_for_ping; #if defined(CONFIG_NET_IPV6) static enum net_verdict _handle_ipv6_echo_reply(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr); + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr); static struct net_icmpv6_handler ping6_handler = { .type = NET_ICMPV6_ECHO_REPLY, @@ -2756,8 +2757,11 @@ static inline void _remove_ipv6_ping_handler(void) } static enum net_verdict _handle_ipv6_echo_reply(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr) + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr) { + ARG_UNUSED(icmp_hdr); + PR_SHELL(shell_for_ping, "Received echo reply from %s to %s\n", net_sprint_ipv6_addr(&ip_hdr->src), net_sprint_ipv6_addr(&ip_hdr->dst)); diff --git a/tests/net/icmpv6/src/main.c b/tests/net/icmpv6/src/main.c index a671b6259b1d5..9e3306b3eb220 100644 --- a/tests/net/icmpv6/src/main.c +++ b/tests/net/icmpv6/src/main.c @@ -61,7 +61,8 @@ NET_PKT_TX_SLAB_DEFINE(pkts_slab, 2); NET_BUF_POOL_DEFINE(data_pool, 2, 128, 0, NULL); static enum net_verdict handle_test_msg(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr) + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr) { struct net_buf *last = net_buf_frag_last(pkt->frags); enum net_verdict ret; diff --git a/tests/net/mld/src/main.c b/tests/net/mld/src/main.c index 68f580cac7166..a0812e787d767 100644 --- a/tests/net/mld/src/main.c +++ b/tests/net/mld/src/main.c @@ -368,7 +368,8 @@ static void send_query(struct net_if *iface) /* We are not really interested to parse the query at this point */ static enum net_verdict handle_mld_query(struct net_pkt *pkt, - struct net_ipv6_hdr *ip_hdr) + struct net_ipv6_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr) { is_query_received = true; From dcf80348e36f74aefd01bf54cf0e76d39d633b0d Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 13:30:25 +0100 Subject: [PATCH 44/70] net/ipv6: Switch NA msg handler to new net_pkt API Reworking the logic to reduce the amount of variables. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6_nbr.c | 164 ++++++++++++++------------------------- 1 file changed, 60 insertions(+), 104 deletions(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 3f92348d60329..cab649303af64 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -118,48 +118,6 @@ static void ipv6_nbr_set_state(struct net_nbr *nbr, net_ipv6_nbr_data(nbr)->state = new_state; } -static inline bool net_is_solicited(struct net_pkt *pkt) -{ - struct net_icmpv6_na_hdr na_hdr; - int ret; - - ret = net_icmpv6_get_na_hdr(pkt, &na_hdr); - if (ret < 0) { - NET_ERR("could not get na_hdr"); - return false; - } - - return na_hdr.flags & NET_ICMPV6_NA_FLAG_SOLICITED; -} - -static inline bool net_is_router(struct net_pkt *pkt) -{ - struct net_icmpv6_na_hdr na_hdr; - int ret; - - ret = net_icmpv6_get_na_hdr(pkt, &na_hdr); - if (ret < 0) { - NET_ERR("could not get na_hdr"); - return false; - } - - return na_hdr.flags & NET_ICMPV6_NA_FLAG_ROUTER; -} - -static inline bool net_is_override(struct net_pkt *pkt) -{ - struct net_icmpv6_na_hdr na_hdr; - int ret; - - ret = net_icmpv6_get_na_hdr(pkt, &na_hdr); - if (ret < 0) { - NET_ERR("could not get na_hdr"); - return false; - } - - return na_hdr.flags & NET_ICMPV6_NA_FLAG_OVERRIDE; -} - static inline struct net_nbr *get_nbr(int idx) { return &net_neighbor_pool[idx].nbr; @@ -1477,16 +1435,13 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, struct net_icmpv6_na_hdr *na_hdr, u16_t tllao_offset) { - bool lladdr_changed = false; - struct net_nbr *nbr; struct net_linkaddr_storage lladdr = { 0 }; + bool lladdr_changed = false; struct net_linkaddr_storage *cached_lladdr; struct net_pkt *pending; - struct net_buf *frag; - u16_t pos; + struct net_nbr *nbr; - nbr = nbr_lookup(&net_neighbor.table, net_pkt_iface(pkt), - &na_hdr->tgt); + nbr = nbr_lookup(&net_neighbor.table, net_pkt_iface(pkt), &na_hdr->tgt); NET_DBG("Neighbor lookup %p iface %p addr %s", nbr, net_pkt_iface(pkt), @@ -1502,9 +1457,10 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, if (tllao_offset) { lladdr.len = net_if_get_link_addr(net_pkt_iface(pkt))->len; - frag = net_frag_read(pkt->frags, tllao_offset, - &pos, lladdr.len, lladdr.addr); - if (!frag && pos == 0xffff) { + net_pkt_cursor_init(pkt); + + if (net_pkt_skip(pkt, tllao_offset) || + net_pkt_read_new(pkt, lladdr.addr, lladdr.len)) { return false; } } @@ -1559,7 +1515,7 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, cached_lladdr->len); } - if (net_is_solicited(pkt)) { + if (na_hdr->flags & NET_ICMPV6_NA_FLAG_SOLICITED) { ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_REACHABLE); net_ipv6_nbr_data(nbr)->ns_count = 0U; @@ -1573,7 +1529,8 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_STALE); } - net_ipv6_nbr_data(nbr)->is_router = net_is_router(pkt); + net_ipv6_nbr_data(nbr)->is_router = + (na_hdr->flags & NET_ICMPV6_NA_FLAG_ROUTER); goto send_pending; } @@ -1581,7 +1538,7 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, /* We do not update the address if override bit is not set * and we have a valid address in the cache. */ - if (!net_is_override(pkt) && lladdr_changed) { + if (!(na_hdr->flags & NET_ICMPV6_NA_FLAG_OVERRIDE) && lladdr_changed) { if (net_ipv6_nbr_data(nbr)->state == NET_IPV6_NBR_STATE_REACHABLE) { ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_STALE); @@ -1590,8 +1547,9 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, return false; } - if (net_is_override(pkt) || - (!net_is_override(pkt) && tllao_offset && !lladdr_changed)) { + if (na_hdr->flags & NET_ICMPV6_NA_FLAG_OVERRIDE || + (!(na_hdr->flags & NET_ICMPV6_NA_FLAG_OVERRIDE) && + tllao_offset && !lladdr_changed)) { if (lladdr_changed) { dbg_update_neighbor_lladdr_raw( @@ -1601,7 +1559,7 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, cached_lladdr->len); } - if (net_is_solicited(pkt)) { + if (na_hdr->flags & NET_ICMPV6_NA_FLAG_SOLICITED) { ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_REACHABLE); /* We might have active timer from PROBE */ @@ -1618,23 +1576,22 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, } } - if (net_ipv6_nbr_data(nbr)->is_router && !net_is_router(pkt)) { + if (net_ipv6_nbr_data(nbr)->is_router && + !(na_hdr->flags & NET_ICMPV6_NA_FLAG_ROUTER)) { /* Update the routing if the peer is no longer * a router. */ /* FIXME */ } - net_ipv6_nbr_data(nbr)->is_router = net_is_router(pkt); + net_ipv6_nbr_data(nbr)->is_router = + (na_hdr->flags & NET_ICMPV6_NA_FLAG_ROUTER); send_pending: /* Next send any pending messages to the peer. */ pending = net_ipv6_nbr_data(nbr)->pending; - if (pending) { - NET_DBG("Sending pending %p to %s lladdr %s", pending, - log_strdup(net_sprint_ipv6_addr( - &NET_IPV6_HDR(pending)->dst)), + NET_DBG("Sending pending %p to lladdr %s", pending, log_strdup(net_sprint_ll_addr(cached_lladdr->addr, cached_lladdr->len))); @@ -1654,55 +1611,52 @@ static enum net_verdict handle_na_input(struct net_pkt *pkt, struct net_ipv6_hdr *ip_hdr, struct net_icmp_hdr *icmp_hdr) { - u16_t total_len = net_pkt_get_len(pkt); + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(na_access, + struct net_icmpv6_na_hdr); + NET_PKT_DATA_ACCESS_DEFINE(nd_access, struct net_icmpv6_nd_opt_hdr); + u16_t length = net_pkt_get_len(pkt); u16_t tllao_offset = 0U; - u8_t prev_opt_len = 0U; - struct net_icmpv6_nd_opt_hdr nd_opt_hdr; - struct net_icmpv6_na_hdr na_hdr; + struct net_icmpv6_nd_opt_hdr *nd_opt_hdr; + struct net_icmpv6_na_hdr *na_hdr; struct net_if_addr *ifaddr; - size_t left_len; - int ret; - ret = net_icmpv6_get_na_hdr(pkt, &na_hdr); - if (ret < 0) { - NET_ERR("NULL NA header - dropping"); + na_hdr = (struct net_icmpv6_na_hdr *)net_pkt_get_data_new(pkt, + &na_access); + if (!na_hdr) { + NET_ERR("DROP: NULL NA header"); goto drop; } dbg_addr_recv_tgt("Neighbor Advertisement", - &ip_hdr->src, &ip_hdr->dst, &na_hdr.tgt); + &ip_hdr->src, &ip_hdr->dst, &na_hdr->tgt); net_stats_update_ipv6_nd_recv(net_pkt_iface(pkt)); - if ((total_len < (sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_na_hdr) + - sizeof(struct net_icmpv6_nd_opt_hdr))) || - (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT) || - net_ipv6_is_addr_mcast(&na_hdr.tgt) || - (net_is_solicited(pkt) && - net_ipv6_is_addr_mcast(&ip_hdr->dst))) { - struct net_icmp_hdr icmp_hdr; - - ret = net_icmpv6_get_hdr(pkt, &icmp_hdr); - if (ret < 0 || icmp_hdr.code != 0) { - goto drop; - } + if (((length < (sizeof(struct net_ipv6_hdr) + + sizeof(struct net_icmp_hdr) + + sizeof(struct net_icmpv6_na_hdr) + + sizeof(struct net_icmpv6_nd_opt_hdr))) || + (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT) || + net_ipv6_is_addr_mcast(&na_hdr->tgt) || + (na_hdr->flags & NET_ICMPV6_NA_FLAG_SOLICITED && + net_ipv6_is_addr_mcast(&ip_hdr->dst))) && + (icmp_hdr->code != 0)) { + goto drop; } - net_pkt_set_ipv6_ext_opt_len(pkt, sizeof(struct net_icmpv6_na_hdr)); + net_pkt_acknowledge_data(pkt, &na_access); - left_len = net_pkt_get_len(pkt) - (sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr)); + net_pkt_set_ipv6_ext_opt_len(pkt, sizeof(struct net_icmpv6_na_hdr)); + length -= (sizeof(struct net_ipv6_hdr) + sizeof(struct net_icmp_hdr)); - ret = net_icmpv6_get_nd_opt_hdr(pkt, &nd_opt_hdr); + nd_opt_hdr = (struct net_icmpv6_nd_opt_hdr *) + net_pkt_get_data_new(pkt, &nd_access); - while (!ret && net_pkt_ipv6_ext_opt_len(pkt) < left_len) { - if (!nd_opt_hdr.len) { - break; - } + while (nd_opt_hdr && nd_opt_hdr->len && + net_pkt_ipv6_ext_opt_len(pkt) < length) { + u8_t prev_opt_len; - switch (nd_opt_hdr.type) { + switch (nd_opt_hdr->type) { case NET_ICMPV6_ND_OPT_TLLAO: tllao_offset = net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt) + @@ -1711,7 +1665,7 @@ static enum net_verdict handle_na_input(struct net_pkt *pkt, break; default: - NET_DBG("Unknown ND option 0x%x", nd_opt_hdr.type); + NET_DBG("Unknown ND option 0x%x", nd_opt_hdr->type); break; } @@ -1719,33 +1673,35 @@ static enum net_verdict handle_na_input(struct net_pkt *pkt, net_pkt_set_ipv6_ext_opt_len(pkt, net_pkt_ipv6_ext_opt_len(pkt) + - (nd_opt_hdr.len << 3)); + (nd_opt_hdr->len << 3)); if (prev_opt_len >= net_pkt_ipv6_ext_opt_len(pkt)) { - NET_ERR("Corrupted NA message"); + NET_ERR("DROP: Corrupted NA message"); goto drop; } - ret = net_icmpv6_get_nd_opt_hdr(pkt, &nd_opt_hdr); + net_pkt_acknowledge_data(pkt, &nd_access); + nd_opt_hdr = (struct net_icmpv6_nd_opt_hdr *) + net_pkt_get_data_new(pkt, &nd_access); } ifaddr = net_if_ipv6_addr_lookup_by_iface(net_pkt_iface(pkt), - &na_hdr.tgt); + &na_hdr->tgt); if (ifaddr) { NET_DBG("Interface %p already has address %s", net_pkt_iface(pkt), - log_strdup(net_sprint_ipv6_addr(&na_hdr.tgt))); + log_strdup(net_sprint_ipv6_addr(&na_hdr->tgt))); #if defined(CONFIG_NET_IPV6_DAD) if (ifaddr->addr_state == NET_ADDR_TENTATIVE) { - dad_failed(net_pkt_iface(pkt), &na_hdr.tgt); + dad_failed(net_pkt_iface(pkt), &na_hdr->tgt); } #endif /* CONFIG_NET_IPV6_DAD */ goto drop; } - if (!handle_na_neighbor(pkt, &na_hdr, tllao_offset)) { + if (!handle_na_neighbor(pkt, na_hdr, tllao_offset)) { goto drop; } From 8b26a74baaab6db32cad35f83a6e35a3eac7002c Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 14:00:05 +0100 Subject: [PATCH 45/70] net/ipv6: Switch NS msg handler to new net_pkt API Reworking the logic to reduce the amount of variables. Also taking the opportunity to normalize drop messages. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6_nbr.c | 129 +++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 74 deletions(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index cab649303af64..98eb86bed3f86 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -893,19 +893,15 @@ static inline bool set_llao(struct net_pkt *pkt, } static inline struct net_nbr *handle_ns_neighbor(struct net_pkt *pkt, - u8_t ll_len, - u16_t sllao_offset) + u8_t ll_len) { struct net_linkaddr_storage lladdr; struct net_linkaddr nbr_lladdr; - struct net_buf *frag; u16_t pos; lladdr.len = 8 * ll_len - 2; - frag = net_frag_read(pkt->frags, sllao_offset, - &pos, lladdr.len, lladdr.addr); - if (!frag && pos == 0xffff) { + if (net_pkt_read_new(pkt, lladdr.addr, lladdr.len)) { return NULL; } @@ -1023,86 +1019,71 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt, struct net_ipv6_hdr *ip_hdr, struct net_icmp_hdr *icmp_hdr) { - u16_t total_len = net_pkt_get_len(pkt); - u8_t prev_opt_len = 0U; + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ns_access, + struct net_icmpv6_ns_hdr); + NET_PKT_DATA_ACCESS_DEFINE(nd_access, struct net_icmpv6_nd_opt_hdr); + u16_t length = net_pkt_get_len(pkt); u8_t flags = 0U; bool routing = false; - struct net_icmpv6_nd_opt_hdr nd_opt_hdr; - struct net_icmpv6_ns_hdr ns_hdr; + struct net_icmpv6_nd_opt_hdr *nd_opt_hdr; + struct net_icmpv6_ns_hdr *ns_hdr; struct net_if_addr *ifaddr; - struct in6_addr *tgt; const struct in6_addr *src; - size_t left_len; - int ret; + struct in6_addr *tgt; - ret = net_icmpv6_get_ns_hdr(pkt, &ns_hdr); - if (ret < 0) { - NET_ERR("NULL NS header - dropping"); + ns_hdr = (struct net_icmpv6_ns_hdr *)net_pkt_get_data_new(pkt, + &ns_access); + if (!ns_hdr) { + NET_ERR("DROP: NULL NS header"); goto drop; } dbg_addr_recv_tgt("Neighbor Solicitation", - &ip_hdr->src, &ip_hdr->dst, &ns_hdr.tgt); + &ip_hdr->src, &ip_hdr->dst, &ns_hdr->tgt); net_stats_update_ipv6_nd_recv(net_pkt_iface(pkt)); - if ((total_len < (sizeof(struct net_ipv6_hdr) + + if (((length < (sizeof(struct net_ipv6_hdr) + sizeof(struct net_icmp_hdr) + sizeof(struct net_icmpv6_ns_hdr))) || - (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT)) { - if (net_ipv6_is_addr_mcast(&ns_hdr.tgt)) { - struct net_icmp_hdr icmp_hdr; - - ret = net_icmpv6_get_hdr(pkt, &icmp_hdr); - if (ret < 0 || icmp_hdr.code != 0) { - NET_DBG("Preliminary check failed %u/%zu, " - "code %u, hop %u", - total_len, - (sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_ns_hdr)), - icmp_hdr.code, ip_hdr->hop_limit); - goto drop; - } - } + (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT)) && + (net_ipv6_is_addr_mcast(&ns_hdr->tgt) && icmp_hdr->code != 0)) { + goto drop; } + net_pkt_acknowledge_data(pkt, &ns_access); + net_pkt_set_ipv6_ext_opt_len(pkt, sizeof(struct net_icmpv6_ns_hdr)); + length -= (sizeof(struct net_ipv6_hdr) + sizeof(struct net_icmp_hdr)); - left_len = net_pkt_get_len(pkt) - (sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr)); + nd_opt_hdr = (struct net_icmpv6_nd_opt_hdr *) + net_pkt_get_data_new(pkt, &nd_access); - ret = net_icmpv6_get_nd_opt_hdr(pkt, &nd_opt_hdr); + while (nd_opt_hdr && nd_opt_hdr->len > 0 && + net_pkt_ipv6_ext_opt_len(pkt) < length) { + u8_t prev_opt_len; - while (!ret && net_pkt_ipv6_ext_opt_len(pkt) < left_len) { - if (!nd_opt_hdr.len) { - break; - } + net_pkt_acknowledge_data(pkt, &nd_access); - switch (nd_opt_hdr.type) { + switch (nd_opt_hdr->type) { case NET_ICMPV6_ND_OPT_SLLAO: if (net_ipv6_is_addr_unspecified(&ip_hdr->src)) { goto drop; } - if (nd_opt_hdr.len > 2) { - NET_ERR("Too long source link-layer address " + if (nd_opt_hdr->len > 2) { + NET_ERR("DROP: Too long source ll address " "in NS option"); goto drop; } - if (!handle_ns_neighbor(pkt, nd_opt_hdr.len, - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr) + - net_pkt_ipv6_ext_opt_len(pkt) + - 1 + 1)) { + if (!handle_ns_neighbor(pkt, nd_opt_hdr->len)) { goto drop; } - break; + break; default: - NET_DBG("Unknown ND option 0x%x", nd_opt_hdr.type); + NET_DBG("Unknown ND option 0x%x", nd_opt_hdr->type); break; } @@ -1110,36 +1091,37 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt, net_pkt_set_ipv6_ext_opt_len(pkt, net_pkt_ipv6_ext_opt_len(pkt) + - (nd_opt_hdr.len << 3)); + (nd_opt_hdr->len << 3)); if (prev_opt_len >= net_pkt_ipv6_ext_opt_len(pkt)) { - NET_ERR("Corrupted NS message"); + NET_ERR("DROP: Corrupted NS message"); goto drop; } - ret = net_icmpv6_get_nd_opt_hdr(pkt, &nd_opt_hdr); + nd_opt_hdr = (struct net_icmpv6_nd_opt_hdr *) + net_pkt_get_data_new(pkt, &nd_access); } if (IS_ENABLED(CONFIG_NET_ROUTING)) { - ifaddr = net_if_ipv6_addr_lookup(&ns_hdr.tgt, NULL); + ifaddr = net_if_ipv6_addr_lookup(&ns_hdr->tgt, NULL); } else { ifaddr = net_if_ipv6_addr_lookup_by_iface(net_pkt_iface(pkt), - &ns_hdr.tgt); + &ns_hdr->tgt); } if (!ifaddr) { if (IS_ENABLED(CONFIG_NET_ROUTING)) { struct in6_addr *nexthop; - nexthop = check_route(NULL, &ns_hdr.tgt, NULL); + nexthop = check_route(NULL, &ns_hdr->tgt, NULL); if (nexthop) { - ns_routing_info(pkt, nexthop, &ns_hdr.tgt); + ns_routing_info(pkt, nexthop, &ns_hdr->tgt); /* Note that the target is not the address of * the "nethop" as that is a link-local address * which is not routable. */ - tgt = &ns_hdr.tgt; + tgt = &ns_hdr->tgt; /* Source address must be one of our real * interface address where the packet was @@ -1148,8 +1130,8 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt, src = net_if_ipv6_select_src_addr( net_pkt_iface(pkt), &ip_hdr->src); if (!src) { - NET_DBG("No interface address for " - "dst %s iface %p", + NET_DBG("DROP: No interface address " + "for dst %s iface %p", log_strdup( net_sprint_ipv6_addr( &ip_hdr->src)), @@ -1162,8 +1144,8 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt, } } - NET_DBG("No such interface address %s", - log_strdup(net_sprint_ipv6_addr(&ns_hdr.tgt))); + NET_DBG("DROP: No such interface address %s", + log_strdup(net_sprint_ipv6_addr(&ns_hdr->tgt))); goto drop; } else { tgt = &ifaddr->address.in6_addr; @@ -1187,13 +1169,13 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt, if (net_ipv6_is_addr_unspecified(&ip_hdr->src)) { if (!net_ipv6_is_addr_solicited_node(&ip_hdr->dst)) { - NET_DBG("Not solicited node addr %s", + NET_DBG("DROP: Not solicited node addr %s", log_strdup(net_sprint_ipv6_addr(&ip_hdr->dst))); goto drop; } if (ifaddr->addr_state == NET_ADDR_TENTATIVE) { - NET_DBG("DAD failed for %s iface %p", + NET_DBG("DROP: DAD failed for %s iface %p", log_strdup(net_sprint_ipv6_addr( &ifaddr->address.in6_addr)), net_pkt_iface(pkt)); @@ -1214,7 +1196,7 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt, #endif /* CONFIG_NET_IPV6_DAD */ if (net_ipv6_is_my_addr(&ip_hdr->src)) { - NET_DBG("Duplicate IPv6 %s address", + NET_DBG("DROP: Duplicate IPv6 %s address", log_strdup(net_sprint_ipv6_addr(&ip_hdr->src))); goto drop; } @@ -1222,7 +1204,7 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt, /* Address resolution */ if (net_ipv6_is_addr_solicited_node(&ip_hdr->dst)) { net_ipaddr_copy(&ip_hdr->dst, &ip_hdr->src); - net_ipaddr_copy(&ip_hdr->src, &ns_hdr.tgt); + net_ipaddr_copy(&ip_hdr->src, &ns_hdr->tgt); flags = NET_ICMPV6_NA_FLAG_SOLICITED | NET_ICMPV6_NA_FLAG_OVERRIDE; goto send_na; @@ -1243,26 +1225,25 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt, if (ifaddr) { net_ipaddr_copy(&ip_hdr->dst, &ip_hdr->src); - net_ipaddr_copy(&ip_hdr->src, &ns_hdr.tgt); + net_ipaddr_copy(&ip_hdr->src, &ns_hdr->tgt); src = &ip_hdr->src; tgt = &ifaddr->address.in6_addr; flags = NET_ICMPV6_NA_FLAG_SOLICITED | NET_ICMPV6_NA_FLAG_OVERRIDE; goto send_na; } else { - NET_DBG("NUD failed"); + NET_DBG("DROP: NUD failed"); goto drop; } send_na: - ret = net_ipv6_send_na(net_pkt_iface(pkt), src, - &ip_hdr->dst, tgt, flags); - if (!ret) { + if (!net_ipv6_send_na(net_pkt_iface(pkt), src, + &ip_hdr->dst, tgt, flags)) { net_pkt_unref(pkt); return NET_OK; } - NET_DBG("Cannot send NA (%d)", ret); + NET_DBG("DROP: Cannot send NA"); return NET_DROP; From 046e08c148fd1c43c867067dff03ba57e60a381e Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 15:26:22 +0100 Subject: [PATCH 46/70] net/ipv6: Switch RA msg handler to new net_pkt API Reworking the logic to reduce the amount of variables. This part was heavier to change as it was not accessing the headers directly but instead was read parts by parts. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.h | 6 - subsys/net/ip/ipv6_nbr.c | 297 +++++++++++++++------------------------ tests/net/6lo/src/main.c | 4 - 3 files changed, 115 insertions(+), 192 deletions(-) diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index 0b7096b003dbe..0e21687198a67 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -48,15 +48,11 @@ struct net_icmpv6_ra_hdr { } __packed; struct net_icmpv6_nd_opt_mtu { - u8_t type; - u8_t len; u16_t reserved; u32_t mtu; } __packed; struct net_icmpv6_nd_opt_prefix_info { - u8_t type; - u8_t len; u8_t prefix_len; u8_t flags; u32_t valid_lifetime; @@ -66,8 +62,6 @@ struct net_icmpv6_nd_opt_prefix_info { } __packed; struct net_icmpv6_nd_opt_6co { - u8_t type; - u8_t len; u8_t context_len; u8_t flag; /*res:3,c:1,cid:4 */ u16_t reserved; diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 98eb86bed3f86..a6ac27fc78d5c 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -897,7 +897,6 @@ static inline struct net_nbr *handle_ns_neighbor(struct net_pkt *pkt, { struct net_linkaddr_storage lladdr; struct net_linkaddr nbr_lladdr; - u16_t pos; lladdr.len = 8 * ll_len - 2; @@ -1910,44 +1909,32 @@ int net_ipv6_start_rs(struct net_if *iface) return net_ipv6_send_rs(iface); } -static inline struct net_buf *handle_ra_neighbor(struct net_pkt *pkt, - struct net_buf *frag, - u8_t len, - u16_t offset, u16_t *pos, - struct net_nbr **nbr) +static inline struct net_nbr *handle_ra_neighbor(struct net_pkt *pkt, u8_t len) { struct net_linkaddr lladdr; struct net_linkaddr_storage llstorage; u8_t padding; - if (!nbr) { - return NULL; - } - llstorage.len = NET_LINK_ADDR_MAX_LENGTH; - lladdr.len = NET_LINK_ADDR_MAX_LENGTH; lladdr.addr = llstorage.addr; + lladdr.len = NET_LINK_ADDR_MAX_LENGTH; if (net_pkt_lladdr_src(pkt)->len < lladdr.len) { lladdr.len = net_pkt_lladdr_src(pkt)->len; } - frag = net_frag_read(frag, offset, pos, lladdr.len, lladdr.addr); - if (!frag && offset) { + if (net_pkt_read_new(pkt, lladdr.addr, lladdr.len)) { return NULL; } padding = len * 8 - 2 - lladdr.len; if (padding) { - frag = net_frag_read(frag, *pos, pos, padding, NULL); - if (!frag && *pos) { + if (net_pkt_skip(pkt, padding)) { return NULL; } } - *nbr = nbr_add(pkt, &lladdr, true, NET_IPV6_NBR_STATE_STALE); - - return frag; + return nbr_add(pkt, &lladdr, true, NET_IPV6_NBR_STATE_STALE); } static inline void handle_prefix_onlink(struct net_pkt *pkt, @@ -2010,12 +1997,11 @@ static inline void handle_prefix_onlink(struct net_pkt *pkt, NET_DBG("Interface %p update prefix %s/%u lifetime %u", net_pkt_iface(pkt), log_strdup(net_sprint_ipv6_addr(&prefix_info->prefix)), - prefix_info->prefix_len, - prefix_info->valid_lifetime); + prefix_info->prefix_len, prefix_info->valid_lifetime); net_if_ipv6_prefix_set_lf(prefix, false); net_if_ipv6_prefix_set_timer(prefix, - prefix_info->valid_lifetime); + prefix_info->valid_lifetime); break; } } @@ -2075,8 +2061,8 @@ static inline void handle_prefix_autonomous(struct net_pkt *pkt, log_strdup(net_sprint_ipv6_addr(&addr)), prefix_info->valid_lifetime); - net_if_ipv6_addr_update_lifetime(ifaddr, - prefix_info->valid_lifetime); + net_if_ipv6_addr_update_lifetime( + ifaddr, prefix_info->valid_lifetime); } else { NET_DBG("Timer updating for address %s " "lifetime %u secs", @@ -2100,109 +2086,77 @@ static inline void handle_prefix_autonomous(struct net_pkt *pkt, } } -static inline struct net_buf *handle_ra_prefix(struct net_pkt *pkt, - struct net_buf *frag, - u8_t len, - u16_t offset, u16_t *pos) +static inline bool handle_ra_prefix(struct net_pkt *pkt) { - struct net_icmpv6_nd_opt_prefix_info prefix_info; - - prefix_info.type = NET_ICMPV6_ND_OPT_PREFIX_INFO; - prefix_info.len = len * 8 - 2; - - frag = net_frag_read(frag, offset, pos, 1, &prefix_info.prefix_len); - frag = net_frag_read(frag, *pos, pos, 1, &prefix_info.flags); - frag = net_frag_read_be32(frag, *pos, pos, &prefix_info.valid_lifetime); - frag = net_frag_read_be32(frag, *pos, pos, - &prefix_info.preferred_lifetime); - /* Skip reserved bytes */ - frag = net_frag_skip(frag, *pos, pos, 4); - frag = net_frag_read(frag, *pos, pos, sizeof(struct in6_addr), - prefix_info.prefix.s6_addr); - if (!frag && *pos) { - return NULL; + NET_PKT_DATA_ACCESS_DEFINE(rapfx_access, + struct net_icmpv6_nd_opt_prefix_info); + struct net_icmpv6_nd_opt_prefix_info *pfx_info; + + pfx_info = (struct net_icmpv6_nd_opt_prefix_info *) + net_pkt_get_data_new(pkt, &rapfx_access); + if (!pfx_info) { + return false; } - if (prefix_info.valid_lifetime >= prefix_info.preferred_lifetime && - !net_ipv6_is_ll_addr(&prefix_info.prefix)) { + net_pkt_acknowledge_data(pkt, &rapfx_access); - if (prefix_info.flags & NET_ICMPV6_RA_FLAG_ONLINK) { - handle_prefix_onlink(pkt, &prefix_info); + pfx_info->valid_lifetime = ntohl(pfx_info->valid_lifetime); + pfx_info->preferred_lifetime = ntohl(pfx_info->preferred_lifetime); + + if (pfx_info->valid_lifetime >= pfx_info->preferred_lifetime && + !net_ipv6_is_ll_addr(&pfx_info->prefix)) { + if (pfx_info->flags & NET_ICMPV6_RA_FLAG_ONLINK) { + handle_prefix_onlink(pkt, pfx_info); } - if ((prefix_info.flags & NET_ICMPV6_RA_FLAG_AUTONOMOUS) && - prefix_info.valid_lifetime && - (prefix_info.prefix_len == NET_IPV6_DEFAULT_PREFIX_LEN)) { - handle_prefix_autonomous(pkt, &prefix_info); + if ((pfx_info->flags & NET_ICMPV6_RA_FLAG_AUTONOMOUS) && + pfx_info->valid_lifetime && + (pfx_info->prefix_len == NET_IPV6_DEFAULT_PREFIX_LEN)) { + handle_prefix_autonomous(pkt, pfx_info); } } - return frag; + return true; } #if defined(CONFIG_NET_6LO_CONTEXT) /* 6lowpan Context Option RFC 6775, 4.2 */ -static inline struct net_buf *handle_ra_6co(struct net_pkt *pkt, - struct net_buf *frag, - u8_t len, - u16_t offset, u16_t *pos) +static inline bool handle_ra_6co(struct net_pkt *pkt, u8_t len) { - struct net_icmpv6_nd_opt_6co context; + NET_PKT_DATA_ACCESS_DEFINE(ctx_access, struct net_icmpv6_nd_opt_6co); + struct net_icmpv6_nd_opt_6co *context; - context.type = NET_ICMPV6_ND_OPT_6CO; - context.len = len * 8 - 2; - - frag = net_frag_read_u8(frag, offset, pos, &context.context_len); + context = (struct net_icmpv6_nd_opt_6co *) + net_pkt_get_data_new(pkt, &ctx_access); + if (!context) { + return false; + } /* RFC 6775, 4.2 * Context Length: 8-bit unsigned integer. The number of leading * bits in the Context Prefix field that are valid. The value ranges * from 0 to 128. If it is more than 64, then the Length MUST be 3. */ - if (context.context_len > 64 && len != 3) { - return NULL; - } - - if (context.context_len <= 64 && len != 2) { - return NULL; - } - - context.context_len = context.context_len / 8; - frag = net_frag_read_u8(frag, *pos, pos, &context.flag); - - /* Skip reserved bytes */ - frag = net_frag_skip(frag, *pos, pos, 2); - frag = net_frag_read_be16(frag, *pos, pos, &context.lifetime); - - /* RFC 6775, 4.2 (Length field). Length can be 2 or 3 depending - * on the length of context prefix field. - */ - if (len == 3) { - frag = net_frag_read(frag, *pos, pos, sizeof(struct in6_addr), - context.prefix.s6_addr); - } else if (len == 2) { - /* If length is 2 means only 64 bits of context prefix - * is available, rest set to zeros. - */ - frag = net_frag_read(frag, *pos, pos, 8, - context.prefix.s6_addr); + if ((context->context_len > 64 && len != 3) || + (context->context_len <= 64 && len != 2)) { + return false; } - if (!frag && *pos) { - return NULL; - } + context->context_len = context->context_len / 8; /* context_len: The number of leading bits in the Context Prefix - * field that are valid. So set remaining data to zero. + * field that are valid. Rest must be set to 0 by the sender and + * ignored by the receiver. But since there is no way to make sure + * the sender followed the rule, let's make sure rest is set to 0. */ - if (context.context_len != sizeof(struct in6_addr)) { - (void)memset(context.prefix.s6_addr + context.context_len, 0, - sizeof(struct in6_addr) - context.context_len); + if (context->context_len != sizeof(struct in6_addr)) { + (void)memset(context->prefix.s6_addr + context->context_len, 0, + sizeof(struct in6_addr) - context->context_len); } - net_6lo_set_context(net_pkt_iface(pkt), &context); + net_6lo_set_context(net_pkt_iface(pkt), context); - return frag; + return true; } #endif @@ -2210,109 +2164,90 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt, struct net_ipv6_hdr *ip_hdr, struct net_icmp_hdr *icmp_hdr) { - u16_t total_len = net_pkt_get_len(pkt); + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ra_access, + struct net_icmpv6_ra_hdr); + NET_PKT_DATA_ACCESS_DEFINE(nd_access, struct net_icmpv6_nd_opt_hdr); + u16_t length = net_pkt_get_len(pkt); struct net_nbr *nbr = NULL; - struct net_icmpv6_ra_hdr ra_hdr; + struct net_icmpv6_nd_opt_hdr *nd_opt_hdr; + struct net_icmpv6_ra_hdr *ra_hdr; struct net_if_router *router; - struct net_buf *frag; - u16_t router_lifetime; - u32_t reachable_time; - u32_t retrans_timer; - u8_t hop_limit; - u16_t offset; - u8_t length; - u8_t type; u32_t mtu; - int ret; + + ra_hdr = (struct net_icmpv6_ra_hdr *)net_pkt_get_data_new(pkt, + &ra_access); + if (!ra_hdr) { + NET_ERR("DROP: NULL RA header"); + goto drop; + } dbg_addr_recv("Router Advertisement", &ip_hdr->src, &ip_hdr->dst); net_stats_update_ipv6_nd_recv(net_pkt_iface(pkt)); - if ((total_len < (sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_ra_hdr) + - sizeof(struct net_icmpv6_nd_opt_hdr))) || - (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT) || - !net_ipv6_is_ll_addr(&ip_hdr->src)) { - struct net_icmp_hdr icmp_hdr; - - ret = net_icmpv6_get_hdr(pkt, &icmp_hdr); - if (ret < 0 || icmp_hdr.code != 0) { - goto drop; - } + if (((length < (sizeof(struct net_ipv6_hdr) + + sizeof(struct net_icmp_hdr) + + sizeof(struct net_icmpv6_ra_hdr) + + sizeof(struct net_icmpv6_nd_opt_hdr))) || + (ip_hdr->hop_limit != NET_IPV6_ND_HOP_LIMIT) || + !net_ipv6_is_ll_addr(&ip_hdr->src)) && icmp_hdr->code != 0) { + goto drop; } - frag = pkt->frags; - offset = sizeof(struct net_ipv6_hdr) + net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr); + net_pkt_acknowledge_data(pkt, &ra_access); - frag = net_frag_read_u8(frag, offset, &offset, &hop_limit); - frag = net_frag_skip(frag, offset, &offset, 1); /* flags */ - if (!frag) { - goto drop; - } + ra_hdr->router_lifetime = ntohs(ra_hdr->router_lifetime); + ra_hdr->reachable_time = ntohl(ra_hdr->reachable_time); + ra_hdr->retrans_timer = ntohl(ra_hdr->retrans_timer); - if (hop_limit) { - net_ipv6_set_hop_limit(net_pkt_iface(pkt), hop_limit); + if (ra_hdr->cur_hop_limit) { + net_ipv6_set_hop_limit(net_pkt_iface(pkt), + ra_hdr->cur_hop_limit); NET_DBG("New hop limit %d", net_if_ipv6_get_hop_limit(net_pkt_iface(pkt))); } - frag = net_frag_read_be16(frag, offset, &offset, &router_lifetime); - frag = net_frag_read_be32(frag, offset, &offset, &reachable_time); - frag = net_frag_read_be32(frag, offset, &offset, &retrans_timer); - if (!frag) { - goto drop; - } - - ret = net_icmpv6_get_ra_hdr(pkt, &ra_hdr); - if (ret < 0) { - NET_ERR("could not get ra_hdr"); - goto drop; - } - - if (reachable_time && reachable_time <= MAX_REACHABLE_TIME && + if (ra_hdr->reachable_time && + ra_hdr->reachable_time <= MAX_REACHABLE_TIME && (net_if_ipv6_get_reachable_time(net_pkt_iface(pkt)) != - ra_hdr.reachable_time)) { + ra_hdr->reachable_time)) { net_if_ipv6_set_base_reachable_time(net_pkt_iface(pkt), - reachable_time); - + ra_hdr->reachable_time); net_if_ipv6_set_reachable_time( net_pkt_iface(pkt)->config.ip.ipv6); } - if (retrans_timer) { + if (ra_hdr->retrans_timer) { net_if_ipv6_set_retrans_timer(net_pkt_iface(pkt), - retrans_timer); + ra_hdr->retrans_timer); } - while (frag) { - frag = net_frag_read(frag, offset, &offset, 1, &type); - frag = net_frag_read(frag, offset, &offset, 1, &length); - if (!frag) { - goto drop; - } + net_pkt_set_ipv6_ext_opt_len(pkt, sizeof(struct net_icmpv6_ra_hdr)); + length -= (sizeof(struct net_ipv6_hdr) + sizeof(struct net_icmp_hdr)); - switch (type) { + nd_opt_hdr = (struct net_icmpv6_nd_opt_hdr *) + net_pkt_get_data_new(pkt, &nd_access); + + while (nd_opt_hdr) { + net_pkt_acknowledge_data(pkt, &nd_access); + + switch (nd_opt_hdr->type) { case NET_ICMPV6_ND_OPT_SLLAO: - frag = handle_ra_neighbor(pkt, frag, length, offset, - &offset, &nbr); - if (!frag && offset) { + nbr = handle_ra_neighbor(pkt, nd_opt_hdr->len); + if (!nbr) { goto drop; } break; case NET_ICMPV6_ND_OPT_MTU: /* MTU has reserved 2 bytes, so skip it. */ - frag = net_frag_skip(frag, offset, &offset, 2); - frag = net_frag_read_be32(frag, offset, &offset, &mtu); - if (!frag && offset) { + if (net_pkt_skip(pkt, 2) || + net_pkt_read_be32_new(pkt, &mtu)) { goto drop; } if (mtu < MIN_IPV6_MTU || mtu > MAX_IPV6_MTU) { - NET_ERR("Unsupported MTU %u, min is %u, " + NET_ERR("DROP: Unsupported MTU %u, min is %u, " "max is %u", mtu, MIN_IPV6_MTU, MAX_IPV6_MTU); goto drop; @@ -2322,9 +2257,7 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt, break; case NET_ICMPV6_ND_OPT_PREFIX_INFO: - frag = handle_ra_prefix(pkt, frag, length, offset, - &offset); - if (!frag && offset) { + if (!handle_ra_prefix(pkt)) { goto drop; } @@ -2332,49 +2265,49 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt, #if defined(CONFIG_NET_6LO_CONTEXT) case NET_ICMPV6_ND_OPT_6CO: /* RFC 6775, 4.2 (Length)*/ - if (!(length == 2 || length == 3)) { - NET_ERR("Invalid 6CO length %d", length); + if (!(nd_opt_hdr->len == 2 || nd_opt_hdr->len == 3)) { + NET_ERR("DROP: Invalid 6CO length %d", + nd_opt_hdr->len); goto drop; } - frag = handle_ra_6co(pkt, frag, length, offset, - &offset); - if (!frag && offset) { + if (!handle_ra_6co(pkt, nd_opt_hdr->len)) { goto drop; } break; #endif case NET_ICMPV6_ND_OPT_ROUTE: - NET_DBG("Route option (0x%x) skipped", type); + NET_DBG("Route option skipped"); goto skip; #if defined(CONFIG_NET_IPV6_RA_RDNSS) case NET_ICMPV6_ND_OPT_RDNSS: - NET_DBG("RDNSS option (0x%x) skipped", type); + NET_DBG("RDNSS option skipped"); goto skip; #endif case NET_ICMPV6_ND_OPT_DNSSL: - NET_DBG("DNSSL option (0x%x) skipped", type); + NET_DBG("DNSSL option skipped"); goto skip; default: - NET_DBG("Unknown ND option 0x%x", type); + NET_DBG("Unknown ND option 0x%x", nd_opt_hdr->type); skip: - frag = net_frag_skip(frag, offset, &offset, - length * 8 - 2); - if (!frag && offset) { + if (net_pkt_skip(pkt, nd_opt_hdr->len * 8 - 2)) { goto drop; } break; } + + nd_opt_hdr = (struct net_icmpv6_nd_opt_hdr *) + net_pkt_get_data_new(pkt, &nd_access); } router = net_if_ipv6_router_lookup(net_pkt_iface(pkt), &ip_hdr->src); if (router) { - if (!router_lifetime) { + if (!ra_hdr->router_lifetime) { /* TODO: Start rs_timer on iface if no routers * at all available on iface. */ @@ -2384,12 +2317,12 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt, net_ipv6_nbr_data(nbr)->is_router = true; } - net_if_ipv6_router_update_lifetime(router, - router_lifetime); + net_if_ipv6_router_update_lifetime( + router, ra_hdr->router_lifetime); } } else { net_if_ipv6_router_add(net_pkt_iface(pkt), - &ip_hdr->src, router_lifetime); + &ip_hdr->src, ra_hdr->router_lifetime); } if (nbr && net_ipv6_nbr_data(nbr)->pending) { diff --git a/tests/net/6lo/src/main.c b/tests/net/6lo/src/main.c index bcec2b872e5cd..1da63cc05d4ce 100644 --- a/tests/net/6lo/src/main.c +++ b/tests/net/6lo/src/main.c @@ -109,8 +109,6 @@ u8_t dst_mac[8] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xaa }; /* 6CO contexts */ static struct net_icmpv6_nd_opt_6co ctx1 = { - .type = 0x22, - .len = 0x02, .context_len = 0x40, .flag = 0x11, .reserved = 0, @@ -123,8 +121,6 @@ static struct net_icmpv6_nd_opt_6co ctx1 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } } static struct net_icmpv6_nd_opt_6co ctx2 = { - .type = 0x22, - .len = 0x03, .context_len = 0x80, .flag = 0x12, .reserved = 0, From c8818ea24bc2241a8bebc3d699516aa2b8157810 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 21 Dec 2018 08:40:39 +0100 Subject: [PATCH 47/70] net/ipv6: Switch MLD query msg handler to new net_pkt API Reworking the logic to reduce the amount of variables. Introducing a generic struct to acces the common part of MLD queries, instead of accessing part by part. Also, returning NET_OK in case parsing went fine. We send an MLD report anyway, so it's not a good idea to count the message as being dropped in statistics. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.h | 8 +++++ subsys/net/ip/ipv6_mld.c | 69 +++++++++++++++++----------------------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index 0e21687198a67..eecebe52f0aa5 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -74,6 +74,14 @@ struct net_icmpv6_echo_req { u16_t sequence; } __packed; +struct net_icmpv6_mld_query { + u16_t max_response_code; + u16_t reserved; + struct in6_addr mcast_address; + u16_t flagg; /*S, QRV & QQIC */ + u16_t num_sources; +} __packed; + #define NET_ICMPV6_ND_O_FLAG(flag) ((flag) & 0x40) #define NET_ICMPV6_ND_M_FLAG(flag) ((flag) & 0x80) diff --git a/subsys/net/ip/ipv6_mld.c b/subsys/net/ip/ipv6_mld.c index 204788d63ea4e..3adb6c0dbc269 100644 --- a/subsys/net/ip/ipv6_mld.c +++ b/subsys/net/ip/ipv6_mld.c @@ -302,59 +302,50 @@ static enum net_verdict handle_mld_query(struct net_pkt *pkt, struct net_ipv6_hdr *ip_hdr, struct net_icmp_hdr *icmp_hdr) { - u16_t total_len = net_pkt_get_len(pkt); - struct in6_addr mcast; - u16_t max_rsp_code, num_src, pkt_len; - u16_t offset, pos; - struct net_buf *frag; - int ret; + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(mld_access, + struct net_icmpv6_mld_query); + u16_t length = net_pkt_get_len(pkt); + struct net_icmpv6_mld_query *mld_query; + u16_t pkt_len; + + mld_query = (struct net_icmpv6_mld_query *) + net_pkt_get_data_new(pkt, &mld_access); + if (!mld_query) { + NET_DBG("DROP: NULL MLD query"); + goto drop; + } + + net_pkt_acknowledge_data(pkt, &mld_access); dbg_addr_recv("Multicast Listener Query", &ip_hdr->src, &ip_hdr->dst); net_stats_update_ipv6_mld_recv(net_pkt_iface(pkt)); - /* offset tells now where the ICMPv6 header is starting */ - frag = net_frag_get_pos(pkt, - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr), - &offset); - - frag = net_frag_read_be16(frag, offset, &pos, &max_rsp_code); - frag = net_frag_skip(frag, pos, &pos, 2); /* two reserved bytes */ - frag = net_frag_read(frag, pos, &pos, sizeof(mcast), mcast.s6_addr); - frag = net_frag_skip(frag, pos, &pos, 2); /* skip S, QRV & QQIC */ - frag = net_frag_read_be16(pkt->frags, pos, &pos, &num_src); - if (!frag && pos == 0xffff) { - goto drop; - } + mld_query->num_sources = ntohs(mld_query->num_sources); pkt_len = sizeof(struct net_ipv6_hdr) + net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr) + (2 + 2 + 16 + 2 + 2) + - sizeof(struct in6_addr) * num_src; - - if ((total_len < pkt_len || pkt_len > NET_IPV6_MTU || - (ip_hdr->hop_limit != 1))) { - struct net_icmp_hdr icmp_hdr; - - ret = net_icmpv6_get_hdr(pkt, &icmp_hdr); - if (ret < 0 || icmp_hdr.code != 0) { - NET_DBG("Preliminary check failed %u/%u, code %u, " - "hop %u", total_len, pkt_len, - icmp_hdr.code, ip_hdr->hop_limit); - goto drop; - } + sizeof(struct net_icmp_hdr) + + sizeof(struct net_icmpv6_mld_query) + + sizeof(struct in6_addr) * mld_query->num_sources; + + if (length < pkt_len || pkt_len > NET_IPV6_MTU || + ip_hdr->hop_limit != 1 || icmp_hdr->code != 0) { + goto drop; } - /* Currently we only support a unspecified address query. */ - if (!net_ipv6_addr_cmp(&mcast, net_ipv6_unspecified_address())) { - NET_DBG("Only supporting unspecified address query (%s)", - log_strdup(net_sprint_ipv6_addr(&mcast))); + /* Currently we only support an unspecified address query. */ + if (!net_ipv6_addr_cmp(&mld_query->mcast_address, + net_ipv6_unspecified_address())) { + NET_DBG("DROP: only supporting unspecified address query"); goto drop; } send_mld_report(net_pkt_iface(pkt)); + net_pkt_unref(pkt); + + return NET_OK; + drop: net_stats_update_ipv6_mld_drop(net_pkt_iface(pkt)); From dd976c26a678fa52e0c443d099baaab794a05112 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 20 Dec 2018 17:14:03 +0100 Subject: [PATCH 48/70] net/icmpv6: Remove various useless get/set hdr functions All of these are unused anywhere now, thus can be safely removed. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.c | 145 ----------------------------------------- subsys/net/ip/icmpv6.h | 14 ---- 2 files changed, 159 deletions(-) diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index ce6a065e86ebd..88e7be3aa1d4c 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -127,151 +127,6 @@ int net_icmpv6_finalize(struct net_pkt *pkt) return net_pkt_set_data(pkt, &icmp_access); } -int net_icmpv6_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - frag = net_frag_read(pkt->frags, - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt), - &pos, sizeof(*hdr), (u8_t *)hdr); - if (pos > 0 && !frag) { - NET_ERR("Cannot get the ICMPv6 header");; - return -EINVAL; - } - - return 0; -} - -int net_icmpv6_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - frag = net_pkt_write(pkt, pkt->frags, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt), &pos, - sizeof(*hdr), (u8_t *)hdr, PKT_WAIT_TIME); - if (pos > 0 && !frag) { - NET_ERR("Cannot set the ICMPv6 header"); - return -EINVAL; - } - - return 0; -} - -int net_icmpv6_get_ns_hdr(struct net_pkt *pkt, struct net_icmpv6_ns_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - frag = net_frag_read(pkt->frags, - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr), - &pos, sizeof(*hdr), (u8_t *)hdr); - if (pos > 0 && !frag) { - NET_ERR("Cannot get the ICMPv6 NS header");; - return -EINVAL; - } - - return 0; -} - -int net_icmpv6_set_ns_hdr(struct net_pkt *pkt, struct net_icmpv6_ns_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - hdr->reserved = 0U; - - frag = net_pkt_write(pkt, pkt->frags, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr), &pos, - sizeof(*hdr), (u8_t *)hdr, PKT_WAIT_TIME); - if (pos > 0 && !frag) { - NET_ERR("Cannot set the ICMPv6 NS header"); - return -EINVAL; - } - - return 0; -} - -int net_icmpv6_get_nd_opt_hdr(struct net_pkt *pkt, - struct net_icmpv6_nd_opt_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - frag = net_frag_read(pkt->frags, - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr) + - net_pkt_ipv6_ext_opt_len(pkt), - &pos, sizeof(*hdr), (u8_t *)hdr); - if (pos > 0 && !frag) { - return -EINVAL; - } - - return 0; -} - -int net_icmpv6_get_na_hdr(struct net_pkt *pkt, struct net_icmpv6_na_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - frag = net_frag_read(pkt->frags, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr), - &pos, sizeof(*hdr), (u8_t *)hdr); - - if (pos > 0 && !frag) { - NET_ERR("Cannot get the ICMPv6 NA header"); - return -EINVAL; - } - - return 0; -} - -int net_icmpv6_set_na_hdr(struct net_pkt *pkt, struct net_icmpv6_na_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - (void)memset(hdr->reserved, 0, sizeof(hdr->reserved)); - - frag = net_pkt_write(pkt, pkt->frags, - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr), - &pos, sizeof(*hdr), (u8_t *)hdr, - PKT_WAIT_TIME); - if (!frag) { - NET_ERR("Cannot set the ICMPv6 NA header"); - return -EINVAL; - } - - return 0; -} - -int net_icmpv6_get_ra_hdr(struct net_pkt *pkt, struct net_icmpv6_ra_hdr *hdr) -{ - struct net_buf *frag; - u16_t pos; - - frag = net_frag_read(pkt->frags, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_icmp_hdr), - &pos, sizeof(*hdr), (u8_t *)hdr); - if (pos > 0 && !frag) { - NET_ERR("Cannot get the ICMPv6 RA header"); - return -EINVAL; - } - - return 0; -} - int net_icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index eecebe52f0aa5..3580d7b39a2c7 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -183,24 +183,10 @@ void net_icmpv6_unregister_handler(struct net_icmpv6_handler *handler); enum net_verdict net_icmpv6_input(struct net_pkt *pkt, struct net_ipv6_hdr *ip_hdr); -int net_icmpv6_get_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); -int net_icmpv6_set_hdr(struct net_pkt *pkt, struct net_icmp_hdr *hdr); - int net_icmpv6_set_chksum(struct net_pkt *pkt); int net_icmpv6_create(struct net_pkt *pkt, u8_t icmp_type, u8_t icmp_code); int net_icmpv6_finalize(struct net_pkt *pkt); -int net_icmpv6_get_ns_hdr(struct net_pkt *pkt, struct net_icmpv6_ns_hdr *hdr); -int net_icmpv6_set_ns_hdr(struct net_pkt *pkt, struct net_icmpv6_ns_hdr *hdr); - -int net_icmpv6_get_nd_opt_hdr(struct net_pkt *pkt, - struct net_icmpv6_nd_opt_hdr *hdr); - -int net_icmpv6_get_na_hdr(struct net_pkt *pkt, struct net_icmpv6_na_hdr *hdr); -int net_icmpv6_set_na_hdr(struct net_pkt *pkt, struct net_icmpv6_na_hdr *hdr); - -int net_icmpv6_get_ra_hdr(struct net_pkt *pkt, struct net_icmpv6_ra_hdr *hdr); - #if defined(CONFIG_NET_IPV6) void net_icmpv6_init(void); #else From 96d00cbfeff1ca0f70a6fbbadc77a870f69b2431 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 21 Dec 2018 09:08:19 +0100 Subject: [PATCH 49/70] net/ipv6: Switch IPv6 sending preparation to new net_pkt API Also, return a verdict instead of a pointer to net_pkt. It's simpler as it will be up to net_send_data()'s caller to unref the net_pkt in case of NET_DROP: less places where net_pkt can be unref. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6.h | 8 ++--- subsys/net/ip/ipv6_nbr.c | 66 ++++++++++++++++++++-------------------- subsys/net/ip/net_if.c | 6 +--- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/subsys/net/ip/ipv6.h b/subsys/net/ip/ipv6.h index 2734e1630b118..9de3e63403526 100644 --- a/subsys/net/ip/ipv6.h +++ b/subsys/net/ip/ipv6.h @@ -232,9 +232,9 @@ typedef void (*net_nbr_cb_t)(struct net_nbr *nbr, void *user_data); * * @param pkt Network packet * - * @return Return network packet to be sent. + * @return Return a verdict. */ -struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt); +enum net_verdict net_ipv6_prepare_for_send(struct net_pkt *pkt); /** * @brief Look for a neighbor from it's address on an iface @@ -310,9 +310,9 @@ bool net_ipv6_nbr_rm(struct net_if *iface, struct in6_addr *addr); void net_ipv6_nbr_foreach(net_nbr_cb_t cb, void *user_data); #else /* CONFIG_NET_IPV6_NBR_CACHE */ -static inline struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) +static inline enum net_verdict net_ipv6_prepare_for_send(struct net_pkt *pkt) { - return pkt; + return NET_OK; } static inline struct net_nbr *net_ipv6_nbr_lookup(struct net_if *iface, diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index a6ac27fc78d5c..015d717ec61f5 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -643,14 +643,21 @@ static struct in6_addr *check_route(struct net_if *iface, return nexthop; } -struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) +enum net_verdict net_ipv6_prepare_for_send(struct net_pkt *pkt) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr); struct in6_addr *nexthop = NULL; struct net_if *iface = NULL; + struct net_ipv6_hdr *ip_hdr; struct net_nbr *nbr; int ret; - NET_ASSERT(pkt && pkt->frags); + NET_ASSERT(pkt && pkt->buffer); + + ip_hdr = (struct net_ipv6_hdr *)net_pkt_get_data_new(pkt, &ipv6_access); + if (!ip_hdr) { + return NET_DROP; + } #if defined(CONFIG_NET_IPV6_FRAGMENT) /* If we have already fragmented the packet, the fragment id will @@ -681,7 +688,9 @@ struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) * thing to do here and will cause free memory access * if not done. */ - net_pkt_set_sent(pkt, true); + if (IS_ENABLED(CONFIG_NET_TCP)) { + net_pkt_set_sent(pkt, true); + } /* We need to unref here because we simulate the packet * sending. @@ -692,20 +701,12 @@ struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) * is now split and its fragments will be sent * separately to network. */ - return NULL; + return NET_CONTINUE; } } ignore_frag_error: #endif /* CONFIG_NET_IPV6_FRAGMENT */ - /* Workaround Linux bug, see: - * https://github.com/zephyrproject-rtos/zephyr/issues/3111 - */ - if (atomic_test_bit(net_pkt_iface(pkt)->if_dev->flags, - NET_IF_POINTOPOINT)) { - return pkt; - } - /* If the IPv6 destination address is not link local, then try to get * the next hop from routing table if we have multi interface routing * enabled. The reason for this is that the neighbor cache will not @@ -714,15 +715,19 @@ struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) */ if ((net_pkt_lladdr_dst(pkt)->addr && ((IS_ENABLED(CONFIG_NET_ROUTING) && - net_ipv6_is_ll_addr(&NET_IPV6_HDR(pkt)->dst)) || + net_ipv6_is_ll_addr(&ip_hdr->dst)) || !IS_ENABLED(CONFIG_NET_ROUTING))) || - net_ipv6_is_addr_mcast(&NET_IPV6_HDR(pkt)->dst)) { - return pkt; + net_ipv6_is_addr_mcast(&ip_hdr->dst) || + /* Workaround Linux bug, see: + * https://github.com/zephyrproject-rtos/zephyr/issues/3111 + */ + atomic_test_bit(net_pkt_iface(pkt)->if_dev->flags, + NET_IF_POINTOPOINT)) { + return NET_OK; } - if (net_if_ipv6_addr_onlink(&iface, - &NET_IPV6_HDR(pkt)->dst)) { - nexthop = &NET_IPV6_HDR(pkt)->dst; + if (net_if_ipv6_addr_onlink(&iface, &ip_hdr->dst)) { + nexthop = &ip_hdr->dst; net_pkt_set_iface(pkt, iface); } else { /* We need to figure out where the destination @@ -730,11 +735,9 @@ struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) */ bool try_route = false; - nexthop = check_route(NULL, &NET_IPV6_HDR(pkt)->dst, - &try_route); + nexthop = check_route(NULL, &ip_hdr->dst, &try_route); if (!nexthop) { - net_pkt_unref(pkt); - return NULL; + return NET_DROP; } if (try_route) { @@ -797,34 +800,31 @@ struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) } } #endif - - return pkt; + return NET_OK; } #if defined(CONFIG_NET_IPV6_ND) /* We need to send NS and wait for NA before sending the packet. */ ret = net_ipv6_send_ns(net_pkt_iface(pkt), pkt, - &NET_IPV6_HDR(pkt)->src, NULL, - nexthop, false); + &ip_hdr->src, NULL, nexthop, false); if (ret < 0) { /* In case of an error, the NS send function will unref * the pkt. */ NET_DBG("Cannot send NS (%d)", ret); - return NULL; } - NET_DBG("pkt %p (frag %p) will be sent later", pkt, pkt->frags); + NET_DBG("pkt %p (buffer %p) will be sent later", pkt, pkt->buffer); + + return NET_CONTINUE; #else ARG_UNUSED(ret); - NET_DBG("pkt %p (frag %p) cannot be sent, dropping it.", pkt, - pkt->frags); + NET_DBG("pkt %p (buffer %p) cannot be sent, dropping it.", + pkt, pkt->buffer); - net_pkt_unref(pkt); + return NET_DROP; #endif /* CONFIG_NET_IPV6_ND */ - - return NULL; } struct net_nbr *net_ipv6_nbr_lookup(struct net_if *iface, diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 78cb5219daebf..24831f40c8d67 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -284,11 +284,7 @@ enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt) * cache. */ if (net_pkt_family(pkt) == AF_INET6) { - pkt = net_ipv6_prepare_for_send(pkt); - if (!pkt) { - verdict = NET_CONTINUE; - goto done; - } + verdict = net_ipv6_prepare_for_send(pkt); } #endif From f491728bcc0f721afeb1a0c9848ae287a56cf299 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 21 Dec 2018 14:10:03 +0100 Subject: [PATCH 50/70] net/ipv6: Switch MLD join, leave and report to new net_pkt API Most of the code had to be reworked due to the new API: it's more logical to do everything sequentially (first headers, then MLD part) than the contrary with inserting headers at the end. Using get_data/set_data as well it makes the code clearer. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/icmpv6.h | 8 ++ subsys/net/ip/ipv6_mld.c | 241 +++++++++++++++++++-------------------- tests/net/mld/src/main.c | 18 ++- 3 files changed, 142 insertions(+), 125 deletions(-) diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index 3580d7b39a2c7..9a0f4cb8eda9f 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -82,6 +82,14 @@ struct net_icmpv6_mld_query { u16_t num_sources; } __packed; +struct net_icmpv6_mld_mcast_record { + u8_t record_type; + u8_t aux_data_len; + u16_t num_sources; + struct in6_addr mcast_address; +} __packed; + + #define NET_ICMPV6_ND_O_FLAG(flag) ((flag) & 0x40) #define NET_ICMPV6_ND_M_FLAG(flag) ((flag) & 0x80) diff --git a/subsys/net/ip/ipv6_mld.c b/subsys/net/ip/ipv6_mld.c index 3adb6c0dbc269..e729ccd842821 100644 --- a/subsys/net/ip/ipv6_mld.c +++ b/subsys/net/ip/ipv6_mld.c @@ -30,160 +30,155 @@ LOG_MODULE_DECLARE(net_ipv6, CONFIG_NET_IPV6_LOG_LEVEL); #include "net_stats.h" /* Timeout for various buffer allocations in this file. */ -#define NET_BUF_TIMEOUT K_MSEC(50) +#define PKT_WAIT_TIME K_MSEC(50) -#define append(pkt, type, value) \ - do { \ - if (!net_pkt_append_##type##_timeout(pkt, value, \ - NET_BUF_TIMEOUT)) { \ - ret = -ENOMEM; \ - goto drop; \ - } \ - } while (0) - -#define append_all(pkt, size, value) \ - do { \ - if (!net_pkt_append_all(pkt, size, value, \ - NET_BUF_TIMEOUT)) { \ - ret = -ENOMEM; \ - goto drop; \ - } \ - } while (0) +#define MLDv2_MCAST_RECORD_LEN sizeof(struct net_icmpv6_mld_mcast_record) +#define IPV6_OPT_HDR_ROUTER_ALERT_LEN 8 -#define MLDv2_LEN (2 + 1 + 1 + 2 + sizeof(struct in6_addr) * 2) +#define MLDv2_LEN (MLDv2_MCAST_RECORD_LEN + sizeof(struct in6_addr)) -static struct net_pkt *create_mldv2(struct net_pkt *pkt, - const struct in6_addr *addr, - u16_t record_type, - u8_t num_sources) +static int mld_create(struct net_pkt *pkt, + const struct in6_addr *addr, + u8_t record_type, + u16_t num_sources) { - int ret; + NET_PKT_DATA_ACCESS_DEFINE(mld_access, + struct net_icmpv6_mld_mcast_record); + struct net_icmpv6_mld_mcast_record *mld; + + mld = (struct net_icmpv6_mld_mcast_record *) + net_pkt_get_data_new(pkt, &mld_access); + if (!mld) { + return -ENOBUFS; + } - append(pkt, u8, record_type); - append(pkt, u8, 0); /* aux data len */ - append(pkt, be16, num_sources); /* number of addresses */ + mld->record_type = record_type; + mld->aux_data_len = 0; + mld->num_sources = htons(num_sources); - append_all(pkt, sizeof(struct in6_addr), addr->s6_addr); + net_ipaddr_copy(&mld->mcast_address, addr); + + if (net_pkt_set_data(pkt, &mld_access)) { + return -ENOBUFS; + } if (num_sources > 0) { /* All source addresses, RFC 3810 ch 3 */ - append_all(pkt, sizeof(struct in6_addr), - net_ipv6_unspecified_address()->s6_addr); + if (net_pkt_write_new(pkt, + net_ipv6_unspecified_address()->s6_addr, + sizeof(struct in6_addr))) { + return -ENOBUFS; + } } - return pkt; - -drop: - return NULL; + return 0; } -static int send_mldv2_raw(struct net_if *iface, struct net_buf *frags) +static int mld_create_packet(struct net_pkt *pkt, u16_t count) { - struct net_pkt *pkt; struct in6_addr dst; - u16_t pos; - int ret; /* Sent to all MLDv2-capable routers */ net_ipv6_addr_create(&dst, 0xff02, 0, 0, 0, 0, 0, 0, 0x0016); - pkt = net_pkt_get_reserve_tx(NET_BUF_TIMEOUT); - if (!pkt) { - return -ENOMEM; + net_pkt_set_ipv6_hop_limit(pkt, 1); /* RFC 3810 ch 7.4 */ + + if (net_ipv6_create_new(pkt, + net_if_ipv6_select_src_addr( + net_pkt_iface(pkt), &dst), + &dst)) { + return -ENOBUFS; } - if (!net_ipv6_create(pkt, - net_if_ipv6_select_src_addr(iface, &dst), - &dst, - iface, - NET_IPV6_NEXTHDR_HBHO)) { - ret = -ENOMEM; - goto drop; + /* Add hop-by-hop option and router alert option, RFC 3810 ch 5. */ + if (net_pkt_write_u8_new(pkt, IPPROTO_ICMPV6) || + net_pkt_write_u8_new(pkt, 0)) { + return -ENOBUFS; } - NET_IPV6_HDR(pkt)->hop_limit = 1; /* RFC 3810 ch 7.4 */ + /* IPv6 router alert option is described in RFC 2711. + * - 0x0502 RFC 2711 ch 2.1 + * - MLD (value 0) + * - 2 bytes of padding + */ + if (net_pkt_write_be16_new(pkt, 0x0502) || + net_pkt_write_be16_new(pkt, 0) || + net_pkt_write_be16_new(pkt, 0)) { + return -ENOBUFS; + } - net_pkt_set_ipv6_hdr_prev(pkt, pkt->frags->len); + net_pkt_set_ipv6_ext_len(pkt, IPV6_OPT_HDR_ROUTER_ALERT_LEN); - /* Add hop-by-hop option and router alert option, RFC 3810 ch 5. */ - append(pkt, u8, IPPROTO_ICMPV6); - append(pkt, u8, 0); /* length (0 means 8 bytes) */ + /* ICMPv6 header + reserved space + count. + * MLDv6 stuff will come right after + */ + if (net_icmpv6_create(pkt, NET_ICMPV6_MLDv2, 0) || + net_pkt_write_be16_new(pkt, 0) || + net_pkt_write_be16_new(pkt, count)) { + return -ENOBUFS; + } - /* IPv6 router alert option is described in RFC 2711. */ - append(pkt, be16, 0x0502); /* RFC 2711 ch 2.1 */ - append(pkt, be16, 0); /* pkt contains MLD msg */ - append(pkt, u8, 0); /* padding */ - append(pkt, u8, 0); /* padding */ + return 0; +} - /* ICMPv6 header */ - append(pkt, u8, NET_ICMPV6_MLDv2); /* type */ - append(pkt, u8, 0); /* code */ - append(pkt, be16, 0); /* chksum */ - append(pkt, be16, 0); /* reserved field */ +static int mld_send(struct net_pkt *pkt) +{ + net_pkt_cursor_init(pkt); -#define ROUTER_ALERT_LEN 8 + net_ipv6_finalize_new(pkt, NET_IPV6_NEXTHDR_HBHO); - net_pkt_set_iface(pkt, iface); + /* IPV6 finalization above could not update ICMPv6 checksum + * due to the existence of Router Alert option in between. + * So let's do it here: + */ + net_pkt_skip(pkt, IPV6_OPT_HDR_ROUTER_ALERT_LEN); - /* Insert the actual multicast record(s) here */ - net_pkt_frag_add(pkt, frags); + net_icmpv6_finalize(pkt); - ret = net_ipv6_finalize(pkt, NET_IPV6_NEXTHDR_HBHO); - if (ret < 0) { - goto drop; - } + if (net_send_data(pkt) < 0) { + net_stats_update_icmp_drop(net_pkt_iface(pkt)); + net_stats_update_ipv6_mld_drop(net_pkt_iface(pkt)); - net_pkt_set_ipv6_ext_len(pkt, ROUTER_ALERT_LEN); + net_pkt_unref(pkt); - if (!net_pkt_write_be16_timeout(pkt, pkt->frags, - NET_IPV6H_LEN + ROUTER_ALERT_LEN + 2, - &pos, - ntohs(net_calc_chksum_icmpv6(pkt)), - NET_BUF_TIMEOUT)) { - ret = -ENOMEM; - goto drop; - } - - ret = net_send_data(pkt); - if (ret < 0) { - goto drop; + return -1; } net_stats_update_icmp_sent(net_pkt_iface(pkt)); net_stats_update_ipv6_mld_sent(net_pkt_iface(pkt)); return 0; - -drop: - net_stats_update_icmp_drop(net_pkt_iface(pkt)); - net_stats_update_ipv6_mld_drop(net_pkt_iface(pkt)); - - net_pkt_unref(pkt); - - return ret; } -static int send_mldv2(struct net_if *iface, const struct in6_addr *addr, - u8_t mode) +static int mld_send_generic(struct net_if *iface, + const struct in6_addr *addr, + u8_t mode) { struct net_pkt *pkt; int ret; - pkt = net_pkt_get_reserve_tx(NET_BUF_TIMEOUT); + pkt = net_pkt_alloc_with_buffer(iface, IPV6_OPT_HDR_ROUTER_ALERT_LEN + + NET_ICMPV6_UNUSED_LEN + + MLDv2_MCAST_RECORD_LEN + + sizeof(struct in6_addr), + AF_INET6, IPPROTO_ICMPV6, + PKT_WAIT_TIME); if (!pkt) { return -ENOMEM; } - append(pkt, be16, 1); /* number of records */ - - if (!create_mldv2(pkt, addr, mode, 1)) { - ret = -ENOMEM; + if (mld_create_packet(pkt, 1) || + mld_create(pkt, addr, mode, 1)) { + ret = -ENOBUFS; goto drop; } - ret = send_mldv2_raw(iface, pkt->frags); + ret = mld_send(pkt); + if (ret) { + goto drop; + } - pkt->frags = NULL; + return 0; drop: net_pkt_unref(pkt); @@ -208,7 +203,7 @@ int net_ipv6_mld_join(struct net_if *iface, const struct in6_addr *addr) } } - ret = send_mldv2(iface, addr, NET_IPV6_MLDv2_MODE_IS_EXCLUDE); + ret = mld_send_generic(iface, addr, NET_IPV6_MLDv2_MODE_IS_EXCLUDE); if (ret < 0) { return ret; } @@ -230,7 +225,7 @@ int net_ipv6_mld_leave(struct net_if *iface, const struct in6_addr *addr) return -EINVAL; } - ret = send_mldv2(iface, addr, NET_IPV6_MLDv2_MODE_IS_INCLUDE); + ret = mld_send_generic(iface, addr, NET_IPV6_MLDv2_MODE_IS_INCLUDE); if (ret < 0) { return ret; } @@ -246,42 +241,44 @@ static void send_mld_report(struct net_if *iface) { struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6; struct net_pkt *pkt; - int i, ret, count = 0; + int i, count = 0; NET_ASSERT(ipv6); - pkt = net_pkt_get_reserve_tx(NET_BUF_TIMEOUT); + for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) { + if (!ipv6->mcast[i].is_used || !ipv6->mcast[i].is_joined) { + continue; + } + + count++; + } + + pkt = net_pkt_alloc_with_buffer(iface, IPV6_OPT_HDR_ROUTER_ALERT_LEN + + NET_ICMPV6_UNUSED_LEN + + count * MLDv2_MCAST_RECORD_LEN, + AF_INET6, IPPROTO_ICMPV6, + PKT_WAIT_TIME); if (!pkt) { return; } - append(pkt, u8, 0); /* This will be the record count */ + if (mld_create_packet(pkt, count)) { + goto drop; + } for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) { if (!ipv6->mcast[i].is_used || !ipv6->mcast[i].is_joined) { continue; } - if (!create_mldv2(pkt, &ipv6->mcast[i].address.in6_addr, - NET_IPV6_MLDv2_MODE_IS_EXCLUDE, 0)) { + if (!mld_create(pkt, &ipv6->mcast[i].address.in6_addr, + NET_IPV6_MLDv2_MODE_IS_EXCLUDE, 0)) { goto drop; } - - count++; } - if (count > 0) { - u16_t pos; - - /* Write back the record count */ - if (!net_pkt_write_u8_timeout(pkt, pkt->frags, 0, &pos, - count, NET_BUF_TIMEOUT)) { - goto drop; - } - - send_mldv2_raw(iface, pkt->frags); - - pkt->frags = NULL; + if (!mld_send(pkt)) { + return; } drop: diff --git a/tests/net/mld/src/main.c b/tests/net/mld/src/main.c index a0812e787d767..574fe8a387f47 100644 --- a/tests/net/mld/src/main.c +++ b/tests/net/mld/src/main.c @@ -96,17 +96,29 @@ static void net_test_iface_init(struct net_if *iface) NET_LINK_ETHERNET); } +static struct net_icmp_hdr *get_icmp_hdr(struct net_pkt *pkt) +{ + net_pkt_cursor_init(pkt); + + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt)); + + return (struct net_icmp_hdr *)net_pkt_cursor_get_pos(pkt); +} + #define NET_ICMP_HDR(pkt) ((struct net_icmp_hdr *)net_pkt_icmp_data(pkt)) static int tester_send(struct device *dev, struct net_pkt *pkt) { - struct net_icmp_hdr *icmp = NET_ICMP_HDR(pkt); + struct net_icmp_hdr *icmp; if (!pkt->frags) { TC_ERROR("No data to send!\n"); return -ENODATA; } + icmp = get_icmp_hdr(pkt); + if (icmp->type == NET_ICMPV6_MLDv2) { /* FIXME, add more checks here */ @@ -353,12 +365,12 @@ static void send_query(struct net_if *iface) net_pkt_append_be16(pkt, 0); /* Resv, S, QRV and QQIC */ net_pkt_append_be16(pkt, 0); /* number of addresses */ + net_pkt_set_ipv6_ext_len(pkt, ROUTER_ALERT_LEN); + net_ipv6_finalize(pkt, NET_IPV6_NEXTHDR_HBHO); net_pkt_set_iface(pkt, iface); - net_pkt_set_ipv6_ext_len(pkt, ROUTER_ALERT_LEN); - net_pkt_write_be16(pkt, pkt->frags, NET_IPV6H_LEN + ROUTER_ALERT_LEN + 2, &pos, ntohs(net_calc_chksum_icmpv6(pkt))); From fb9c76d549d8e462d4c695e70a7bf81a604b447a Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 9 Jan 2019 15:53:07 +0100 Subject: [PATCH 51/70] net/ipv6: Re-enable support for fragmented packet at input Now using the new API. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6.c | 8 +- subsys/net/ip/ipv6.h | 24 ++++-- subsys/net/ip/ipv6_fragment.c | 151 ++++++++++++++++++---------------- 3 files changed, 102 insertions(+), 81 deletions(-) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 6633654822125..2fe2e7c267e63 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -568,7 +568,13 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) break; case NET_IPV6_NEXTHDR_FRAG: - /* Temporarly unsupported */ + if (IS_ENABLED(CONFIG_NET_IPV6_FRAGMENT)) { + net_pkt_set_ipv6_fragment_start( + pkt, net_pkt_get_current_offset(pkt)); + return net_ipv6_handle_fragment_hdr(pkt, hdr, + nexthdr); + } + goto bad_hdr; case NET_IPV6_NEXTHDR_NONE: diff --git a/subsys/net/ip/ipv6.h b/subsys/net/ip/ipv6.h index 9de3e63403526..2b1402e180d8d 100644 --- a/subsys/net/ip/ipv6.h +++ b/subsys/net/ip/ipv6.h @@ -430,21 +430,27 @@ int net_ipv6_find_last_ext_hdr(struct net_pkt *pkt, u16_t *next_hdr_idx, /** * @brief Handles IPv6 fragmented packets. * - * @param pkt Network head packet. - * @param frag Network packet fragment - * @param total_len Total length of the packet - * @param offset Start of fragment header - * @param loc End of fragment header, this is returned to the caller + * @param pkt Network head packet. + * @param hdr The IPv6 header of the current packet * @param nexthdr IPv6 next header after fragment header part * * @return Return verdict about the packet */ enum net_verdict net_ipv6_handle_fragment_hdr(struct net_pkt *pkt, - struct net_buf *frag, - int total_len, - u16_t buf_offset, - u16_t *loc, + struct net_ipv6_hdr *hdr, u8_t nexthdr); +#else +static inline +enum net_verdict net_ipv6_handle_fragment_hdr(struct net_pkt *pkt, + struct net_ipv6_hdr *hdr, + u8_t nexthdr) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(hdr); + ARG_UNUSED(nexthdr); + + return NET_DROP; +} #endif /* CONFIG_NET_IPV6_FRAGMENT */ #if defined(CONFIG_NET_IPV6) diff --git a/subsys/net/ip/ipv6_fragment.c b/subsys/net/ip/ipv6_fragment.c index 44ef01103d647..ca49f16a89268 100644 --- a/subsys/net/ip/ipv6_fragment.c +++ b/subsys/net/ip/ipv6_fragment.c @@ -286,25 +286,29 @@ static void reassembly_timeout(struct k_work *work) static void reassemble_packet(struct net_ipv6_reassembly *reass) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr); + NET_PKT_DATA_ACCESS_DEFINE(frag_access, struct net_ipv6_frag_hdr); + union { + struct net_ipv6_hdr *hdr; + struct net_ipv6_frag_hdr *frag_hdr; + } ipv6; + struct net_pkt *pkt; struct net_buf *last; - struct net_buf *frag; u8_t next_hdr; - int i, len, ret; - u16_t pos; + int i, len; k_delayed_work_cancel(&reass->timer); NET_ASSERT(reass->pkt[0]); - last = net_buf_frag_last(reass->pkt[0]->frags); + last = net_buf_frag_last(reass->pkt[0]->buffer); /* We start from 2nd packet which is then appended to * the first one. */ for (i = 1; i < NET_IPV6_FRAGMENTS_MAX_PKT; i++) { int removed_len; - int ret; pkt = reass->pkt[i]; @@ -315,19 +319,19 @@ static void reassemble_packet(struct net_ipv6_reassembly *reass) sizeof(struct net_ipv6_frag_hdr); NET_DBG("Removing %d bytes from start of pkt %p", - removed_len, pkt->frags); + removed_len, pkt->buffer); - ret = net_pkt_pull(pkt, 0, removed_len); - if (ret) { + if (net_pkt_pull_new(pkt, removed_len)) { NET_ERR("Failed to pull headers"); - NET_ASSERT(ret != 0); + reassembly_cancel(reass->id, &reass->src, &reass->dst); + return; } /* Attach the data to previous pkt */ - last->frags = pkt->frags; - last = net_buf_frag_last(pkt->frags); + last->frags = pkt->buffer; + last = net_buf_frag_last(pkt->buffer); - pkt->frags = NULL; + pkt->buffer = NULL; reass->pkt[i] = NULL; net_pkt_unref(pkt); @@ -339,35 +343,44 @@ static void reassemble_packet(struct net_ipv6_reassembly *reass) /* Next we need to strip away the fragment header from the first packet * and set the various pointers and values in packet. */ + net_pkt_cursor_init(pkt); + + if (net_pkt_skip(pkt, net_pkt_ipv6_fragment_start(pkt))) { + NET_ERR("Failed to move to fragment header"); + goto error; + } - frag = net_frag_read_u8(pkt->frags, net_pkt_ipv6_fragment_start(pkt), - &pos, &next_hdr); - if (!frag && pos == 0xFFFF) { - NET_ERR("Failed to read next header"); - NET_ASSERT(frag); + ipv6.frag_hdr = (struct net_ipv6_frag_hdr *)net_pkt_get_data_new( + pkt, &frag_access); + if (!ipv6.frag_hdr) { + NET_ERR("Failed to get fragment header"); + goto error; } - ret = net_pkt_pull(pkt, net_pkt_ipv6_fragment_start(pkt), - sizeof(struct net_ipv6_frag_hdr)); - if (ret) { - NET_ERR("Failed to pull fragmentation header"); - NET_ASSERT(ret); + next_hdr = ipv6.frag_hdr->nexthdr; + + if (net_pkt_pull_new(pkt, sizeof(struct net_ipv6_frag_hdr))) { + NET_ERR("Failed to remove fragment header"); + goto error; } + net_pkt_cursor_init(pkt); + /* This one updates the previous header's nexthdr value */ - if (!net_pkt_write_u8_timeout(pkt, pkt->frags, - net_pkt_ipv6_hdr_prev(pkt), - &pos, next_hdr, NET_BUF_TIMEOUT)) { - net_pkt_unref(pkt); - return; + if (net_pkt_skip(pkt, net_pkt_ipv6_hdr_prev(pkt)) || + net_pkt_write_u8_new(pkt, next_hdr)) { + goto error; } - if (!net_pkt_compact(pkt)) { - NET_ERR("Cannot compact reassembly packet %p", pkt); - net_pkt_unref(pkt); - return; + net_pkt_cursor_init(pkt); + + ipv6.hdr = (struct net_ipv6_hdr *)net_pkt_get_data_new(pkt, + &ipv6_access); + if (!ipv6.hdr) { + goto error; } + /* Fix the total length of the IPv6 packet. */ len = net_pkt_ipv6_ext_len(pkt); if (len > 0) { @@ -378,7 +391,9 @@ static void reassemble_packet(struct net_ipv6_reassembly *reass) len = net_pkt_get_len(pkt) - sizeof(struct net_ipv6_hdr); - NET_IPV6_HDR(pkt)->len = htons(len); + ipv6.hdr->len = htons(len); + + net_pkt_set_data(pkt, &ipv6_access); NET_DBG("New pkt %p IPv6 len is %d bytes", pkt, len); @@ -388,10 +403,11 @@ static void reassemble_packet(struct net_ipv6_reassembly *reass) * MUST NOT pass it to L2 so there will be a special check for that * in process_data() when handling the packet. */ - ret = net_recv_data(net_pkt_iface(pkt), pkt); - if (ret < 0) { - net_pkt_unref(pkt); + if (net_recv_data(net_pkt_iface(pkt), pkt) >= 0) { + return; } +error: + net_pkt_unref(pkt); } void net_ipv6_frag_foreach(net_ipv6_frag_cb_t cb, void *user_data) @@ -471,18 +487,14 @@ static int shift_packets(struct net_ipv6_reassembly *reass, int pos) } enum net_verdict net_ipv6_handle_fragment_hdr(struct net_pkt *pkt, - struct net_buf *frag, - int total_len, - u16_t buf_offset, - u16_t *loc, + struct net_ipv6_hdr *hdr, u8_t nexthdr) { struct net_ipv6_reassembly *reass = NULL; - u32_t id; - u16_t offset; u16_t flag; - u8_t more; bool found; + u8_t more; + u32_t id; int i; if (!reassembly_init_done) { @@ -497,29 +509,29 @@ enum net_verdict net_ipv6_handle_fragment_hdr(struct net_pkt *pkt, reassembly_init_done = true; } - /* Each fragment has a fragment header. */ - frag = net_frag_skip(frag, buf_offset, loc, 1); /* reserved */ - frag = net_frag_read_be16(frag, *loc, loc, &flag); - frag = net_frag_read_be32(frag, *loc, loc, &id); - if (!frag && *loc == 0xffff) { + /* Each fragment has a fragment header, however since we already + * read the nexthdr part of it, we are not going to use + * net_pkt_get_data_new() and access the header directly: the cursor + * being 1 byte too far, let's just read the next relevant pieces. + */ + if (net_pkt_skip(pkt, 1) || /* reserved */ + net_pkt_read_be16_new(pkt, &flag) || + net_pkt_read_be32_new(pkt, &id)) { goto drop; } - reass = reassembly_get(id, &NET_IPV6_HDR(pkt)->src, - &NET_IPV6_HDR(pkt)->dst); + reass = reassembly_get(id, &hdr->src, &hdr->dst); if (!reass) { NET_DBG("Cannot get reassembly slot, dropping pkt %p", pkt); goto drop; } - offset = flag & 0xfff8; more = flag & 0x01; - - net_pkt_set_ipv6_fragment_offset(pkt, offset); + net_pkt_set_ipv6_fragment_offset(pkt, flag & 0xfff8); if (!reass->pkt[0]) { - NET_DBG("Storing pkt %p to slot %d offset 0x%x", pkt, 0, - offset); + NET_DBG("Storing pkt %p to slot %d offset 0x%x", + pkt, 0, net_pkt_ipv6_fragment_offset(pkt)); reass->pkt[0] = pkt; reassembly_info("Reassembly 1st pkt", reass); @@ -532,28 +544,25 @@ enum net_verdict net_ipv6_handle_fragment_hdr(struct net_pkt *pkt, * in reassembly chain in correct order. */ for (i = 0, found = false; i < NET_IPV6_FRAGMENTS_MAX_PKT; i++) { - if (!reass->pkt[i]) { - NET_DBG("Storing pkt %p to slot %d offset 0x%x", pkt, - i, offset); - reass->pkt[i] = pkt; - found = true; - break; - } - - if (net_pkt_ipv6_fragment_offset(reass->pkt[i]) < offset) { - continue; - } + if (reass->pkt[i]) { + if (net_pkt_ipv6_fragment_offset(reass->pkt[i]) < + net_pkt_ipv6_fragment_offset(pkt)) { + continue; + } - /* Make room for this fragment, if there is no room, then - * discard the whole reassembly. - */ - if (shift_packets(reass, i)) { - break; + /* Make room for this fragment. If there is no room, + * then it will discard the whole reassembly. + */ + if (shift_packets(reass, i)) { + break; + } } - NET_DBG("Storing %p (offset 0x%x) to [%d]", pkt, offset, i); + NET_DBG("Storing pkt %p to slot %d offset 0x%x", + pkt, i, net_pkt_ipv6_fragment_offset(pkt)); reass->pkt[i] = pkt; found = true; + break; } From 510f769408621c7255871ecd364672b830fa7245 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 10 Jan 2019 20:57:21 +0100 Subject: [PATCH 52/70] net/ipv6: Switch sending fragmented IPv6 packet to new API This optimizes the memory quite a bit since we do not need to clone nor split the original packet at any time. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv6.c | 8 +- subsys/net/ip/ipv6.h | 17 +- subsys/net/ip/ipv6_fragment.c | 366 +++++++++-------------------- tests/net/ipv6_fragment/src/main.c | 12 + 4 files changed, 141 insertions(+), 262 deletions(-) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 2fe2e7c267e63..bfb27a9639cde 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -320,12 +320,6 @@ static inline int ipv6_handle_ext_hdr_options(struct net_pkt *pkt, return exthdr_len; } -static inline bool ipv6_nexthdr_is_upper_layer(u8_t proto) -{ - return (proto == IPPROTO_ICMPV6 || proto == IPPROTO_UDP || - proto == IPPROTO_TCP); -} - #if defined(CONFIG_NET_ROUTE) static struct net_route_entry *add_route(struct net_if *iface, struct in6_addr *addr, @@ -528,7 +522,7 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) net_pkt_acknowledge_data(pkt, &ipv6_access); nexthdr = hdr->nexthdr; - while (!ipv6_nexthdr_is_upper_layer(nexthdr)) { + while (!net_ipv6_is_nexthdr_upper_layer(nexthdr)) { u16_t exthdr_len; NET_DBG("IPv6 next header %d", nexthdr); diff --git a/subsys/net/ip/ipv6.h b/subsys/net/ip/ipv6.h index 2b1402e180d8d..9aa21e479e1e9 100644 --- a/subsys/net/ip/ipv6.h +++ b/subsys/net/ip/ipv6.h @@ -128,6 +128,13 @@ int net_ipv6_send_na(struct net_if *iface, const struct in6_addr *src, const struct in6_addr *dst, const struct in6_addr *tgt, u8_t flags); + +static inline bool net_ipv6_is_nexthdr_upper_layer(u8_t nexthdr) +{ + return (nexthdr == IPPROTO_ICMPV6 || nexthdr == IPPROTO_UDP || + nexthdr == IPPROTO_TCP); +} + /** * @brief Create IPv6 packet in provided net_pkt. * @@ -417,15 +424,15 @@ void net_ipv6_frag_foreach(net_ipv6_frag_cb_t cb, void *user_data); * @brief Find the last IPv6 extension header in the network packet. * * @param pkt Network head packet. - * @param next_hdr_idx Where is the index to next header field that points + * @param next_hdr_off Offset of the next header field that points * to last header. This is returned to caller. - * @param last_hdr_idx Where is the last header field in the packet. + * @param last_hdr_off Offset of the last header field in the packet. * This is returned to caller. * - * @return Return 0 if ok or <0 if the packet is malformed. + * @return 0 on success, a negative errno otherwise. */ -int net_ipv6_find_last_ext_hdr(struct net_pkt *pkt, u16_t *next_hdr_idx, - u16_t *last_hdr_idx); +int net_ipv6_find_last_ext_hdr(struct net_pkt *pkt, u16_t *next_hdr_off, + u16_t *last_hdr_off); /** * @brief Handles IPv6 fragmented packets. diff --git a/subsys/net/ip/ipv6_fragment.c b/subsys/net/ip/ipv6_fragment.c index ca49f16a89268..8d8634d67f62b 100644 --- a/subsys/net/ip/ipv6_fragment.c +++ b/subsys/net/ip/ipv6_fragment.c @@ -46,133 +46,80 @@ static bool reassembly_init_done; static struct net_ipv6_reassembly reassembly[CONFIG_NET_IPV6_FRAGMENT_MAX_COUNT]; -int net_ipv6_find_last_ext_hdr(struct net_pkt *pkt, u16_t *next_hdr_idx, - u16_t *last_hdr_idx) +int net_ipv6_find_last_ext_hdr(struct net_pkt *pkt, u16_t *next_hdr_off, + u16_t *last_hdr_off) { - struct net_buf *next_hdr_frag; - struct net_buf *last_hdr_frag; - struct net_buf *frag; - u16_t pkt_offset; - u16_t offset; + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr); + struct net_ipv6_hdr *hdr; + u8_t next_nexthdr; + u8_t nexthdr; u16_t length; - u8_t next_hdr; - u8_t next; - if (!pkt || !pkt->frags || !next_hdr_idx || !last_hdr_idx) { + if (!pkt || !pkt->frags || !next_hdr_off || !last_hdr_off) { return -EINVAL; } - next = NET_IPV6_HDR(pkt)->nexthdr; - - /* Initial value if no extension fragments are found */ - *next_hdr_idx = 6U; - *last_hdr_idx = sizeof(struct net_ipv6_hdr); + net_pkt_cursor_init(pkt); - /* First check the simplest case where there is no extension headers - * in the packet. There cannot be any extensions after the normal or - * typical IP protocols - */ - if (next == IPPROTO_ICMPV6 || next == IPPROTO_UDP || - next == IPPROTO_TCP || next == NET_IPV6_NEXTHDR_NONE) { - return 0; + hdr = (struct net_ipv6_hdr *)net_pkt_get_data_new(pkt, &ipv6_access); + if (!hdr) { + return -ENOBUFS; } - frag = pkt->frags; - offset = *last_hdr_idx; - *next_hdr_idx = *last_hdr_idx; - next_hdr_frag = last_hdr_frag = frag; + net_pkt_acknowledge_data(pkt, &ipv6_access); - while (frag) { - frag = net_frag_read_u8(frag, offset, &offset, &next_hdr); - if (!frag) { - goto fail; - } + nexthdr = hdr->nexthdr; - switch (next) { - case NET_IPV6_NEXTHDR_FRAG: - frag = net_frag_skip(frag, offset, &offset, 7); - if (!frag) { - goto fail; - } + /* Initial values */ + *next_hdr_off = offsetof(struct net_ipv6_hdr, nexthdr); + *last_hdr_off = sizeof(struct net_ipv6_hdr); - break; + nexthdr = hdr->nexthdr; + while (!net_ipv6_is_nexthdr_upper_layer(nexthdr)) { + if (net_pkt_read_u8_new(pkt, &next_nexthdr)) { + goto fail; + } + switch (nexthdr) { case NET_IPV6_NEXTHDR_HBHO: case NET_IPV6_NEXTHDR_DESTO: length = 0U; - frag = net_frag_read_u8(frag, offset, &offset, - (u8_t *)&length); - if (!frag) { + + if (net_pkt_read_u8_new(pkt, (u8_t *)&length)) { goto fail; } - length = length * 8 + 8; + length = length * 8 + 8 - 2; - frag = net_frag_skip(frag, offset, &offset, length - 2); - if (!frag) { + if (net_pkt_skip(pkt, length)) { goto fail; } break; + case NET_IPV6_NEXTHDR_FRAG: + if (net_pkt_skip(pkt, 7)) { + goto fail; + } + break; case NET_IPV6_NEXTHDR_NONE: - case IPPROTO_ICMPV6: - case IPPROTO_UDP: - case IPPROTO_TCP: goto out; - default: /* TODO: Add more IPv6 extension headers to check */ goto fail; } - *next_hdr_idx = *last_hdr_idx; - next_hdr_frag = last_hdr_frag; + *next_hdr_off = *last_hdr_off; + *last_hdr_off = net_pkt_get_current_offset(pkt); - *last_hdr_idx = offset; - last_hdr_frag = frag; - - next = next_hdr; + nexthdr = next_nexthdr; } - -fail: - return -EINVAL; - out: - /* Current next_hdr_idx offset is based on respective fragment, but we - * need to calculate next_hdr_idx offset based on whole packet. - */ - pkt_offset = 0U; - frag = pkt->frags; - while (frag) { - if (next_hdr_frag == frag) { - *next_hdr_idx += pkt_offset; - break; - } - - pkt_offset += frag->len; - frag = frag->frags; - } - - /* Current last_hdr_idx offset is based on respective fragment, but we - * need to calculate last_hdr_idx offset based on whole packet. - */ - pkt_offset = 0U; - frag = pkt->frags; - while (frag) { - if (last_hdr_frag == frag) { - *last_hdr_idx += pkt_offset; - break; - } - - pkt_offset += frag->len; - frag = frag->frags; - } - return 0; +fail: + return -EINVAL; } - static struct net_ipv6_reassembly *reassembly_get(u32_t id, struct in6_addr *src, struct in6_addr *dst) @@ -624,124 +571,76 @@ enum net_verdict net_ipv6_handle_fragment_hdr(struct net_pkt *pkt, #define BUF_ALLOC_TIMEOUT K_MSEC(100) -static int send_ipv6_fragment(struct net_if *iface, - struct net_pkt *pkt, - struct net_buf **rest, - u16_t ipv6_hdrs_len, +static int send_ipv6_fragment(struct net_pkt *pkt, u16_t fit_len, u16_t frag_offset, + u16_t next_hdr_off, u8_t next_hdr, - u16_t next_hdr_idx, - u8_t last_hdr, - u16_t last_hdr_idx, - u16_t frag_count) + bool final) { - struct net_pkt *ipv6 = NULL; - bool final; - struct net_ipv6_frag_hdr hdr; - struct net_buf *frag; - struct net_buf *temp; - u16_t pos; - bool res; - int ret; - - ipv6 = net_pkt_clone(pkt, BUF_ALLOC_TIMEOUT); - if (!ipv6) { - NET_DBG("Cannot clone %p", ipv6); + NET_PKT_DATA_ACCESS_DEFINE(frag_access, struct net_ipv6_frag_hdr); + int ret = -ENOBUFS; + struct net_ipv6_frag_hdr *frag_hdr; + struct net_pkt *frag_pkt; + + frag_pkt = net_pkt_alloc_with_buffer(net_pkt_iface(pkt), fit_len + + net_pkt_ipv6_ext_len(pkt) + + NET_IPV6_FRAGH_LEN, + AF_INET6, 0, BUF_ALLOC_TIMEOUT); + if (!frag_pkt) { return -ENOMEM; } - /* And we need to update the last header in the IPv6 packet to point to - * fragment header. - */ - temp = net_pkt_write_u8_timeout(ipv6, ipv6->frags, next_hdr_idx, &pos, - NET_IPV6_NEXTHDR_FRAG, - BUF_ALLOC_TIMEOUT); - if (!temp) { - if (pos == 0xffff) { - ret = -EINVAL; - } else { - ret = -ENOMEM; - } - - goto fail; - } + net_pkt_cursor_init(pkt); - /* Update the extension length metadata so that upper layer checksum - * will be calculated properly by net_ipv6_finalize(). + /* We copy original headers back to the fragment packet + * Note that we insert the right next header to point to fragment header */ - net_pkt_set_ipv6_ext_len(ipv6, - net_pkt_ipv6_ext_len(pkt) + - sizeof(struct net_ipv6_frag_hdr)); - - frag = *rest; - if (fit_len < net_buf_frags_len(*rest)) { - ret = net_pkt_split(pkt, frag, fit_len, rest, FRAG_BUF_WAIT); - if (ret < 0) { - net_buf_unref(frag); - goto fail; - } - } else { - *rest = NULL; + if (net_pkt_copy_new(frag_pkt, pkt, next_hdr_off) || + net_pkt_write_u8_new(frag_pkt, NET_IPV6_NEXTHDR_FRAG) || + net_pkt_skip(pkt, 1) || + net_pkt_copy_new(frag_pkt, pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) - next_hdr_off - 1)) { + goto fail; } - final = false; - /* *rest == NULL means no more data to send */ - if (!*rest) { - final = true; + /* And we append the fragmentation header */ + frag_hdr = (struct net_ipv6_frag_hdr *)net_pkt_get_data_new( + frag_pkt, &frag_access); + if (!frag_hdr) { + goto fail; } - /* Append the Fragmentation Header */ - hdr.nexthdr = next_hdr; - hdr.reserved = 0; - hdr.id = net_pkt_ipv6_fragment_id(pkt); - hdr.offset = htons(((frag_offset / 8) << 3) | !final); + frag_hdr->nexthdr = next_hdr; + frag_hdr->reserved = 0; + frag_hdr->id = net_pkt_ipv6_fragment_id(pkt); + frag_hdr->offset = htons(((frag_offset / 8) << 3) | !final); - res = net_pkt_append_all(ipv6, sizeof(struct net_ipv6_frag_hdr), - (u8_t *)&hdr, FRAG_BUF_WAIT); - if (!res) { - net_buf_unref(frag); - ret = EINVAL; + if (net_pkt_set_data(frag_pkt, &frag_access)) { goto fail; } - /* Attach the first part of split payload to end of the packet. And - * "rest" of the packet will be sent in next iteration. - */ - temp = ipv6->frags; - while (1) { - if (!temp->frags) { - temp->frags = frag; - break; - } - - temp = temp->frags; - } + net_pkt_set_ipv6_ext_len(frag_pkt, + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_ipv6_frag_hdr)); - res = net_pkt_compact(ipv6); - if (!res) { - ret = -EINVAL; + /* Finally we copy the payload part of this fragment from + * the original packet + */ + if (net_pkt_skip(pkt, frag_offset) || + net_pkt_copy_new(frag_pkt, pkt, fit_len)) { goto fail; } - /* Note that we must not calculate possible UDP/TCP/ICMPv6 checksum - * as that is already calculated in the non-fragmented packet. - */ - ret = net_ipv6_finalize(ipv6, NET_IPV6_NEXTHDR_FRAG); - if (ret < 0) { - NET_DBG("Cannot create IPv6 packet (%d)", ret); + net_pkt_cursor_init(frag_pkt); + + if (net_ipv6_finalize_new(frag_pkt, 0) < 0) { goto fail; } - /* If everything has been ok so far, we can send the packet. - * Note that we cannot send this re-constructed packet directly - * as the link layer headers will not be properly set (because - * we recreated the packet). So pass this packet back to TX - * so that the pkt is going back to L2 for setup. - */ - ret = net_send_data(ipv6); + /* If everything has been ok so far, we can send the packet. */ + ret = net_send_data(frag_pkt); if (ret < 0) { - NET_DBG("Cannot send fragment (%d)", ret); goto fail; } @@ -753,9 +652,8 @@ static int send_ipv6_fragment(struct net_if *iface, return 0; fail: - if (ipv6) { - net_pkt_unref(ipv6); - } + NET_DBG("Cannot send fragment (%d)", ret); + net_pkt_unref(frag_pkt); return ret; } @@ -763,97 +661,65 @@ static int send_ipv6_fragment(struct net_if *iface, int net_ipv6_send_fragmented_pkt(struct net_if *iface, struct net_pkt *pkt, u16_t pkt_len) { - struct net_buf *rest = NULL; - struct net_pkt *clone; - struct net_buf *temp; - u16_t next_hdr_idx; - u16_t last_hdr_idx; - u16_t ipv6_hdrs_len; + u16_t next_hdr_off; + u16_t last_hdr_off; u16_t frag_offset; - u16_t frag_count; - u16_t pos; + size_t length; u8_t next_hdr; u8_t last_hdr; int fit_len; - int ret = -EINVAL; - - /* We cannot touch original pkt because it might be used for - * some other purposes, like TCP resend etc. So we need to copy - * the large pkt here and do the fragmenting with the clone. - */ - clone = net_pkt_clone(pkt, BUF_ALLOC_TIMEOUT); - if (!clone) { - NET_DBG("Cannot clone %p", pkt); - return -ENOMEM; - } + int ret; - pkt = clone; net_pkt_set_ipv6_fragment_id(pkt, sys_rand32_get()); - ret = net_ipv6_find_last_ext_hdr(pkt, &next_hdr_idx, &last_hdr_idx); + ret = net_ipv6_find_last_ext_hdr(pkt, &next_hdr_off, &last_hdr_off); if (ret < 0) { - goto fail; + return ret; } - temp = net_frag_read_u8(pkt->frags, next_hdr_idx, &pos, &next_hdr); - if (!temp && pos == 0xffff) { - ret = -EINVAL; - goto fail; - } - - temp = net_frag_read_u8(pkt->frags, last_hdr_idx, &pos, &last_hdr); - if (!temp && pos == 0xffff) { - ret = -EINVAL; - goto fail; - } - - ipv6_hdrs_len = net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt); + net_pkt_cursor_init(pkt); - ret = net_pkt_split(pkt, pkt->frags, ipv6_hdrs_len, &rest, - FRAG_BUF_WAIT); - if (ret < 0 || ipv6_hdrs_len != net_pkt_get_len(pkt)) { - NET_DBG("Cannot split packet (%d)", ret); - goto fail; + if (net_pkt_skip(pkt, next_hdr_off) || + net_pkt_read_u8_new(pkt, &next_hdr) || + net_pkt_skip(pkt, last_hdr_off) || + net_pkt_read_u8_new(pkt, &last_hdr)) { + return -ENOBUFS; } - frag_count = 0U; - frag_offset = 0U; - /* The Maximum payload can fit into each packet after IPv6 header, * Extenstion headers and Fragmentation header. */ - fit_len = NET_IPV6_MTU - NET_IPV6_FRAGH_LEN - ipv6_hdrs_len; + fit_len = NET_IPV6_MTU - NET_IPV6_FRAGH_LEN - + (net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt)); if (fit_len <= 0) { /* Must be invalid extension headers length */ NET_DBG("No room for IPv6 payload MTU %d hdrs_len %d", - NET_IPV6_MTU, NET_IPV6_FRAGH_LEN + ipv6_hdrs_len); - ret = -EINVAL; - goto fail; + NET_IPV6_MTU, NET_IPV6_FRAGH_LEN + + net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt)); + return -EINVAL; } - while (rest) { - ret = send_ipv6_fragment(iface, pkt, &rest, ipv6_hdrs_len, - fit_len, frag_offset, next_hdr, - next_hdr_idx, last_hdr, last_hdr_idx, - frag_count); + frag_offset = 0U; + + length = net_pkt_get_len(pkt) - + (net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt)); + while (length) { + bool final = false; + + if (fit_len >= length) { + final = true; + fit_len = length; + } + + ret = send_ipv6_fragment(pkt, fit_len, frag_offset, + next_hdr_off, next_hdr, final); if (ret < 0) { - goto fail; + return ret; } - frag_count++; + length -= fit_len; frag_offset += fit_len; } - net_pkt_unref(pkt); - return 0; - -fail: - net_pkt_unref(pkt); - - if (rest) { - net_buf_unref(rest); - } - - return ret; } diff --git a/tests/net/ipv6_fragment/src/main.c b/tests/net/ipv6_fragment/src/main.c index 42fbbaffa6317..981d292a6d77d 100644 --- a/tests/net/ipv6_fragment/src/main.c +++ b/tests/net/ipv6_fragment/src/main.c @@ -1355,6 +1355,8 @@ static void test_find_last_ipv6_fragment_hbho_2(void) ALLOC_TIMEOUT); zassert_true(ret, "IPv6 header append failed"); + net_pkt_set_overwrite(pkt, true); + net_pkt_lladdr_clear(pkt); ret = net_ipv6_find_last_ext_hdr(pkt, &next_hdr_idx, &last_hdr_pos); @@ -1398,6 +1400,8 @@ static void test_find_last_ipv6_fragment_hbho_3(void) ALLOC_TIMEOUT); zassert_true(ret, "IPv6 header append failed"); + net_pkt_set_overwrite(pkt, true); + net_pkt_lladdr_clear(pkt); ret = net_ipv6_find_last_ext_hdr(pkt, &next_hdr_idx, &last_hdr_pos); @@ -1438,6 +1442,8 @@ static void test_find_last_ipv6_fragment_hbho_frag(void) ALLOC_TIMEOUT); zassert_true(ret, "IPv6 header append failed"); + net_pkt_set_overwrite(pkt, true); + net_pkt_lladdr_clear(pkt); ret = net_ipv6_find_last_ext_hdr(pkt, &next_hdr_idx, &last_hdr_pos); @@ -1477,6 +1483,8 @@ static void test_find_last_ipv6_fragment_hbho_frag_1(void) ipv6_hbho_frag_1, ALLOC_TIMEOUT); zassert_true(ret, "IPv6 header append failed"); + net_pkt_set_overwrite(pkt, true); + net_pkt_lladdr_clear(pkt); ret = net_ipv6_find_last_ext_hdr(pkt, &next_hdr_idx, &last_hdr_pos); @@ -1548,6 +1556,8 @@ static void test_send_ipv6_fragment(void) NET_IPV6_HDR(pkt)->len = htons(total_len); + net_pkt_set_overwrite(pkt, true); + net_udp_set_chksum(pkt, pkt->frags); test_failed = false; @@ -1586,6 +1596,8 @@ static void test_send_ipv6_fragment_large_hbho(void) ipv6_large_hbho, ALLOC_TIMEOUT); zassert_true(ret, "IPv6 header append failed"); + net_pkt_set_overwrite(pkt, true); + net_pkt_lladdr_clear(pkt); total_len = net_pkt_get_len(pkt) - sizeof(struct net_ipv6_hdr); From 3dad8612d6d53eaa207965c3b51f42c2335fd9cb Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 11 Jan 2019 12:05:16 +0100 Subject: [PATCH 53/70] net/ipv4: Move autoconf to new net_pkt API Only the allocator needed to be changed here. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv4_autoconf.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/subsys/net/ip/ipv4_autoconf.c b/subsys/net/ip/ipv4_autoconf.c index 789d93f642e14..e7e5933443ed9 100644 --- a/subsys/net/ip/ipv4_autoconf.c +++ b/subsys/net/ip/ipv4_autoconf.c @@ -33,32 +33,21 @@ static struct net_pkt *ipv4_autoconf_prepare_arp(struct net_if *iface) { struct net_if_config *cfg = net_if_get_config(iface); struct net_pkt *pkt; - struct net_buf *frag; - pkt = net_pkt_get_reserve_tx(BUF_ALLOC_TIMEOUT); + /* We provide AF_UNSPEC to the allocator: this packet does not + * need space for any IPv4 header. + */ + pkt = net_pkt_alloc_with_buffer(iface, sizeof(struct net_arp_hdr), + AF_UNSPEC, 0, BUF_ALLOC_TIMEOUT); if (!pkt) { - goto fail; + return NULL; } - frag = net_pkt_get_frag(pkt, BUF_ALLOC_TIMEOUT); - if (!frag) { - goto fail; - } - - net_pkt_frag_add(pkt, frag); - net_pkt_set_iface(pkt, iface); net_pkt_set_family(pkt, AF_INET); net_pkt_set_ipv4_auto(pkt, true); return net_arp_prepare(pkt, &cfg->ipv4auto.requested_ip, &cfg->ipv4auto.current_ip); - -fail: - if (pkt) { - net_pkt_unref(pkt); - } - - return NULL; } static void ipv4_autoconf_send_probe(struct net_if_ipv4_autoconf *ipv4auto) From 27d464e84b4eecddae4717564bb0dc05fded9283 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 11 Jan 2019 12:12:40 +0100 Subject: [PATCH 54/70] net/arp: Switch ARP to new net_pkt API Only the allocators needed to be changed there. Signed-off-by: Tomasz Bursztyka --- subsys/net/l2/ethernet/arp.c | 46 +++++++++--------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/subsys/net/l2/ethernet/arp.c b/subsys/net/l2/ethernet/arp.c index ff0d7e792614d..7e754219cc3bf 100644 --- a/subsys/net/l2/ethernet/arp.c +++ b/subsys/net/l2/ethernet/arp.c @@ -235,9 +235,9 @@ static inline struct net_pkt *arp_prepare(struct net_if *iface, struct net_pkt *pending, struct in_addr *current_ip) { - struct net_pkt *pkt; struct net_arp_hdr *hdr; struct in_addr *my_addr; + struct net_pkt *pkt; if (current_ip) { /* This is the IPv4 autoconf case where we have already @@ -245,27 +245,17 @@ static inline struct net_pkt *arp_prepare(struct net_if *iface, */ pkt = pending; } else { - struct net_buf *frag; - - pkt = net_pkt_get_reserve_tx(NET_BUF_TIMEOUT); + pkt = net_pkt_alloc_with_buffer(iface, + sizeof(struct net_arp_hdr), + AF_UNSPEC, 0, NET_BUF_TIMEOUT); if (!pkt) { return NULL; } - - frag = net_pkt_get_frag(pkt, NET_BUF_TIMEOUT); - if (!frag) { - net_pkt_unref(pkt); - return NULL; - } - - net_pkt_frag_add(pkt, frag); - net_pkt_set_iface(pkt, iface); - net_pkt_set_family(pkt, AF_UNSPEC); } net_pkt_set_vlan_tag(pkt, net_eth_get_vlan_tag(iface)); - net_buf_add(pkt->frags, sizeof(struct net_arp_hdr)); + net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr)); hdr = NET_ARP_HDR(pkt); @@ -329,7 +319,7 @@ struct net_pkt *net_arp_prepare(struct net_pkt *pkt, struct arp_entry *entry; struct in_addr *addr; - if (!pkt || !pkt->frags) { + if (!pkt || !pkt->buffer) { return NULL; } @@ -468,24 +458,16 @@ static inline struct net_pkt *arp_prepare_reply(struct net_if *iface, struct net_pkt *req, struct net_eth_hdr *eth_query) { - struct net_pkt *pkt; - struct net_buf *frag; struct net_arp_hdr *hdr, *query; + struct net_pkt *pkt; - pkt = net_pkt_get_reserve_tx(NET_BUF_TIMEOUT); + pkt = net_pkt_alloc_with_buffer(iface, sizeof(struct net_arp_hdr), + AF_UNSPEC, 0, NET_BUF_TIMEOUT); if (!pkt) { - goto fail; - } - - net_pkt_set_iface(pkt, iface); - net_pkt_set_family(pkt, AF_UNSPEC); - - frag = net_pkt_get_frag(pkt, NET_BUF_TIMEOUT); - if (!frag) { - goto fail; + return NULL; } - net_pkt_frag_add(pkt, frag); + net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr)); hdr = NET_ARP_HDR(pkt); query = NET_ARP_HDR(req); @@ -512,13 +494,7 @@ static inline struct net_pkt *arp_prepare_reply(struct net_if *iface, net_pkt_lladdr_dst(pkt)->addr = (u8_t *)&hdr->dst_hwaddr.addr; net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr); - net_buf_add(frag, sizeof(struct net_arp_hdr)); - return pkt; - -fail: - net_pkt_unref(pkt); - return NULL; } static bool arp_hdr_check(struct net_arp_hdr *arp_hdr) From b580d6a23a5653550dcf77e967841b97fbd42681 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 11 Jan 2019 12:35:12 +0100 Subject: [PATCH 55/70] net/gptp: Switch GPTP to new net_pkt API Allocation and a minor writing logic needed to be changed. Signed-off-by: Tomasz Bursztyka --- subsys/net/l2/ethernet/gptp/gptp_messages.c | 77 +++++++++------------ 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.c b/subsys/net/l2/ethernet/gptp/gptp_messages.c index 048c19f84c621..4c6cbb7522ee3 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.c +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.c @@ -143,40 +143,33 @@ static void gptp_pdelay_response_timestamp_callback(struct net_pkt *pkt) #if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC) static struct net_pkt *setup_gptp_frame_debug(struct net_if *iface, + size_t extra_header, const char *caller, int line) -#define setup_gptp_frame(iface) \ - setup_gptp_frame_debug(iface, __func__, __LINE__) +#define setup_gptp_frame(iface, extra_header) \ + setup_gptp_frame_debug(iface, extra_header, __func__, __LINE__) #else -static struct net_pkt *setup_gptp_frame(struct net_if *iface) +static struct net_pkt *setup_gptp_frame(struct net_if *iface, + size_t extra_header) #endif { struct net_pkt *pkt; - struct net_buf *frag; #if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC) + pkt = net_pkt_alloc_with_buffer_debug(iface, sizeof(struct gptp_hdr) + + extra_header, AF_UNSPEC, 0, + NET_BUF_TIMEOUT, caller, line); pkt = net_pkt_get_reserve_tx_debug(NET_BUF_TIMEOUT, caller, line); #else - pkt = net_pkt_get_reserve_tx(NET_BUF_TIMEOUT); + pkt = net_pkt_alloc_with_buffer(iface, sizeof(struct gptp_hdr) + + extra_header, AF_UNSPEC, 0, + NET_BUF_TIMEOUT); #endif if (!pkt) { return NULL; } -#if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC) - frag = net_pkt_get_reserve_tx_data_debug(NET_BUF_TIMEOUT, caller, - line); -#else - frag = net_pkt_get_reserve_tx_data(NET_BUF_TIMEOUT); -#endif - if (!frag) { - net_pkt_unref(pkt); - return NULL; - } - - net_pkt_frag_add(pkt, frag); - net_pkt_set_iface(pkt, iface); - net_pkt_set_family(pkt, AF_UNSPEC); + net_buf_add(pkt->buffer, sizeof(struct gptp_hdr) + extra_header); net_pkt_set_gptp(pkt, true); net_pkt_lladdr_src(pkt)->addr = (u8_t *)net_if_get_link_addr(iface); @@ -185,8 +178,6 @@ static struct net_pkt *setup_gptp_frame(struct net_if *iface) net_pkt_lladdr_dst(pkt)->addr = (u8_t *)&gptp_multicast_eth_addr; net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr); - net_buf_add(frag, sizeof(struct gptp_hdr)); - return pkt; } @@ -202,7 +193,7 @@ struct net_pkt *gptp_prepare_sync(int port) iface = GPTP_PORT_IFACE(port); NET_ASSERT(iface); - pkt = setup_gptp_frame(iface); + pkt = setup_gptp_frame(iface, sizeof(struct gptp_sync)); if (!pkt) { NET_DBG("Cannot get gPTP frame"); return NULL; @@ -239,8 +230,6 @@ struct net_pkt *gptp_prepare_sync(int port) /* PTP configuration. */ (void)memset(&sync->reserved, 0, sizeof(sync->reserved)); - net_buf_add(pkt->frags, sizeof(struct gptp_sync)); - /* Update sequence number. */ port_ds->sync_seq_id++; @@ -259,7 +248,7 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) iface = GPTP_PORT_IFACE(port); NET_ASSERT(iface); - pkt = setup_gptp_frame(iface); + pkt = setup_gptp_frame(iface, sizeof(struct gptp_follow_up)); if (!pkt) { NET_DBG("Cannot get gPTP frame"); return NULL; @@ -296,8 +285,6 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) /* PTP configuration will be set by the MDSyncSend state machine. */ - net_buf_add(pkt->frags, sizeof(struct gptp_follow_up)); - return pkt; } @@ -313,7 +300,7 @@ struct net_pkt *gptp_prepare_pdelay_req(int port) iface = GPTP_PORT_IFACE(port); NET_ASSERT(iface); - pkt = setup_gptp_frame(iface); + pkt = setup_gptp_frame(iface, sizeof(struct gptp_pdelay_req)); if (!pkt) { NET_DBG("Cannot get gPTP frame"); return NULL; @@ -353,8 +340,6 @@ struct net_pkt *gptp_prepare_pdelay_req(int port) (void)memset(&req->reserved1, 0, sizeof(req->reserved1)); (void)memset(&req->reserved2, 0, sizeof(req->reserved2)); - net_buf_add(pkt->frags, sizeof(struct gptp_pdelay_req)); - /* Update sequence number. */ port_ds->pdelay_req_seq_id++; @@ -371,7 +356,7 @@ struct net_pkt *gptp_prepare_pdelay_resp(int port, struct gptp_port_ds *port_ds; struct net_pkt *pkt; - pkt = setup_gptp_frame(iface); + pkt = setup_gptp_frame(iface, sizeof(struct gptp_pdelay_resp)); if (!pkt) { NET_DBG("Cannot get gPTP frame"); return NULL; @@ -419,8 +404,6 @@ struct net_pkt *gptp_prepare_pdelay_resp(int port, memcpy(&pdelay_resp->requesting_port_id, &query->port_id, sizeof(struct gptp_port_identity)); - net_buf_add(pkt->frags, sizeof(struct gptp_pdelay_resp)); - return pkt; } @@ -434,7 +417,8 @@ struct net_pkt *gptp_prepare_pdelay_follow_up(int port, struct gptp_port_ds *port_ds; struct net_pkt *pkt; - pkt = setup_gptp_frame(iface); + pkt = setup_gptp_frame(iface, + sizeof(struct gptp_pdelay_resp_follow_up)); if (!pkt) { NET_DBG("Cannot get gPTP frame"); return NULL; @@ -483,8 +467,6 @@ struct net_pkt *gptp_prepare_pdelay_follow_up(int port, &pdelay_resp->requesting_port_id, sizeof(struct gptp_port_identity)); - net_buf_add(pkt->frags, sizeof(struct gptp_pdelay_resp_follow_up)); - return pkt; } @@ -504,7 +486,8 @@ struct net_pkt *gptp_prepare_announce(int port) iface = GPTP_PORT_IFACE(port); NET_ASSERT(iface); - pkt = setup_gptp_frame(iface); + pkt = setup_gptp_frame(iface, sizeof(struct gptp_announce) - 8 + + ntohs(global_ds->path_trace.len)); if (!pkt) { NET_DBG("Cannot get gPTP frame"); return NULL; @@ -582,17 +565,25 @@ struct net_pkt *gptp_prepare_announce(int port) sizeof(struct gptp_announce) - 8 + ntohs(global_ds->path_trace.len)); - net_buf_add(pkt->frags, sizeof(struct gptp_announce) - 8); - ann->tlv.len = global_ds->path_trace.len; - if (net_pkt_append(pkt, ntohs(global_ds->path_trace.len), - &global_ds->path_trace.path_sequence[0][0], - NET_BUF_TIMEOUT) < - ntohs(global_ds->path_trace.len)) { + net_pkt_cursor_init(pkt); + + /* setup_gptp_frame() already added all the length, so let's not + * add up more with net_pkt_skip/write_new(), let's just overwrite + */ + net_pkt_set_overwrite(pkt, true); + + if (net_pkt_skip(pkt, sizeof(struct gptp_hdr) + + sizeof(struct gptp_announce) - 8) || + net_pkt_write_new(pkt, + &global_ds->path_trace.path_sequence[0][0], + ntohs(global_ds->path_trace.len))) { goto fail; } + net_pkt_set_overwrite(pkt, false); + return pkt; fail: From dd1551897065bb53b793d071fb4b25f5ccff1e0b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 11 Jan 2019 13:33:01 +0100 Subject: [PATCH 56/70] net/pkt: Add a marker to identify LLDP message This will be used by Ethernet L2 to set the right PTYPE in its header. Signed-off-by: Tomasz Bursztyka --- include/net/net_pkt.h | 44 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index ac6eb7461e47e..316aafb260214 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -149,10 +149,21 @@ struct net_pkt { * Used only if defined(CONFIG_NET_ROUTE) */ u8_t family : 3; /* IPv4 vs IPv6 */ - u8_t ipv4_auto_arp_msg : 1; /* Is this pkt IPv4 autoconf ARP message. - * Used only if - * defined(CONFIG_NET_IPV4_AUTO) - */ + + union { + u8_t ipv4_auto_arp_msg : 1; /* Is this pkt IPv4 autoconf ARP + * message. Used only if + * defined(CONFIG_NET_IPV4_AUTO). + * Note: family needs to be + * AF_INET. + */ + u8_t lldp_pkt : 1; /* Is this pkt an LLDP message. + * Used only if + * defined(CONFIG_NET_LLDP). + * Note: family needs to be + * AF_UNSPEC. + */ + }; union { /* IPv6 hop limit or IPv4 ttl for this network packet. @@ -830,6 +841,31 @@ static inline void net_pkt_set_ipv4_auto(struct net_pkt *pkt, } #endif /* CONFIG_NET_IPV4_AUTO */ +#if defined(CONFIG_NET_LLDP) +static inline bool net_pkt_is_lldp(struct net_pkt *pkt) +{ + return pkt->lldp_pkt; +} + +static inline void net_pkt_set_lldp(struct net_pkt *pkt, bool is_lldp) +{ + pkt->lldp_pkt = is_lldp; +} +#else +static inline bool net_pkt_is_lldp(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return false; +} + +static inline void net_pkt_set_lldp(struct net_pkt *pkt, bool is_lldp) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(is_lldp); +} +#endif /* CONFIG_NET_LLDP */ + #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)) From 74ae9c65cf022a70694d38d693faf57bde8675ec Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 11 Jan 2019 13:35:11 +0100 Subject: [PATCH 57/70] net/lldp: Fix where Ethernet PTYPE is set for LLDP message Since the rework of L2/L3 split, only L2 has access to its header. Thus up to Ethernet one to set LLDP PTYPE. Signed-off-by: Tomasz Bursztyka --- subsys/net/l2/ethernet/ethernet.c | 2 ++ subsys/net/l2/ethernet/lldp/lldp.c | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c index 43d62478b903f..fa6dea91145ef 100644 --- a/subsys/net/l2/ethernet/ethernet.c +++ b/subsys/net/l2/ethernet/ethernet.c @@ -523,6 +523,8 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) ptype = htons(NET_ETH_PTYPE_IPV6); } else if (IS_ENABLED(CONFIG_NET_GPTP) && net_pkt_is_gptp(pkt)) { ptype = htons(NET_ETH_PTYPE_PTP); + } else if (IS_ENABLED(CONFIG_NET_LLDP) && net_pkt_is_lldp(pkt)) { + ptype = htons(NET_ETH_PTYPE_LLDP); } else if (IS_ENABLED(CONFIG_NET_ARP)) { /* Unktown type: Unqueued pkt is an ARP reply. */ diff --git a/subsys/net/l2/ethernet/lldp/lldp.c b/subsys/net/l2/ethernet/lldp/lldp.c index a30f38faae2f4..162a98132dcd1 100644 --- a/subsys/net/l2/ethernet/lldp/lldp.c +++ b/subsys/net/l2/ethernet/lldp/lldp.c @@ -88,7 +88,6 @@ static int lldp_send(struct ethernet_lldp *lldp) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } }; int ret = 0; - struct net_eth_hdr *hdr; struct net_pkt *pkt; struct net_buf *frag; u16_t pos; @@ -129,9 +128,6 @@ static int lldp_send(struct ethernet_lldp *lldp) net_pkt_lladdr_dst(pkt)->addr = (u8_t *)lldp_multicast_eth_addr.addr; net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr); - hdr = NET_ETH_HDR(pkt); - hdr->type = htons(NET_ETH_PTYPE_LLDP); - net_pkt_set_iface(pkt, lldp->iface); if (net_if_send_data(lldp->iface, pkt) == NET_DROP) { From 22cbf3fd87cb5d1dd289aaa880760281f6fd9e36 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 11 Jan 2019 12:40:25 +0100 Subject: [PATCH 58/70] net/lldp: Switch LLDP to new net_pkt API Minor changes: - allocator needed to be changed - and writing the lldp_pdu as well Signed-off-by: Tomasz Bursztyka --- subsys/net/l2/ethernet/lldp/lldp.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/subsys/net/l2/ethernet/lldp/lldp.c b/subsys/net/l2/ethernet/lldp/lldp.c index 162a98132dcd1..1d901a22aaafd 100644 --- a/subsys/net/l2/ethernet/lldp/lldp.c +++ b/subsys/net/l2/ethernet/lldp/lldp.c @@ -89,8 +89,6 @@ static int lldp_send(struct ethernet_lldp *lldp) }; int ret = 0; struct net_pkt *pkt; - struct net_buf *frag; - u16_t pos; if (!lldp->lldpdu) { /* The ethernet driver has not set the lldpdu pointer */ @@ -99,25 +97,15 @@ static int lldp_send(struct ethernet_lldp *lldp) goto out; } - pkt = net_pkt_get_reserve_tx(BUF_ALLOC_TIMEOUT); + pkt = net_pkt_alloc_with_buffer(lldp->iface, sizeof(struct net_lldpdu), + AF_UNSPEC, 0, BUF_ALLOC_TIMEOUT); if (!pkt) { ret = -ENOMEM; goto out; } - frag = net_pkt_get_frag(pkt, BUF_ALLOC_TIMEOUT); - if (!frag) { - net_pkt_unref(pkt); - ret = -ENOMEM; - goto out; - } - - net_pkt_frag_add(pkt, frag); - - net_buf_add(frag, sizeof(struct net_lldpdu)); - - if (!net_pkt_write(pkt, frag, 0, &pos, sizeof(struct net_lldpdu), - (u8_t *)lldp->lldpdu, BUF_ALLOC_TIMEOUT)) { + if (net_pkt_write_new(pkt, (u8_t *)lldp->lldpdu, + sizeof(struct net_lldpdu))) { net_pkt_unref(pkt); ret = -ENOMEM; goto out; @@ -128,8 +116,6 @@ static int lldp_send(struct ethernet_lldp *lldp) net_pkt_lladdr_dst(pkt)->addr = (u8_t *)lldp_multicast_eth_addr.addr; net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr); - net_pkt_set_iface(pkt, lldp->iface); - if (net_if_send_data(lldp->iface, pkt) == NET_DROP) { net_pkt_unref(pkt); ret = -EIO; From f8eae38a35ebece147f839b65dcbf168c491d17b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 14 Jan 2019 10:57:42 +0100 Subject: [PATCH 59/70] net/context: Expose new functions to create ipv4/6 packet from context These will be specifically needed in TCP, as well as being used in context internally. Signed-off-by: Tomasz Bursztyka --- include/net/net_context.h | 28 ++++++++++++++++++++++++++++ subsys/net/ip/net_context.c | 28 ++++++++++++---------------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/include/net/net_context.h b/include/net/net_context.h index 70a931289a7c9..76d502ba53e83 100644 --- a/include/net/net_context.h +++ b/include/net/net_context.h @@ -596,6 +596,20 @@ struct net_pkt *net_context_create_ipv4(struct net_context *context, return NULL; } #endif /* CONFIG_NET_IPV4 */ +#if defined(CONFIG_NET_IPV4) +int net_context_create_ipv4_new(struct net_context *context, + struct net_pkt *pkt, + const struct in_addr *src, + const struct in_addr *dst); +#else +static inline int net_context_create_ipv4_new(struct net_context *context, + struct net_pkt *pkt, + const struct in_addr *src, + const struct in_addr *dst) +{ + return -1; +} +#endif /* CONFIG_NET_IPV4 */ /** * @brief Create IPv6 packet in provided net_pkt from context @@ -622,6 +636,20 @@ struct net_pkt *net_context_create_ipv6(struct net_context *context, return NULL; } #endif /* CONFIG_NET_IPV6 */ +#if defined(CONFIG_NET_IPV6) +int net_context_create_ipv6_new(struct net_context *context, + struct net_pkt *pkt, + const struct in6_addr *src, + const struct in6_addr *dst); +#else +static inline int net_context_create_ipv6_new(struct net_context *context, + struct net_pkt *pkt, + const struct in6_addr *src, + const struct in6_addr *dst) +{ + return -1; +} +#endif /* CONFIG_NET_IPV6 */ /** * @brief Assign a socket a local address. diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index b7f3032682daa..36c51a8db5544 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -679,10 +679,10 @@ struct net_pkt *net_context_create_ipv4(struct net_context *context, net_context_get_ip_proto(context)); } -static int context_create_ipv4_new(struct net_context *context, - struct net_pkt *pkt, - const struct in_addr *src, - const struct in_addr *dst) +int net_context_create_ipv4_new(struct net_context *context, + struct net_pkt *pkt, + const struct in_addr *src, + const struct in_addr *dst) { NET_ASSERT(((struct sockaddr_in_ptr *)&context->local)->sin_addr); @@ -703,8 +703,6 @@ static int context_create_ipv4_new(struct net_context *context, return net_ipv4_create_new(pkt, src, dst); } -#else -#define context_create_ipv4_new(...) -1 #endif /* CONFIG_NET_IPV4 */ #if defined(CONFIG_NET_IPV6) @@ -732,10 +730,10 @@ struct net_pkt *net_context_create_ipv6(struct net_context *context, net_context_get_ip_proto(context)); } -static int context_create_ipv6_new(struct net_context *context, - struct net_pkt *pkt, - const struct in6_addr *src, - const struct in6_addr *dst) +int net_context_create_ipv6_new(struct net_context *context, + struct net_pkt *pkt, + const struct in6_addr *src, + const struct in6_addr *dst) { NET_ASSERT(((struct sockaddr_in6_ptr *)&context->local)->sin6_addr); @@ -751,8 +749,6 @@ static int context_create_ipv6_new(struct net_context *context, return net_ipv6_create_new(pkt, src, dst); } -#else -#define context_create_ipv6_new(...) -1 #endif /* CONFIG_NET_IPV6 */ int net_context_connect(struct net_context *context, @@ -1264,16 +1260,16 @@ static int context_setup_udp_packet(struct net_context *context, dst_port = addr4->sin_port; - ret = context_create_ipv4_new(context, pkt, - NULL, &addr4->sin_addr); + ret = net_context_create_ipv4_new(context, pkt, + NULL, &addr4->sin_addr); } else if (IS_ENABLED(CONFIG_NET_IPV6) && net_context_get_family(context) == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)dst_addr; dst_port = addr6->sin6_port; - ret = context_create_ipv6_new(context, pkt, - NULL, &addr6->sin6_addr); + ret = net_context_create_ipv6_new(context, pkt, + NULL, &addr6->sin6_addr); } if (ret < 0) { From c775fd87fdb7c062eab1432ea621bc78a67248b7 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 14 Jan 2019 11:38:45 +0100 Subject: [PATCH 60/70] net/tcp: Switch TCP segment preparation to new net_pkt API Using new functions for net_context, ipv4 and ipv6 as well. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/tcp.c | 140 ++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 75 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 497283f17d38d..aa7be8e009817 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -345,40 +345,19 @@ int net_tcp_release(struct net_tcp *tcp) return 0; } -static inline u8_t net_tcp_add_options(struct net_buf *header, size_t len, - void *data) +static int finalize_segment(struct net_pkt *pkt) { - u8_t optlen; - - memcpy(net_buf_add(header, len), data, len); - - /* Set the length (this value is saved in 4-byte words format) */ - if ((len & 0x3u) != 0u) { - optlen = (len & 0xfffCu) + 4u; - } else { - optlen = len; - } + net_pkt_cursor_init(pkt); - return optlen; -} - -static int finalize_segment(struct net_context *context, struct net_pkt *pkt) -{ -#if defined(CONFIG_NET_IPV4) - if (net_pkt_family(pkt) == AF_INET) { - net_ipv4_finalize(pkt, net_context_get_ip_proto(context)); - } else -#endif -#if defined(CONFIG_NET_IPV6) - if (net_pkt_family(pkt) == AF_INET6) { - return net_ipv6_finalize(pkt, - net_context_get_ip_proto(context)); - } -#endif - { + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_pkt_family(pkt) == AF_INET) { + return net_ipv4_finalize_new(pkt, IPPROTO_TCP); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6) { + return net_ipv6_finalize_new(pkt, IPPROTO_TCP); } - return 0; + return -EINVAL; } static int prepare_segment(struct net_tcp *tcp, @@ -386,10 +365,10 @@ static int prepare_segment(struct net_tcp *tcp, struct net_pkt *pkt, struct net_pkt **out_pkt) { - struct net_buf *header, *tail = NULL; + NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); struct net_context *context = tcp->context; + struct net_buf *tail = NULL; struct net_tcp_hdr *tcp_hdr; - struct net_pkt *alloc_pkt; u16_t dst_port, src_port; bool pkt_allocated; u8_t optlen = 0U; @@ -403,51 +382,53 @@ static int prepare_segment(struct net_tcp *tcp, * the context), and the data after. Rejigger so we * can insert a TCP header cleanly */ - tail = pkt->frags; - pkt->frags = NULL; + tail = pkt->buffer; + pkt->buffer = NULL; pkt_allocated = false; + + status = net_pkt_alloc_buffer(pkt, segment->optlen, + IPPROTO_TCP, ALLOC_TIMEOUT); + if (status) { + goto fail; + } } else { - pkt = net_pkt_get_tx(context, ALLOC_TIMEOUT); + pkt = net_pkt_alloc_with_buffer(net_context_get_iface(context), + segment->optlen, + net_context_get_family(context), + IPPROTO_TCP, ALLOC_TIMEOUT); if (!pkt) { return -ENOMEM; } + net_pkt_set_context(pkt, context); pkt_allocated = true; } -#if defined(CONFIG_NET_IPV4) - if (net_pkt_family(pkt) == AF_INET) { - alloc_pkt = net_context_create_ipv4(context, pkt, - net_sin_ptr(segment->src_addr)->sin_addr, - &(net_sin(segment->dst_addr)->sin_addr)); - if (!alloc_pkt) { - status = -ENOMEM; + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_pkt_family(pkt) == AF_INET) { + status = net_context_create_ipv4_new(context, pkt, + net_sin_ptr(segment->src_addr)->sin_addr, + &(net_sin(segment->dst_addr)->sin_addr)); + if (status < 0) { goto fail; } dst_port = net_sin(segment->dst_addr)->sin_port; src_port = ((struct sockaddr_in_ptr *)&context->local)-> sin_port; - NET_IPV4_HDR(pkt)->proto = IPPROTO_TCP; - } else -#endif -#if defined(CONFIG_NET_IPV6) - if (net_pkt_family(pkt) == AF_INET6) { - alloc_pkt = net_context_create_ipv6(tcp->context, pkt, - net_sin6_ptr(segment->src_addr)->sin6_addr, - &(net_sin6(segment->dst_addr)->sin6_addr)); - if (!alloc_pkt) { - status = -ENOMEM; + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6) { + status = net_context_create_ipv6_new(context, pkt, + net_sin6_ptr(segment->src_addr)->sin6_addr, + &(net_sin6(segment->dst_addr)->sin6_addr)); + if (status < 0) { goto fail; } dst_port = net_sin6(segment->dst_addr)->sin6_port; src_port = ((struct sockaddr_in6_ptr *)&context->local)-> sin6_port; - NET_IPV6_HDR(pkt)->nexthdr = IPPROTO_TCP; - } else -#endif - { + } else { NET_DBG("[%p] Protocol family %d not supported", tcp, net_pkt_family(pkt)); @@ -455,39 +436,47 @@ static int prepare_segment(struct net_tcp *tcp, goto fail; } - header = net_pkt_get_data(context, ALLOC_TIMEOUT); - if (!header) { - NET_WARN("[%p] Unable to alloc TCP header", tcp); - - status = -ENOMEM; + tcp_hdr = (struct net_tcp_hdr *)net_pkt_get_data_new(pkt, &tcp_access); + if (!tcp_hdr) { + status = -ENOBUFS; goto fail; } - net_pkt_frag_add(pkt, header); - - tcp_hdr = (struct net_tcp_hdr *)net_buf_add(header, NET_TCPH_LEN); - if (segment->options && segment->optlen) { - optlen = net_tcp_add_options(header, segment->optlen, - segment->options); + /* Set the length (this value is saved in 4-byte words format) + */ + if ((segment->optlen & 0x3u) != 0u) { + optlen = (segment->optlen & 0xfffCu) + 4u; + } else { + optlen = segment->optlen; + } } - tcp_hdr->offset = (NET_TCPH_LEN + optlen) << 2; + memset(tcp_hdr, 0, NET_TCPH_LEN); tcp_hdr->src_port = src_port; tcp_hdr->dst_port = dst_port; sys_put_be32(segment->seq, tcp_hdr->seq); sys_put_be32(segment->ack, tcp_hdr->ack); - tcp_hdr->flags = segment->flags; + tcp_hdr->offset = (NET_TCPH_LEN + optlen) << 2; + tcp_hdr->flags = segment->flags; sys_put_be16(segment->wnd, tcp_hdr->wnd); - tcp_hdr->urg[0] = 0; - tcp_hdr->urg[1] = 0; + tcp_hdr->chksum = 0; + tcp_hdr->urg[0] = 0; + tcp_hdr->urg[1] = 0; + + net_pkt_set_data(pkt, &tcp_access); + + if (optlen && + net_pkt_write_new(pkt, segment->options, segment->optlen)) { + goto fail; + } if (tail) { - net_pkt_frag_add(pkt, tail); + net_pkt_append_buffer(pkt, tail); } - status = finalize_segment(context, pkt); + status = finalize_segment(pkt); if (status < 0) { if (pkt_allocated) { net_pkt_unref(pkt); @@ -506,7 +495,8 @@ static int prepare_segment(struct net_tcp *tcp, if (pkt_allocated) { net_pkt_unref(pkt); } else { - pkt->frags = tail; + net_buf_unref(pkt->buffer); + pkt->buffer = tail; } return status; @@ -523,9 +513,9 @@ int net_tcp_prepare_segment(struct net_tcp *tcp, u8_t flags, const struct sockaddr *remote, struct net_pkt **send_pkt) { + struct tcp_segment segment = { 0 }; u32_t seq; u16_t wnd; - struct tcp_segment segment = { 0 }; int status; if (!local) { From 7035c8a726b3dd444091b03b90ad690bc6be6663 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 14 Jan 2019 21:07:42 +0100 Subject: [PATCH 61/70] net/conn: Change callback signature to pass TCP/IP headers As these were parsed already by IPv4/6 input functions let's use them. Applying the change on trivial UDP usage. TCP usage will have its own commit. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/connection.c | 10 ++++++---- subsys/net/ip/connection.h | 2 ++ subsys/net/ip/dhcpv4.c | 2 ++ subsys/net/ip/net_context.c | 2 ++ subsys/net/ip/net_private.h | 2 ++ tests/net/ipv6_fragment/src/main.c | 2 ++ tests/net/udp/src/main.c | 4 ++++ 7 files changed, 20 insertions(+), 4 deletions(-) diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index b81c1e352f1dc..db4b3198d8a88 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -269,6 +269,7 @@ static void cache_clear(void) static inline enum net_verdict cache_check(struct net_pkt *pkt, union ip_header *hdr, + union proto_header *proto_hdr, enum net_ip_protocol proto, u16_t src_port, u16_t dst_port, @@ -288,7 +289,8 @@ static inline enum net_verdict cache_check(struct net_pkt *pkt, net_pkt_family(pkt), *pos, conn_cache[*pos].value); - return conn->cb(conn, pkt, conn->user_data); + return conn->cb(conn, pkt, + hdr, proto_hdr, conn->user_data); } } else if (*cache_value > 0) { if (cache_check_neg(*cache_value)) { @@ -808,7 +810,7 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, union ip_header *ip_hdr, } #if defined(CONFIG_NET_CONN_CACHE) - verdict = cache_check(pkt, ip_hdr, proto, src_port, dst_port, + verdict = cache_check(pkt, ip_hdr, proto_hdr, proto, src_port, dst_port, &cache_value, &pos); if (verdict != NET_CONTINUE) { return verdict; @@ -891,8 +893,8 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, union ip_header *ip_hdr, conns[best_match].rank); #endif /* CONFIG_NET_CONN_CACHE */ - if (conns[best_match].cb(&conns[best_match], pkt, - conns[best_match].user_data) == NET_DROP) { + if (conns[best_match].cb(&conns[best_match], pkt, ip_hdr, + proto_hdr, conns[best_match].user_data) == NET_DROP) { goto drop; } diff --git a/subsys/net/ip/connection.h b/subsys/net/ip/connection.h index aa3cf721939fa..91617054e1502 100644 --- a/subsys/net/ip/connection.h +++ b/subsys/net/ip/connection.h @@ -46,6 +46,8 @@ union proto_header { */ typedef enum net_verdict (*net_conn_cb_t)(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data); /** diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index cb1eb76be0869..039362de06d6c 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -875,6 +875,8 @@ static void dhcpv4_handle_reply(struct net_if *iface, static enum net_verdict net_dhcpv4_input(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data) { NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg); diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 36c51a8db5544..586d9401a6c11 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1470,6 +1470,8 @@ int net_context_sendto_new(struct net_context *context, enum net_verdict net_context_packet_received(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data) { struct net_context *context = find_context(conn); diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index bd2e33cbd635e..017d76dad22f9 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -147,6 +147,8 @@ void net_pkt_set_appdata_values(struct net_pkt *pkt, enum net_verdict net_context_packet_received(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data); #if defined(CONFIG_NET_IPV4) diff --git a/tests/net/ipv6_fragment/src/main.c b/tests/net/ipv6_fragment/src/main.c index 981d292a6d77d..1f780c3adcfcb 100644 --- a/tests/net/ipv6_fragment/src/main.c +++ b/tests/net/ipv6_fragment/src/main.c @@ -1125,6 +1125,8 @@ static void add_nbr(struct net_if *iface, static enum net_verdict udp_data_received(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data) { DBG("Data %p received\n", pkt); diff --git a/tests/net/udp/src/main.c b/tests/net/udp/src/main.c index 50ad4a6af093c..4f436e9a8e0e1 100644 --- a/tests/net/udp/src/main.c +++ b/tests/net/udp/src/main.c @@ -151,6 +151,8 @@ static struct ud *returned_ud; static enum net_verdict test_ok(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data) { struct ud *ud = (struct ud *)user_data; @@ -176,6 +178,8 @@ static enum net_verdict test_ok(struct net_conn *conn, static enum net_verdict test_fail(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data) { /* This function should never be called as there should not From 2cbf1d0a7c4322ed67be0470557074fe444f05f1 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 14 Jan 2019 21:08:39 +0100 Subject: [PATCH 62/70] net/tcp: Apply connection callback signature change This proovse to drastically reduce runtime overhead as it does not need to parse IP nor TCP header all over again in a lot of places. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/tcp.c | 295 +++++++++++++++++------------------ subsys/net/ip/tcp_internal.h | 8 +- tests/net/tcp/src/main.c | 4 + 3 files changed, 150 insertions(+), 157 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index aa7be8e009817..0b0ca5f04ea06 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -70,23 +70,30 @@ static struct tcp_backlog_entry { * pointers and doesn't understand what a net_context is. */ #define NET_CONN_CB(name) \ - static enum net_verdict _##name(struct net_conn *conn, \ - struct net_pkt *pkt, \ - void *user_data); \ - static enum net_verdict name(struct net_conn *conn, \ - struct net_pkt *pkt, \ - void *user_data) \ - { \ - enum net_verdict result; \ - \ - net_context_ref(user_data); \ - result = _##name(conn, pkt, user_data); \ - net_context_unref(user_data); \ - return result; \ - } \ - static enum net_verdict _##name(struct net_conn *conn, \ - struct net_pkt *pkt, \ - void *user_data) \ + static enum net_verdict _##name(struct net_conn *conn, \ + struct net_pkt *pkt, \ + union ip_header *ip_hdr, \ + union proto_header *proto_hdr, \ + void *user_data); \ + static enum net_verdict name(struct net_conn *conn, \ + struct net_pkt *pkt, \ + union ip_header *ip_hdr, \ + union proto_header *proto_hdr, \ + void *user_data) \ + { \ + enum net_verdict result; \ + \ + net_context_ref(user_data); \ + result = _##name(conn, pkt, ip_hdr, \ + proto_hdr, user_data); \ + net_context_unref(user_data); \ + return result; \ + } \ + static enum net_verdict _##name(struct net_conn *conn, \ + struct net_pkt *pkt, \ + union ip_header *ip_hdr, \ + union proto_header *proto_hdr, \ + void *user_data) \ struct tcp_segment { @@ -1217,15 +1224,8 @@ void net_tcp_foreach(net_tcp_cb_t cb, void *user_data) irq_unlock(key); } -bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt) +bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_tcp_hdr *tcp_hdr) { - struct net_tcp_hdr hdr, *tcp_hdr; - - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return false; - } - return (net_tcp_seq_cmp(sys_get_be32(tcp_hdr->seq), tcp->send_ack) >= 0) && (net_tcp_seq_cmp(sys_get_be32(tcp_hdr->seq), @@ -1567,9 +1567,52 @@ static void backlog_ack_timeout(struct k_work *work) (void)memset(backlog, 0, sizeof(struct tcp_backlog_entry)); } -static int tcp_backlog_find(struct net_pkt *pkt, int *empty_slot) +static void tcp_copy_ip_addr_from_hdr(sa_family_t family, + union ip_header *ip_hdr, + struct net_tcp_hdr *tcp_hdr, + struct sockaddr *addr, + bool is_src_addr) +{ + u16_t port; + + if (is_src_addr) { + port = tcp_hdr->src_port; + } else { + port = tcp_hdr->dst_port; + } + + if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { + struct sockaddr_in *addr4 = net_sin(addr); + + if (is_src_addr) { + net_ipaddr_copy(&addr4->sin_addr, &ip_hdr->ipv4->src); + } else { + net_ipaddr_copy(&addr4->sin_addr, &ip_hdr->ipv4->dst); + } + + addr4->sin_port = port; + addr->sa_family = AF_INET; + } + + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { + struct sockaddr_in6 *addr6 = net_sin6(addr); + + if (is_src_addr) { + net_ipaddr_copy(&addr6->sin6_addr, &ip_hdr->ipv6->src); + } else { + net_ipaddr_copy(&addr6->sin6_addr, &ip_hdr->ipv6->dst); + } + + addr6->sin6_port = port; + addr->sa_family = AF_INET6; + } +} + +static int tcp_backlog_find(struct net_pkt *pkt, + union ip_header *hdr, + struct net_tcp_hdr *tcp_hdr, + int *empty_slot) { - struct net_tcp_hdr hdr, *tcp_hdr; int i, empty = -1; for (i = 0; i < CONFIG_NET_TCP_BACKLOG_SIZE; i++) { @@ -1582,42 +1625,28 @@ static int tcp_backlog_find(struct net_pkt *pkt, int *empty_slot) continue; } - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return -EINVAL; - } - - switch (net_pkt_family(pkt)) { -#if defined(CONFIG_NET_IPV6) - case AF_INET6: - if (net_sin6(&tcp_backlog[i].remote)->sin6_port != + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_pkt_family(pkt) == AF_INET) { + if (net_sin(&tcp_backlog[i].remote)->sin_port != tcp_hdr->src_port) { continue; } - if (memcmp(&net_sin6(&tcp_backlog[i].remote)->sin6_addr, - &NET_IPV6_HDR(pkt)->src, - sizeof(struct in6_addr))) { + if (memcmp(&net_sin(&tcp_backlog[i].remote)->sin_addr, + &hdr->ipv4->src, sizeof(struct in_addr))) { continue; } - - break; -#endif -#if defined(CONFIG_NET_IPV4) - case AF_INET: - if (net_sin(&tcp_backlog[i].remote)->sin_port != + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6) { + if (net_sin6(&tcp_backlog[i].remote)->sin6_port != tcp_hdr->src_port) { continue; } - if (memcmp(&net_sin(&tcp_backlog[i].remote)->sin_addr, - &NET_IPV4_HDR(pkt)->src, - sizeof(struct in_addr))) { + if (memcmp(&net_sin6(&tcp_backlog[i].remote)->sin6_addr, + &hdr->ipv6->src, sizeof(struct in6_addr))) { continue; } - - break; -#endif } return i; @@ -1630,13 +1659,15 @@ static int tcp_backlog_find(struct net_pkt *pkt, int *empty_slot) return -EADDRNOTAVAIL; } -static int tcp_backlog_syn(struct net_pkt *pkt, struct net_context *context, +static int tcp_backlog_syn(struct net_pkt *pkt, + union ip_header *ip_hdr, + struct net_tcp_hdr *tcp_hdr, + struct net_context *context, u16_t send_mss) { int empty_slot = -1; - int ret; - if (tcp_backlog_find(pkt, &empty_slot) >= 0) { + if (tcp_backlog_find(pkt, ip_hdr, tcp_hdr, &empty_slot) >= 0) { return -EADDRINUSE; } @@ -1646,14 +1677,8 @@ static int tcp_backlog_syn(struct net_pkt *pkt, struct net_context *context, tcp_backlog[empty_slot].tcp = context->tcp; - ret = net_pkt_get_src_addr(pkt, &tcp_backlog[empty_slot].remote, - sizeof(tcp_backlog[empty_slot].remote)); - if (ret < 0) { - /* Release the assigned empty slot */ - tcp_backlog[empty_slot].tcp = NULL; - - return ret; - } + tcp_copy_ip_addr_from_hdr(net_pkt_family(pkt), ip_hdr, tcp_hdr, + &tcp_backlog[empty_slot].remote, true); tcp_backlog[empty_slot].send_seq = context->tcp->send_seq; tcp_backlog[empty_slot].send_ack = context->tcp->send_ack; @@ -1666,22 +1691,18 @@ static int tcp_backlog_syn(struct net_pkt *pkt, struct net_context *context, return 0; } -static int tcp_backlog_ack(struct net_pkt *pkt, struct net_context *context) +static int tcp_backlog_ack(struct net_pkt *pkt, + union ip_header *ip_hdr, + struct net_tcp_hdr *tcp_hdr, + struct net_context *context) { - struct net_tcp_hdr hdr, *tcp_hdr; int r; - r = tcp_backlog_find(pkt, NULL); - + r = tcp_backlog_find(pkt, ip_hdr, tcp_hdr, NULL); if (r < 0) { return r; } - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return -EINVAL; - } - /* Sent SEQ + 1 needs to be the same as the received ACK */ if (tcp_backlog[r].send_seq + 1 != sys_get_be32(tcp_hdr->ack)) { return -EINVAL; @@ -1699,21 +1720,17 @@ static int tcp_backlog_ack(struct net_pkt *pkt, struct net_context *context) return 0; } -static int tcp_backlog_rst(struct net_pkt *pkt) +static int tcp_backlog_rst(struct net_pkt *pkt, + union ip_header *ip_hdr, + struct net_tcp_hdr *tcp_hdr) { - struct net_tcp_hdr hdr, *tcp_hdr; int r; - r = tcp_backlog_find(pkt, NULL); + r = tcp_backlog_find(pkt, ip_hdr, tcp_hdr, NULL); if (r < 0) { return r; } - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return -EINVAL; - } - /* The ACK sent needs to be the same as the received SEQ */ if (tcp_backlog[r].send_ack != sys_get_be32(tcp_hdr->seq)) { return -EINVAL; @@ -1968,13 +1985,16 @@ static int send_reset(struct net_context *context, * established. The core TCP logic is located here. * * Prototype: - * enum net_verdict tcp_established(struct net_conn *conn, struct net_pkt *pkt, + * enum net_verdict tcp_established(struct net_conn *conn, + * union ip_header *ip_hdr, + * union data_header *proto_hdr, + * struct net_pkt *pkt, * void *user_data) */ NET_CONN_CB(tcp_established) { struct net_context *context = (struct net_context *)user_data; - struct net_tcp_hdr hdr, *tcp_hdr; + struct net_tcp_hdr *tcp_hdr = proto_hdr->tcp; enum net_verdict ret = NET_OK; u8_t tcp_flags; u16_t data_len; @@ -1983,12 +2003,6 @@ NET_CONN_CB(tcp_established) NET_ASSERT(context && context->tcp); - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - ret = NET_DROP; - goto unlock; - } - if (net_tcp_get_state(context->tcp) < NET_TCP_ESTABLISHED) { NET_ERR("Context %p in wrong state %d", context, net_tcp_get_state(context->tcp)); @@ -2031,7 +2045,7 @@ NET_CONN_CB(tcp_established) */ if (tcp_flags & NET_TCP_RST) { /* We only accept RST packet that has valid seq field. */ - if (!net_tcp_validate_seq(context->tcp, pkt)) { + if (!net_tcp_validate_seq(context->tcp, tcp_hdr)) { net_stats_update_tcp_seg_rsterr(net_pkt_iface(pkt)); ret = NET_DROP; goto unlock; @@ -2055,7 +2069,7 @@ NET_CONN_CB(tcp_established) /* Handle TCP state transition */ if (tcp_flags & NET_TCP_ACK) { if (!net_tcp_ack_received(context, - sys_get_be32(tcp_hdr->ack))) { + sys_get_be32(tcp_hdr->ack))) { return NET_DROP; } @@ -2127,7 +2141,7 @@ NET_CONN_CB(tcp_established) * release the pkt. Otherwise, release the pkt immediately. */ if (data_len > 0) { - ret = net_context_packet_received(conn, pkt, + ret = net_context_packet_received(conn, pkt, ip_hdr, proto_hdr, context->tcp->recv_user_data); } else if (data_len == 0) { net_pkt_unref(pkt); @@ -2162,17 +2176,18 @@ NET_CONN_CB(tcp_established) return ret; } - /* * Prototype: * enum net_verdict tcp_synack_received(struct net_conn *conn, - * struct net_pkt *pkt, - * void *user_data) + * struct net_pkt *pkt, + * union ip_header *ip_hdr, + * union data_header *proto_hdr, + * void *user_data) */ NET_CONN_CB(tcp_synack_received) { struct net_context *context = (struct net_context *)user_data; - struct net_tcp_hdr hdr, *tcp_hdr; + struct net_tcp_hdr *tcp_hdr = proto_hdr->tcp; int ret; NET_ASSERT(context && context->tcp); @@ -2191,14 +2206,9 @@ NET_CONN_CB(tcp_synack_received) NET_ASSERT(net_pkt_iface(pkt)); - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return NET_DROP; - } - if (NET_TCP_FLAGS(tcp_hdr) & NET_TCP_RST) { /* We only accept RST packet that has valid seq field. */ - if (!net_tcp_validate_seq(context->tcp, pkt)) { + if (!net_tcp_validate_seq(context->tcp, tcp_hdr)) { net_stats_update_tcp_seg_rsterr(net_pkt_iface(pkt)); return NET_DROP; } @@ -2229,18 +2239,10 @@ NET_CONN_CB(tcp_synack_received) struct sockaddr local_addr; struct sockaddr remote_addr; - if (net_pkt_get_src_addr( - pkt, &remote_addr, sizeof(remote_addr)) < 0) { - NET_DBG("Cannot parse remote address" - " from received pkt"); - return NET_DROP; - } - - if (net_pkt_get_dst_addr( - pkt, &local_addr, sizeof(local_addr)) < 0) { - NET_DBG("Cannot parse local address from received pkt"); - return NET_DROP; - } + tcp_copy_ip_addr_from_hdr(net_pkt_family(pkt), ip_hdr, tcp_hdr, + &remote_addr, true); + tcp_copy_ip_addr_from_hdr(net_pkt_family(pkt), ip_hdr, tcp_hdr, + &local_addr, false); net_tcp_unregister(context->conn_handler); @@ -2272,37 +2274,28 @@ NET_CONN_CB(tcp_synack_received) return NET_DROP; } -static void pkt_get_sockaddr(sa_family_t family, struct net_pkt *pkt, +static void get_sockaddr_ptr(union ip_header *ip_hdr, + struct net_tcp_hdr *tcp_hdr, + sa_family_t family, struct sockaddr_ptr *addr) { - struct net_tcp_hdr hdr, *tcp_hdr; - - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return; - } - (void)memset(addr, 0, sizeof(*addr)); -#if defined(CONFIG_NET_IPV4) - if (family == AF_INET) { + if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { struct sockaddr_in_ptr *addr4 = net_sin_ptr(addr); addr4->sin_family = AF_INET; addr4->sin_port = tcp_hdr->dst_port; - addr4->sin_addr = &NET_IPV4_HDR(pkt)->dst; + addr4->sin_addr = &ip_hdr->ipv4->dst; } -#endif -#if defined(CONFIG_NET_IPV6) - if (family == AF_INET6) { + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { struct sockaddr_in6_ptr *addr6 = net_sin6_ptr(addr); addr6->sin6_family = AF_INET6; addr6->sin6_port = tcp_hdr->dst_port; - addr6->sin6_addr = &NET_IPV6_HDR(pkt)->dst; + addr6->sin6_addr = &ip_hdr->ipv6->dst; } -#endif } #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) @@ -2322,13 +2315,16 @@ static inline void copy_pool_vars(struct net_context *new_context, * connection. * * Prototype: - * enum net_verdict tcp_syn_rcvd(struct net_conn *conn, struct net_pkt *pkt, - * void *user_data) + * enum net_verdict tcp_syn_rcvd(struct net_conn *conn, + * struct net_pkt *pkt, + * union ip_header *ip_hdr, + * union data_header *proto_hdr, + * void *user_data) */ NET_CONN_CB(tcp_syn_rcvd) { struct net_context *context = (struct net_context *)user_data; - struct net_tcp_hdr hdr, *tcp_hdr; + struct net_tcp_hdr *tcp_hdr = proto_hdr->tcp; struct net_tcp *tcp; struct sockaddr_ptr pkt_src_addr; struct sockaddr local_addr; @@ -2357,30 +2353,20 @@ NET_CONN_CB(tcp_syn_rcvd) NET_ASSERT(net_pkt_iface(pkt)); - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return NET_DROP; - } - - if (net_pkt_get_src_addr(pkt, &remote_addr, sizeof(remote_addr)) < 0) { - NET_DBG("Cannot parse remote address from received pkt"); - return NET_DROP; - } - - if (net_pkt_get_dst_addr(pkt, &local_addr, sizeof(local_addr)) < 0) { - NET_DBG("Cannot parse local address from received pkt"); - return NET_DROP; - } + tcp_copy_ip_addr_from_hdr(net_pkt_family(pkt), ip_hdr, tcp_hdr, + &remote_addr, true); + tcp_copy_ip_addr_from_hdr(net_pkt_family(pkt), ip_hdr, tcp_hdr, + &local_addr, false); /* * If we receive SYN, we send SYN-ACK and go to SYN_RCVD state. */ if (NET_TCP_FLAGS(tcp_hdr) == NET_TCP_SYN) { - int r; - int opt_totlen; struct net_tcp_options tcp_opts = { .mss = NET_TCP_DEFAULT_MSS, }; + int opt_totlen; + int r; net_tcp_print_recv_info("SYN", pkt, tcp_hdr->src_port); @@ -2402,7 +2388,8 @@ NET_CONN_CB(tcp_syn_rcvd) /* Get MSS from TCP options here*/ - r = tcp_backlog_syn(pkt, context, tcp_opts.mss); + r = tcp_backlog_syn(pkt, ip_hdr, tcp_hdr, + context, tcp_opts.mss); if (r < 0) { if (r == -EADDRINUSE) { NET_DBG("TCP connection already exists"); @@ -2413,8 +2400,9 @@ NET_CONN_CB(tcp_syn_rcvd) return NET_DROP; } - pkt_get_sockaddr(net_context_get_family(context), - pkt, &pkt_src_addr); + get_sockaddr_ptr(ip_hdr, tcp_hdr, + net_context_get_family(context), + &pkt_src_addr); send_syn_ack(context, &pkt_src_addr, &remote_addr); net_pkt_unref(pkt); return NET_OK; @@ -2426,7 +2414,7 @@ NET_CONN_CB(tcp_syn_rcvd) */ if (NET_TCP_FLAGS(tcp_hdr) & NET_TCP_RST) { - if (tcp_backlog_rst(pkt) < 0) { + if (tcp_backlog_rst(pkt, ip_hdr, tcp_hdr) < 0) { net_stats_update_tcp_seg_rsterr(net_pkt_iface(pkt)); return NET_DROP; } @@ -2464,7 +2452,7 @@ NET_CONN_CB(tcp_syn_rcvd) goto conndrop; } - ret = tcp_backlog_ack(pkt, new_context); + ret = tcp_backlog_ack(pkt, ip_hdr, tcp_hdr, new_context); if (ret < 0) { NET_DBG("Cannot find context from TCP backlog"); @@ -2547,7 +2535,8 @@ NET_CONN_CB(tcp_syn_rcvd) return NET_DROP; } -int net_tcp_accept(struct net_context *context, net_tcp_accept_cb_t cb, +int net_tcp_accept(struct net_context *context, + net_tcp_accept_cb_t cb, void *user_data) { struct sockaddr local_addr; diff --git a/subsys/net/ip/tcp_internal.h b/subsys/net/ip/tcp_internal.h index 1afaf4e5abf3a..268732dce2fbc 100644 --- a/subsys/net/ip/tcp_internal.h +++ b/subsys/net/ip/tcp_internal.h @@ -393,11 +393,11 @@ static inline enum net_tcp_state net_tcp_get_state(const struct net_tcp *tcp) * @brief Check if the sequence number is valid i.e., it is inside the window. * * @param tcp TCP context - * @param pkt Network packet + * @param tcp_hdr TCP header pointer * * @return true if network packet sequence number is valid, false otherwise */ -bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt); +bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_tcp_hdr *tcp_hdr); /** * @brief Set TCP checksum in network packet. @@ -657,10 +657,10 @@ static inline enum net_tcp_state net_tcp_get_state(const struct net_tcp *tcp) } static inline bool net_tcp_validate_seq(struct net_tcp *tcp, - struct net_pkt *pkt) + struct net_tcp_hdr *tcp_hdr) { ARG_UNUSED(tcp); - ARG_UNUSED(pkt); + ARG_UNUSED(tcp_hdr); return false; } diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c index 25d1f2661ccc9..b993eaeca73bd 100644 --- a/tests/net/tcp/src/main.c +++ b/tests/net/tcp/src/main.c @@ -229,6 +229,8 @@ static struct ud *returned_ud; static enum net_verdict test_ok(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data) { struct ud *ud = (struct ud *)user_data; @@ -254,6 +256,8 @@ static enum net_verdict test_ok(struct net_conn *conn, static enum net_verdict test_fail(struct net_conn *conn, struct net_pkt *pkt, + union ip_header *ip_hdr, + union proto_header *proto_hdr, void *user_data) { /* This function should never be called as there should not From 0143e4c78cc1ddc5b015835aba88d940d90f7678 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 15 Jan 2019 15:09:29 +0100 Subject: [PATCH 63/70] net/tcp: Switch rest of TCP to new net_pkt API Only next to be removed functions like net_tcp_set_checksum() are left untouched. All the rest is switched. Adding net_tcp_finalize() to follow the same logic as for UDP and else. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/ipv4.c | 2 +- subsys/net/ip/ipv6.c | 2 +- subsys/net/ip/tcp.c | 275 +++++++++++++++++++---------------- subsys/net/ip/tcp_internal.h | 18 +-- tests/net/tcp/src/main.c | 31 ++-- 5 files changed, 178 insertions(+), 150 deletions(-) diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index a2fa4f77b77ae..a75fa821b1e58 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -160,7 +160,7 @@ int net_ipv4_finalize_new(struct net_pkt *pkt, u8_t next_header_proto) return net_udp_finalize(pkt); } else if (IS_ENABLED(CONFIG_NET_TCP) && next_header_proto == IPPROTO_TCP) { - net_tcp_set_chksum(pkt, pkt->buffer); + net_tcp_finalize(pkt); } else if (next_header_proto == IPPROTO_ICMP) { net_icmpv4_finalize(pkt); } diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index bfb27a9639cde..4024bda37276f 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -206,7 +206,7 @@ int net_ipv6_finalize_new(struct net_pkt *pkt, u8_t next_header_proto) net_udp_finalize(pkt); } else if (IS_ENABLED(CONFIG_NET_TCP) && next_header_proto == IPPROTO_TCP) { - net_tcp_set_chksum(pkt, pkt->buffer); + net_tcp_finalize(pkt); } else if (next_header_proto == IPPROTO_ICMPV6) { return net_icmpv6_finalize(pkt); } diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 0b0ca5f04ea06..9be8899cb1c20 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -116,9 +116,10 @@ static char upper_if_set(char chr, bool set) return chr | 0x20; } -static void net_tcp_trace(struct net_pkt *pkt, struct net_tcp *tcp) +static void net_tcp_trace(struct net_pkt *pkt, + struct net_tcp *tcp, + struct net_tcp_hdr *tcp_hdr) { - struct net_tcp_hdr hdr, *tcp_hdr; u32_t rel_ack, ack; u8_t flags; @@ -126,11 +127,6 @@ static void net_tcp_trace(struct net_pkt *pkt, struct net_tcp *tcp) return; } - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (!tcp_hdr) { - return; - } - flags = NET_TCP_FLAGS(tcp_hdr); ack = sys_get_be32(tcp_hdr->ack); @@ -492,7 +488,7 @@ static int prepare_segment(struct net_tcp *tcp, return status; } - net_tcp_trace(pkt, tcp); + net_tcp_trace(pkt, tcp, tcp_hdr); *out_pkt = pkt; @@ -861,11 +857,26 @@ static int net_tcp_queue_pkt(struct net_context *context, struct net_pkt *pkt) int net_tcp_send_pkt(struct net_pkt *pkt) { + NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); struct net_context *ctx = net_pkt_context(pkt); - struct net_tcp_hdr hdr, *tcp_hdr; + struct net_tcp_hdr *tcp_hdr; bool calc_chksum = false; - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); + if (!ctx || !ctx->tcp) { + NET_ERR("%scontext is not set on pkt %p", + !ctx ? "" : "TCP ", pkt); + return -EINVAL; + } + + net_pkt_cursor_init(pkt); + net_pkt_set_overwrite(pkt, true); + + if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt))) { + return -EMSGSIZE; + } + + tcp_hdr = (struct net_tcp_hdr *)net_pkt_get_data_new(pkt, &tcp_access); if (!tcp_hdr) { NET_ERR("Packet %p does not contain TCP header", pkt); return -EMSGSIZE; @@ -873,6 +884,7 @@ int net_tcp_send_pkt(struct net_pkt *pkt) if (sys_get_be32(tcp_hdr->ack) != ctx->tcp->send_ack) { sys_put_be32(ctx->tcp->send_ack, tcp_hdr->ack); + tcp_hdr->chksum = 0; calc_chksum = true; } @@ -884,11 +896,23 @@ int net_tcp_send_pkt(struct net_pkt *pkt) if (ctx->tcp->sent_ack != ctx->tcp->send_ack && (tcp_hdr->flags & NET_TCP_ACK) == 0) { tcp_hdr->flags |= NET_TCP_ACK; + tcp_hdr->chksum = 0; calc_chksum = true; } + /* As we modified the header, we need to write it back. + */ + net_pkt_set_data(pkt, &tcp_access); + if (calc_chksum) { - net_tcp_set_chksum(pkt, pkt->frags); + net_pkt_cursor_init(pkt); + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt)); + + /* No need to get tcp_hdr again */ + tcp_hdr->chksum = net_calc_chksum_tcp(pkt); + + net_pkt_set_data(pkt, &tcp_access); } if (tcp_hdr->flags & NET_TCP_FIN) { @@ -897,10 +921,6 @@ int net_tcp_send_pkt(struct net_pkt *pkt) ctx->tcp->sent_ack = ctx->tcp->send_ack; - /* As we modified the header, we need to write it back. - */ - net_tcp_set_hdr(pkt, tcp_hdr); - /* We must have special handling for some network technologies that * tweak the IP protocol headers during packet sending. This happens * with Bluetooth and IEEE 802.15.4 which use IPv6 header compression @@ -929,7 +949,7 @@ int net_tcp_send_pkt(struct net_pkt *pkt) } if (pkt_in_slist) { - new_pkt = net_pkt_clone(pkt, ALLOC_TIMEOUT); + new_pkt = net_pkt_clone_new(pkt, ALLOC_TIMEOUT); if (!new_pkt) { return -ENOMEM; } @@ -1038,14 +1058,26 @@ bool net_tcp_ack_received(struct net_context *ctx, u32_t ack) } while (!sys_slist_is_empty(list)) { - struct net_tcp_hdr hdr, *tcp_hdr; + NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); + struct net_tcp_hdr *tcp_hdr; u32_t last_seq; u32_t seq_len; head = sys_slist_peek_head(list); pkt = CONTAINER_OF(head, struct net_pkt, sent_list); - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); + net_pkt_cursor_init(pkt); + net_pkt_set_overwrite(pkt, true); + + if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt))) { + sys_slist_remove(list, NULL, head); + net_pkt_unref(pkt); + continue; + } + + tcp_hdr = (struct net_tcp_hdr *)net_pkt_get_data_new( + pkt, &tcp_access); if (!tcp_hdr) { /* The pkt does not contain TCP header, this should * not happen. @@ -1236,109 +1268,83 @@ bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_tcp_hdr *tcp_hdr) struct net_tcp_hdr *net_tcp_get_hdr(struct net_pkt *pkt, struct net_tcp_hdr *hdr) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(tcp_access, struct net_tcp_hdr); + struct net_pkt_cursor backup; struct net_tcp_hdr *tcp_hdr; - struct net_buf *frag; - u16_t pos; + bool overwrite; - tcp_hdr = net_pkt_tcp_data(pkt); - if (!tcp_hdr) { - NET_ERR("NULL TCP header!"); - return NULL; - } + tcp_access.data = hdr; - if (net_tcp_header_fits(pkt, tcp_hdr)) { - return tcp_hdr; - } + overwrite = net_pkt_is_being_overwritten(pkt); + net_pkt_set_overwrite(pkt, true); - 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->seq), hdr->seq); - frag = net_frag_read(frag, pos, &pos, sizeof(hdr->ack), hdr->ack); - frag = net_frag_read_u8(frag, pos, &pos, &hdr->offset); - frag = net_frag_read_u8(frag, pos, &pos, &hdr->flags); - frag = net_frag_read(frag, pos, &pos, sizeof(hdr->wnd), hdr->wnd); - frag = net_frag_read(frag, pos, &pos, sizeof(hdr->chksum), - (u8_t *)&hdr->chksum); - frag = net_frag_read(frag, pos, &pos, sizeof(hdr->urg), hdr->urg); - - if (!frag && pos == 0xffff) { - /* If the pkt is compressed, then this is the typical outcome - * so no use printing error in this case. - */ - if ((CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG) && - !is_6lo_technology(pkt)) { - NET_ASSERT(frag); - } + net_pkt_cursor_backup(pkt, &backup); + net_pkt_cursor_init(pkt); - return NULL; + if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt))) { + tcp_hdr = NULL; + goto out; } - return hdr; + tcp_hdr = (struct net_tcp_hdr *)net_pkt_get_data_new(pkt, &tcp_access); + +out: + net_pkt_cursor_restore(pkt, &backup); + net_pkt_set_overwrite(pkt, overwrite); + + return tcp_hdr; } struct net_tcp_hdr *net_tcp_set_hdr(struct net_pkt *pkt, struct net_tcp_hdr *hdr) { - struct net_buf *frag; - u16_t pos; + NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); + struct net_pkt_cursor backup; + struct net_tcp_hdr *tcp_hdr; + bool overwrite; - if (net_tcp_header_fits(pkt, hdr)) { - return hdr; - } + overwrite = net_pkt_is_being_overwritten(pkt); + net_pkt_set_overwrite(pkt, true); - 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, ALLOC_TIMEOUT); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->dst_port), - (u8_t *)&hdr->dst_port, ALLOC_TIMEOUT); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->seq), hdr->seq, - ALLOC_TIMEOUT); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->ack), hdr->ack, - ALLOC_TIMEOUT); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->offset), - &hdr->offset, ALLOC_TIMEOUT); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->flags), - &hdr->flags, ALLOC_TIMEOUT); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->wnd), hdr->wnd, - ALLOC_TIMEOUT); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->chksum), - (u8_t *)&hdr->chksum, ALLOC_TIMEOUT); - frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->urg), hdr->urg, - ALLOC_TIMEOUT); + net_pkt_cursor_backup(pkt, &backup); + net_pkt_cursor_init(pkt); - if (!frag) { - NET_ASSERT(frag); - return NULL; + if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt))) { + tcp_hdr = NULL; + goto out; } - return hdr; + tcp_hdr = (struct net_tcp_hdr *)net_pkt_get_data_new(pkt, &tcp_access); + if (!tcp_hdr) { + goto out; + } + + memcpy(tcp_hdr, hdr, sizeof(struct net_tcp_hdr)); + + net_pkt_set_data(pkt, &tcp_access); +out: + net_pkt_cursor_restore(pkt, &backup); + net_pkt_set_overwrite(pkt, overwrite); + + return tcp_hdr == NULL ? NULL : hdr; } -u16_t net_tcp_get_chksum(struct net_pkt *pkt, struct net_buf *frag) +int net_tcp_finalize(struct net_pkt *pkt) { - struct net_tcp_hdr *hdr; - u16_t chksum; - u16_t pos; + NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); + struct net_tcp_hdr *tcp_hdr; - hdr = net_pkt_tcp_data(pkt); - if (net_tcp_header_fits(pkt, hdr)) { - return hdr->chksum; + tcp_hdr = (struct net_tcp_hdr *)net_pkt_get_data_new(pkt, &tcp_access); + if (!tcp_hdr) { + return -ENOBUFS; } - frag = net_frag_read(frag, - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - 2 + 2 + 4 + 4 + /* src + dst + seq + ack */ - 1 + 1 + 2 /* offset + flags + wnd */, - &pos, sizeof(chksum), (u8_t *)&chksum); - NET_ASSERT(frag); + tcp_hdr->chksum = 0; + tcp_hdr->chksum = net_calc_chksum_tcp(pkt); - return chksum; + return net_pkt_set_data(pkt, &tcp_access); } struct net_buf *net_tcp_set_chksum(struct net_pkt *pkt, struct net_buf *frag) @@ -1377,21 +1383,14 @@ struct net_buf *net_tcp_set_chksum(struct net_pkt *pkt, struct net_buf *frag) int net_tcp_parse_opts(struct net_pkt *pkt, int opt_totlen, struct net_tcp_options *opts) { - struct net_buf *frag = pkt->frags; - u16_t pos = net_pkt_ip_hdr_len(pkt) - + net_pkt_ipv6_ext_len(pkt) - + sizeof(struct net_tcp_hdr); u8_t opt, optlen; - /* TODO: this should be done for each TCP pkt, on reception */ - if (pos + opt_totlen > net_pkt_get_len(pkt)) { - NET_ERR("Truncated pkt len: %d, expected: %d", - (int)net_pkt_get_len(pkt), pos + opt_totlen); - return -EINVAL; - } - while (opt_totlen) { - frag = net_frag_read(frag, pos, &pos, sizeof(opt), &opt); + if (net_pkt_read_u8_new(pkt, &opt)) { + optlen = 0U; + goto error; + } + opt_totlen--; /* https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml#tcp-parameters-1 */ @@ -1411,12 +1410,12 @@ int net_tcp_parse_opts(struct net_pkt *pkt, int opt_totlen, goto error; } - frag = net_frag_read(frag, pos, &pos, sizeof(optlen), &optlen); - opt_totlen--; - if (optlen < 2) { + if (net_pkt_read_u8_new(pkt, &optlen) || optlen < 2) { goto error; } + opt_totlen--; + /* Subtract opt/optlen size now to avoid doing this * repeatedly. */ @@ -1430,11 +1429,17 @@ int net_tcp_parse_opts(struct net_pkt *pkt, int opt_totlen, if (optlen != 2) { goto error; } - frag = net_frag_read_be16(frag, pos, &pos, - &opts->mss); + + if (net_pkt_read_be16_new(pkt, &opts->mss)) { + goto error; + } + break; default: - frag = net_frag_skip(frag, pos, &pos, optlen); + if (net_pkt_skip(pkt, optlen)) { + goto error; + } + break; } @@ -1450,9 +1455,17 @@ int net_tcp_parse_opts(struct net_pkt *pkt, int opt_totlen, int tcp_hdr_len(struct net_pkt *pkt) { - struct net_tcp_hdr hdr, *tcp_hdr; + NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); + struct net_tcp_hdr *tcp_hdr; - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); + net_pkt_cursor_init(pkt); + + if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt))) { + return 0; + } + + tcp_hdr = (struct net_tcp_hdr *)net_pkt_get_data_new(pkt, &tcp_access); if (tcp_hdr) { return NET_TCP_HDR_LEN(tcp_hdr); } @@ -1868,15 +1881,27 @@ int net_tcp_unref(struct net_context *context) } \ } -static void print_send_info(struct net_pkt *pkt, const char *msg) +static void print_send_info(struct net_pkt *pkt, + const char *msg, const struct sockaddr *remote) { if (CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG) { - struct net_tcp_hdr hdr, *tcp_hdr; + u16_t port = 0; - tcp_hdr = net_tcp_get_hdr(pkt, &hdr); - if (tcp_hdr) { - net_tcp_print_send_info(msg, pkt, tcp_hdr->dst_port); + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_pkt_family(pkt) == AF_INET) { + struct sockaddr_in *addr4 = net_sin(remote); + + port = addr4->sin_port; + } + + if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6) { + struct sockaddr_in6 *addr6 = net_sin6(remote); + + port = addr6->sin6_port; } + + net_tcp_print_send_info(msg, pkt, port); } } @@ -1901,7 +1926,7 @@ static inline int send_syn_segment(struct net_context *context, return ret; } - print_send_info(pkt, msg); + print_send_info(pkt, msg, remote); ret = net_send_data(pkt); if (ret < 0) { @@ -1949,7 +1974,7 @@ static int send_ack(struct net_context *context, return ret; } - print_send_info(pkt, "ACK"); + print_send_info(pkt, "ACK", remote); ret = net_tcp_send_pkt(pkt); if (ret < 0) { @@ -1971,7 +1996,7 @@ static int send_reset(struct net_context *context, return ret; } - print_send_info(pkt, "RST"); + print_send_info(pkt, "RST", remote); ret = net_send_data(pkt); if (ret < 0) { diff --git a/subsys/net/ip/tcp_internal.h b/subsys/net/ip/tcp_internal.h index 268732dce2fbc..217678a01cd45 100644 --- a/subsys/net/ip/tcp_internal.h +++ b/subsys/net/ip/tcp_internal.h @@ -400,26 +400,24 @@ static inline enum net_tcp_state net_tcp_get_state(const struct net_tcp *tcp) bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_tcp_hdr *tcp_hdr); /** - * @brief Set TCP checksum in network packet. + * @brief Finalize TCP 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. + * @return 0 on success, negative errno otherwise. */ -struct net_buf *net_tcp_set_chksum(struct net_pkt *pkt, struct net_buf *frag); +int net_tcp_finalize(struct net_pkt *pkt); /** - * @brief Get TCP checksum from network packet. + * @brief Set TCP 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 checksum in host byte order. + * @return Return the actual fragment where the checksum was written. */ -u16_t net_tcp_get_chksum(struct net_pkt *pkt, struct net_buf *frag); +struct net_buf *net_tcp_set_chksum(struct net_pkt *pkt, struct net_buf *frag); /** * @brief Parse TCP options from network packet. @@ -664,11 +662,9 @@ static inline bool net_tcp_validate_seq(struct net_tcp *tcp, return false; } -static inline u16_t net_tcp_get_chksum(struct net_pkt *pkt, - struct net_buf *frag) +static inline int net_tcp_finalize(struct net_pkt *pkt) { ARG_UNUSED(pkt); - ARG_UNUSED(frag); return 0; } diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c index b993eaeca73bd..d4ff0061200ed 100644 --- a/tests/net/tcp/src/main.c +++ b/tests/net/tcp/src/main.c @@ -1455,6 +1455,7 @@ static bool test_tcp_seq_validity(void) struct net_tcp *tcp = v6_ctx->tcp; u8_t flags = NET_TCP_RST; struct net_pkt *pkt = NULL; + struct net_tcp_hdr hdr, *tcp_hdr; int ret; ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL, @@ -1464,34 +1465,40 @@ static bool test_tcp_seq_validity(void) return false; } - tcp->send_ack = sys_get_be32(NET_TCP_HDR(pkt)->seq) - + tcp_hdr = net_tcp_get_hdr(pkt, &hdr); + if (!tcp_hdr) { + DBG("Grabbing TCP hdr failed\n"); + return false; + } + + tcp->send_ack = sys_get_be32(tcp_hdr->seq) - get_recv_wnd(tcp) / 2; - if (!net_tcp_validate_seq(tcp, pkt)) { + if (!net_tcp_validate_seq(tcp, tcp_hdr)) { DBG("1) Sequence validation failed (send_ack %u vs seq %u)\n", - tcp->send_ack, sys_get_be32(NET_TCP_HDR(pkt)->seq)); + tcp->send_ack, sys_get_be32(tcp_hdr->seq)); return false; } - tcp->send_ack = sys_get_be32(NET_TCP_HDR(pkt)->seq); - if (!net_tcp_validate_seq(tcp, pkt)) { + tcp->send_ack = sys_get_be32(tcp_hdr->seq); + if (!net_tcp_validate_seq(tcp, tcp_hdr)) { DBG("2) Sequence validation failed (send_ack %u vs seq %u)\n", - tcp->send_ack, sys_get_be32(NET_TCP_HDR(pkt)->seq)); + tcp->send_ack, sys_get_be32(tcp_hdr->seq)); return false; } - tcp->send_ack = sys_get_be32(NET_TCP_HDR(pkt)->seq) + + tcp->send_ack = sys_get_be32(tcp_hdr->seq) + 2 * get_recv_wnd(tcp); - if (net_tcp_validate_seq(tcp, pkt)) { + if (net_tcp_validate_seq(tcp, tcp_hdr)) { DBG("3) Sequence validation failed (send_ack %u vs seq %u)\n", - tcp->send_ack, sys_get_be32(NET_TCP_HDR(pkt)->seq)); + tcp->send_ack, sys_get_be32(tcp_hdr->seq)); return false; } - tcp->send_ack = sys_get_be32(NET_TCP_HDR(pkt)->seq) - + tcp->send_ack = sys_get_be32(tcp_hdr->seq) - 2 * get_recv_wnd(tcp); - if (net_tcp_validate_seq(tcp, pkt)) { + if (net_tcp_validate_seq(tcp, tcp_hdr)) { DBG("4) Sequence validation failed (send_ack %u vs seq %u)\n", - tcp->send_ack, sys_get_be32(NET_TCP_HDR(pkt)->seq)); + tcp->send_ack, sys_get_be32(tcp_hdr->seq)); return false; } From 51d24c2fb05bf60d15ea26c638e5ba30098bf005 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 16 Jan 2019 10:38:06 +0100 Subject: [PATCH 64/70] tests/icmpv6: Real packet length must be given The test counts the '\0' of the data copied, though it does not belong to the packet. Since the test by-passes net_ipv6_input, which would update the packet length according to what is in the IPv6 header, the checksum calculation fails. Before, checksum calculation used to grab the length from IPv6 header, but that changed to use net_pkt_get_len(): that one must provide the real lenth. Signed-off-by: Tomasz Bursztyka --- tests/net/icmpv6/prj.conf | 1 + tests/net/icmpv6/src/main.c | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/net/icmpv6/prj.conf b/tests/net/icmpv6/prj.conf index 9a5e878f3497c..8fd3358b8690d 100644 --- a/tests/net/icmpv6/prj.conf +++ b/tests/net/icmpv6/prj.conf @@ -13,3 +13,4 @@ CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_ZTEST=y CONFIG_MAIN_STACK_SIZE=1280 + diff --git a/tests/net/icmpv6/src/main.c b/tests/net/icmpv6/src/main.c index 9e3306b3eb220..89546f2bf3ff9 100644 --- a/tests/net/icmpv6/src/main.c +++ b/tests/net/icmpv6/src/main.c @@ -28,7 +28,7 @@ static int handler_status; #define TEST_MSG "foobar devnull" -#define ICMPV6_MSG_SIZE 105 +#define ICMPV6_MSG_SIZE 104 static char icmpv6_echo_req[] = "\x60\x02\xea\x12\x00\x40\x3a\x40\xfe\x80\x00\x00\x00\x00\x00\x00" \ @@ -115,8 +115,8 @@ void test_icmpv6(void) net_pkt_set_family(pkt, AF_INET6); net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); - memcpy(net_buf_add(frag, sizeof(icmpv6_inval_chksum)), - icmpv6_inval_chksum, sizeof(icmpv6_inval_chksum)); + memcpy(net_buf_add(frag, ICMPV6_MSG_SIZE), + icmpv6_inval_chksum, ICMPV6_MSG_SIZE); hdr = (struct net_ipv6_hdr *)pkt->buffer->data; net_pkt_cursor_init(pkt); @@ -131,8 +131,8 @@ void test_icmpv6(void) handler_status = -1; frag->len = 0; - memcpy(net_buf_add(frag, sizeof(icmpv6_echo_rep)), - icmpv6_echo_rep, sizeof(icmpv6_echo_rep)); + memcpy(net_buf_add(frag, ICMPV6_MSG_SIZE), + icmpv6_echo_rep, ICMPV6_MSG_SIZE); hdr = (struct net_ipv6_hdr *)pkt->buffer->data; net_pkt_cursor_init(pkt); @@ -148,8 +148,8 @@ void test_icmpv6(void) handler_status = -1; frag->len = 0; - memcpy(net_buf_add(frag, sizeof(icmpv6_echo_req)), - icmpv6_echo_req, sizeof(icmpv6_echo_req)); + memcpy(net_buf_add(frag, ICMPV6_MSG_SIZE), + icmpv6_echo_req, ICMPV6_MSG_SIZE); hdr = (struct net_ipv6_hdr *)pkt->buffer->data; net_pkt_cursor_init(pkt); From ff9d54396714a2877c96486a721d3c99831cdb98 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 18 Jan 2019 09:03:14 +0100 Subject: [PATCH 65/70] net/context: Enable support for TCP on new sendto function Let's enable usage of TCP through net_context on its new sendto function. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/net_context.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 586d9401a6c11..5e3ebe97141c5 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1342,10 +1342,6 @@ static int context_sendto_new(struct net_context *context, return -EBADF; } - if (net_context_get_ip_proto(context) == IPPROTO_TCP) { - return -ENOTSUP; - } - if (!dst_addr) { return -EDESTADDRREQ; } @@ -1405,8 +1401,20 @@ static int context_sendto_new(struct net_context *context, ret = net_send_data(pkt); } else if (IS_ENABLED(CONFIG_NET_TCP) && net_context_get_ip_proto(context) == IPPROTO_TCP) { - /* TCP is not supported yet to work on new net_pkt API */ - ret = -ENOTSUP; + ret = net_pkt_write_new(pkt, buf, len); + if (ret < 0) { + goto fail; + } + + sent = len; + + net_pkt_cursor_init(pkt); + ret = net_tcp_queue_data(context, pkt); + if (ret < 0) { + goto fail; + } + + ret = net_tcp_send_data(context, cb, token, user_data); } else { NET_DBG("Unknown protocol while sending packet: %d", net_context_get_ip_proto(context)); From e0b53403c506fecb44426887a22f9dbf2088fbf2 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 18 Jan 2019 12:42:41 +0100 Subject: [PATCH 66/70] net/tcp: Fix net_tcp_print_recv/send_info macros Context was missing, and anyway the familiy can be grabbed from the packet. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/tcp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 9be8899cb1c20..6d190e861a6fd 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -1852,12 +1852,12 @@ int net_tcp_unref(struct net_context *context) #define net_tcp_print_recv_info(str, pkt, port) \ if (IS_ENABLED(CONFIG_NET_TCP_LOG_LEVEL_DBG)) { \ - if (net_context_get_family(context) == AF_INET6) { \ + if (net_pkt_family(pkt) == AF_INET6) { \ NET_DBG("%s received from %s port %d", str, \ log_strdup(net_sprint_ipv6_addr( \ &NET_IPV6_HDR(pkt)->src)), \ ntohs(port)); \ - } else if (net_context_get_family(context) == AF_INET) {\ + } else if (net_pkt_family(pkt) == AF_INET) {\ NET_DBG("%s received from %s port %d", str, \ log_strdup(net_sprint_ipv4_addr( \ &NET_IPV4_HDR(pkt)->src)), \ @@ -1867,13 +1867,12 @@ int net_tcp_unref(struct net_context *context) #define net_tcp_print_send_info(str, pkt, port) \ if (IS_ENABLED(CONFIG_NET_TCP_LOG_LEVEL_DBG)) { \ - struct net_context *ctx = net_pkt_context(pkt); \ - if (net_context_get_family(ctx) == AF_INET6) { \ + if (net_pkt_family(pkt) == AF_INET6) { \ NET_DBG("%s sent to %s port %d", str, \ log_strdup(net_sprint_ipv6_addr( \ &NET_IPV6_HDR(pkt)->dst)), \ ntohs(port)); \ - } else if (net_context_get_family(ctx) == AF_INET) { \ + } else if (net_pkt_family(pkt) == AF_INET) { \ NET_DBG("%s sent to %s port %d", str, \ log_strdup(net_sprint_ipv4_addr( \ &NET_IPV4_HDR(pkt)->dst)), \ From 4e0eba97e22973a7ab570e2670c3c73c3fe83d3b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 3 Oct 2018 15:29:24 +0200 Subject: [PATCH 67/70] test/net: Quick sample explaining/testing the new net_pkt buffer API This goes through basic allocation, atomic read/write, data getter/setter and cloning/copying. Signed-off-by: Tomasz Bursztyka --- tests/net/net_pkt_new/CMakeLists.txt | 6 + tests/net/net_pkt_new/prj.conf | 14 + tests/net/net_pkt_new/src/main.c | 615 +++++++++++++++++++++++++++ tests/net/net_pkt_new/testcase.yaml | 7 + 4 files changed, 642 insertions(+) create mode 100644 tests/net/net_pkt_new/CMakeLists.txt create mode 100644 tests/net/net_pkt_new/prj.conf create mode 100644 tests/net/net_pkt_new/src/main.c create mode 100644 tests/net/net_pkt_new/testcase.yaml diff --git a/tests/net/net_pkt_new/CMakeLists.txt b/tests/net/net_pkt_new/CMakeLists.txt new file mode 100644 index 0000000000000..bcb30403b1a03 --- /dev/null +++ b/tests/net/net_pkt_new/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.13.1) +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/net/net_pkt_new/prj.conf b/tests/net/net_pkt_new/prj.conf new file mode 100644 index 0000000000000..764d86554af08 --- /dev/null +++ b/tests/net/net_pkt_new/prj.conf @@ -0,0 +1,14 @@ +CONFIG_NET_TEST=y +CONFIG_ZTEST=y + +CONFIG_NETWORKING=y +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=n +CONFIG_NET_ARP=y +CONFIG_NET_UDP=y +CONFIG_NET_BUF_LOG=y +CONFIG_NET_LOG=y + +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/tests/net/net_pkt_new/src/main.c b/tests/net/net_pkt_new/src/main.c new file mode 100644 index 0000000000000..5bd3fbf442392 --- /dev/null +++ b/tests/net/net_pkt_new/src/main.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static u8_t mac_addr[sizeof(struct net_eth_addr)]; +static struct net_if *eth_if; +static u8_t small_buffer[512]; + +/************************\ + * FAKE ETHERNET DEVICE * +\************************/ + +static void fake_dev_iface_init(struct net_if *iface) +{ + if (mac_addr[2] == 0) { + /* 00-00-5E-00-53-xx Documentation RFC 7042 */ + mac_addr[0] = 0x00; + mac_addr[1] = 0x00; + mac_addr[2] = 0x5E; + mac_addr[3] = 0x00; + mac_addr[4] = 0x53; + mac_addr[5] = sys_rand32_get(); + } + + net_if_set_link_addr(iface, mac_addr, 6, NET_LINK_ETHERNET); + + eth_if = iface; +} + +static int fake_dev_send(struct device *dev, struct net_pkt *pkt) +{ + return 0; +} + +int fake_dev_init(struct device *dev) +{ + ARG_UNUSED(dev); + + return 0; +} + +#if defined(CONFIG_NET_L2_ETHERNET) +static const struct ethernet_api fake_dev_api = { + .iface_api.init = fake_dev_iface_init, + .send = fake_dev_send, +}; + +#define _ETH_L2_LAYER ETHERNET_L2 +#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(ETHERNET_L2) +#else +static const struct dummy_api fake_dev_api = { + .iface_api.init = fake_dev_iface_init, + .send = fake_dev_send, +}; + +#define _ETH_L2_LAYER DUMMY_L2 +#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2) +#endif + +NET_DEVICE_INIT(fake_dev, "fake_dev", + fake_dev_init, NULL, NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &fake_dev_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, 1500); + +/*********************\ + * UTILITY FUNCTIONS * +\*********************/ + +static bool pkt_is_of_size(struct net_pkt *pkt, size_t size) +{ + return (net_pkt_available_buffer(pkt) == size); +} + +static void pkt_print_cursor(struct net_pkt *pkt) +{ + if (!pkt || !pkt->cursor.buf || !pkt->cursor.pos) { + printk("Unknown position\n"); + } else { + printk("Position %zu (%p) in net_buf %p (data %p)\n", + pkt->cursor.pos - pkt->cursor.buf->data, + pkt->cursor.pos, pkt->cursor.buf, + pkt->cursor.buf->data); + } +} + + +/*****************************\ + * HOW TO ALLOCATE - 2 TESTS * +\*****************************/ + +static void test_net_pkt_allocate_wo_buffer(void) +{ + struct net_pkt *pkt; + + /* How to allocate a packet, with no buffer */ + pkt = net_pkt_alloc(K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + /* Freeing the packet */ + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); + + /* Note that, if you already know the iface to which the packet + * belongs to, you will be able to use net_pkt_alloc_on_iface(). + */ + pkt = net_pkt_alloc_on_iface(eth_if, K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); +} + +static void test_net_pkt_allocate_with_buffer(void) +{ + struct net_pkt *pkt; + + /* How to allocate a packet, with buffer + * a) - with a size that will fit MTU, let's say 512 bytes + * Note: we don't care of the family/protocol for now + */ + pkt = net_pkt_alloc_with_buffer(eth_if, 512, + AF_UNSPEC, 0, K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + /* Did we get the requested size? */ + zassert_true(pkt_is_of_size(pkt, 512), "Pkt size is not right"); + + /* Freeing the packet */ + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); + + /* + * b) - with a size that will not fit MTU, let's say 1800 bytes + * Note: again we don't care of family/protocol for now. + */ + pkt = net_pkt_alloc_with_buffer(eth_if, 1800, + AF_UNSPEC, 0, K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + zassert_false(pkt_is_of_size(pkt, 1800), "Pkt size is not right"); + zassert_true(pkt_is_of_size(pkt, net_if_get_mtu(eth_if)), + "Pkt size is not right"); + + /* Freeing the packet */ + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); + + /* + * c) - Now with 512 bytes but on IPv4/UDP + */ + pkt = net_pkt_alloc_with_buffer(eth_if, 512, AF_INET, + IPPROTO_UDP, K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + /* Because 512 + NET_IPV4UDPH_LEN fits MTU, total must be that one */ + zassert_true(pkt_is_of_size(pkt, 512 + NET_IPV4UDPH_LEN), + "Pkt overall size does not match"); + + /* Freeing the packet */ + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); + + /* + * c) - Now with 1800 bytes but on IPv4/UDP + */ + pkt = net_pkt_alloc_with_buffer(eth_if, 1800, AF_INET, + IPPROTO_UDP, K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + /* Because 1800 + NET_IPV4UDPH_LEN won't fit MTU, payload size + * should be MTU + */ + zassert_true(net_pkt_available_buffer(pkt) == + net_if_get_mtu(eth_if), + "Payload buf size does not match for ipv4/udp"); + + /* Freeing the packet */ + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); +} + +/********************************\ + * HOW TO R/W A PACKET - TESTS * +\********************************/ + +static void test_net_pkt_basics_of_rw(void) +{ + struct net_pkt *pkt; + int ret; + + pkt = net_pkt_alloc_with_buffer(eth_if, 512, + AF_UNSPEC, 0, K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + /* Once newly allocated with buffer, + * a packet has no data accounted for in its buffer + */ + zassert_true(net_pkt_get_len(pkt) == 0, + "Pkt initial length should be 0"); + + /* This is done through net_buf which can distinguish + * the size of a buffer from the length of the data in it. + */ + + /* Let's subsequently write 1 byte, then 2 bytes and 4 bytes + * We write values made of 0s + */ + ret = net_pkt_write_u8_new(pkt, 0); + zassert_true(ret == 0, "Pkt write failed"); + + /* Length should be 1 now */ + zassert_true(net_pkt_get_len(pkt) == 1, "Pkt length mismatch"); + + ret = net_pkt_write_be16_new(pkt, 0); + zassert_true(ret == 0, "Pkt write failed"); + + /* Length should be 3 now */ + zassert_true(net_pkt_get_len(pkt) == 3, "Pkt length mismatch"); + + ret = net_pkt_write_be32_new(pkt, 0); + zassert_true(ret == 0, "Pkt write failed"); + + /* Length should be 7 now */ + zassert_true(net_pkt_get_len(pkt) == 7, "Pkt length mismatch"); + + /* All these writing functions use net_ptk_write(), which works + * this way: + */ + ret = net_pkt_write_new(pkt, small_buffer, 9); + zassert_true(ret == 0, "Pkt write failed"); + + /* Length should be 16 now */ + zassert_true(net_pkt_get_len(pkt) == 16, "Pkt length mismatch"); + + /* Now let's say you want to memset some data */ + ret = net_pkt_memset(pkt, 0, 4); + zassert_true(ret == 0, "Pkt memset failed"); + + /* Length should be 20 now */ + zassert_true(net_pkt_get_len(pkt) == 20, "Pkt length mismatch"); + + /* So memset affects the length exactly as write does */ + + /* Sometimes you might want to advance in the buffer without caring + * what's written there since you'll eventually come back for that. + * net_pkt_skip() is used for it. + * Note: usally you will not have to use that function a lot yourself. + */ + ret = net_pkt_skip(pkt, 20); + zassert_true(ret == 0, "Pkt skip failed"); + + /* Length should be 40 now */ + zassert_true(net_pkt_get_len(pkt) == 40, "Pkt length mismatch"); + + /* Again, skip affected the length also, like a write + * But wait a minute: how to get back then, in order to write at + * the position we just skipped? + * + * So let's introduce the concept of buffer cursor. (which could + * be named 'cursor' if such name has more relevancy. Basically, each + * net_pkt embeds such 'cursor': it's like a head of a tape + * recorder/reader, it holds the current position in the buffer where + * you can r/w. All operations use and update it below. + * There is, however, a catch: buffer is described through net_buf + * and these are like a simple linked-list. + * Which means that unlike a tape recorder/reader: you are not + * able to go backward. Only back from starting point and forward. + * Thus why there is a net_pkt_cursor_init(pkt) which will let you going + * back from the start. We could hold more info in order to avoid that, + * but that would mean growing each an every net_buf. + */ + net_pkt_cursor_init(pkt); + + /* But isn't it so that if I want to go at the previous position I + * skipped, I'll use skip again but then won't it affect again the + * length? + * Answer is yes. Hopefully there is a mean to avoid that. Basically + * for data that already "exists" in the buffer (aka: data accounted + * for in the buffer, through the length) you'll need to set the packet + * to overwrite: all subsequent operations will then work on existing + * data and will not affect the length (it won't add more data) + */ + net_pkt_set_overwrite(pkt, true); + + zassert_true(net_pkt_is_being_overwritten(pkt), + "Pkt is not set to overwrite"); + + /* Ok so previous skipped position was at offset 20 */ + ret = net_pkt_skip(pkt, 20); + zassert_true(ret == 0, "Pkt skip failed"); + + /* Length should _still_ be 40 */ + zassert_true(net_pkt_get_len(pkt) == 40, "Pkt length mismatch"); + + /* And you can write stuff */ + ret = net_pkt_write_le32_new(pkt, 0); + zassert_true(ret == 0, "Pkt write failed"); + + /* Again, length should _still_ be 40 */ + zassert_true(net_pkt_get_len(pkt) == 40, "Pkt length mismatch"); + + /* Let's memset the rest */ + ret = net_pkt_memset(pkt, 0, 16); + zassert_true(ret == 0, "Pkt memset failed"); + + /* Again, length should _still_ be 40 */ + zassert_true(net_pkt_get_len(pkt) == 40, "Pkt length mismatch"); + + /* We are now back at the end of the existing data in the buffer + * Since overwrite is still on, we should not be able to r/w + * anything. + * This is completely nominal, as being set, overwrite allows r/w only + * on existing data in the buffer: + */ + ret = net_pkt_write_be32_new(pkt, 0); + zassert_true(ret != 0, "Pkt write succeeded where it shouldn't have"); + + /* Logically, in order to be able to add new data in the buffer, + * overwrite should be disabled: + */ + net_pkt_set_overwrite(pkt, false); + + /* But it will fail: */ + ret = net_pkt_write_le32_new(pkt, 0); + zassert_true(ret != 0, "Pkt write succeeded?"); + + /* Why is that? + * This is because in case of r/w error: the iterator is invalidated. + * This a design choice, once you get a r/w error it means your code + * messed up requesting smaller buffer than you actually needed, or + * writing too much data than it should have been etc...). + * So you must drop your packet entirely. + */ + + /* Freeing the packet */ + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); +} + +void test_net_pkt_advanced_basics(void) +{ + struct net_pkt_cursor backup; + struct net_pkt *pkt; + int ret; + + pkt = net_pkt_alloc_with_buffer(eth_if, 512, + AF_INET, IPPROTO_UDP, K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + pkt_print_cursor(pkt); + + /* As stated earlier, initializing the cursor, is the way to go + * back from the start in the buffer (either header or payload then). + * We also showed that using net_pkt_skip() could be used to move + * forward in the buffer. + * But what if you are far in the buffer, you need to go backward, + * and back again to your previous position? + * You could certainly do: + */ + ret = net_pkt_write_new(pkt, small_buffer, 20); + zassert_true(ret == 0, "Pkt write failed"); + + pkt_print_cursor(pkt); + + net_pkt_cursor_init(pkt); + + pkt_print_cursor(pkt); + + /* ... do something here ... */ + + /* And finally go back with overwrite/skip: */ + net_pkt_set_overwrite(pkt, true); + ret = net_pkt_skip(pkt, 20); + zassert_true(ret == 0, "Pkt skip failed"); + net_pkt_set_overwrite(pkt, false); + + pkt_print_cursor(pkt); + + /* In this example, do not focus on the 20 bytes. It is just for + * the sake of the example. + * The other method is backup/restore the packet cursor. + */ + net_pkt_cursor_backup(pkt, &backup); + + net_pkt_cursor_init(pkt); + + /* ... do something here ... */ + + /* and restore: */ + net_pkt_cursor_restore(pkt, &backup); + + pkt_print_cursor(pkt); + + /* Another feature, is how you access your data. Earlier was + * presented basic r/w functions. But sometime you might want to + * access your data directly through a structure/type etc... + * Due to the "fragmented" possible nature of your buffer, you + * need to know if the data you are trying to access is in + * contiguous area. + * For this, you'll use: + */ + ret = (int) net_pkt_is_contiguous(pkt, 4); + zassert_true(ret == 1, "Pkt contiguity check failed"); + + /* If that's successful you should be able to get the actual + * position in the buffer and cast it to the type you want. + */ + { + u32_t *val = (u32_t *)net_pkt_cursor_get_pos(pkt); + + *val = 0; + /* etc... */ + } + + /* However, to advance your cursor, since none of the usual r/w + * functions got used: net_pkt_skip() should be called relevantly: + */ + net_pkt_skip(pkt, 4); + + /* Freeing the packet */ + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); + + /* Obviously one will very rarely use these 2 last low level functions + * - net_pkt_is_contiguous() + * - net_pkt_cursor_update() + * + * Let's see why next. + */ +} + +void test_net_pkt_easier_rw_usage(void) +{ + struct net_pkt *pkt; + int ret; + + pkt = net_pkt_alloc_with_buffer(eth_if, 512, + AF_INET, IPPROTO_UDP, K_NO_WAIT); + zassert_true(pkt != NULL, "Pkt not allocated"); + + /* In net core, all goes down in fine to header manipulation. + * Either it's an IP header, UDP, ICMP, TCP one etc... + * One would then prefer to access those directly via there + * descriptors (struct net_udp_hdr, struct net_icmp_hdr, ...) + * rather than building it byte by bytes etc... + * + * As seen earlier, it is possible to cast on current position. + * However, due to the "fragmented" possible nature of the buffer, + * it should also be possible to handle the case the data being + * accessed is scattered on 1+ net_buf. + * + * To avoid redoing the contiguity check, cast or copy on failure, + * a complex type named struct net_pkt_header_access exists. + * It solves both cases (accessing data contiguous or not), without + * the need for runtime allocation (all is on stack) + */ + { + NET_PKT_DATA_ACCESS_DEFINE(ip_access, struct net_ipv4_hdr); + struct net_ipv4_hdr *ip_hdr; + + ip_hdr = (struct net_ipv4_hdr *) + net_pkt_get_data_new(pkt, &ip_access); + zassert_not_null(ip_hdr, "Accessor failed"); + + ip_hdr->tos = 0x00; + + ret = net_pkt_set_data(pkt, &ip_access); + zassert_true(ret == 0, "Accessor failed"); + + zassert_true(net_pkt_get_len(pkt) == NET_IPV4H_LEN, + "Pkt length mismatch"); + } + + /* As you can notice: get/set take also care of handling the cursor + * and updating the packet length relevantly thus why packet length + * has properly grown. + */ + + /* Freeing the packet */ + net_pkt_unref(pkt); + zassert_true(atomic_get(&pkt->atomic_ref) == 0, + "Pkt not properly unreferenced"); +} + +u8_t b5_data[10] = "qrstuvwxyz"; +struct net_buf b5 = { + .ref = 1, + .data = b5_data, + .len = 0, + .size = 0, +}; + +u8_t b4_data[4] = "mnop"; +struct net_buf b4 = { + .frags = &b5, + .ref = 1, + .data = b4_data, + .len = sizeof(b4_data) - 2, + .size = sizeof(b4_data), +}; + +struct net_buf b3 = { + .frags = &b4, + .ref = 1, +}; + +u8_t b2_data[8] = "efghijkl"; +struct net_buf b2 = { + .frags = &b3, + .ref = 1, + .data = b2_data, + .len = 0, + .size = sizeof(b2_data), +}; + +u8_t b1_data[4] = "abcd"; +struct net_buf b1 = { + .frags = &b2, + .ref = 1, + .data = b1_data, + .len = sizeof(b1_data) - 2, + .size = sizeof(b1_data), +}; + +void test_net_pkt_copy(void) +{ + struct net_pkt *pkt_src; + struct net_pkt *pkt_dst; + + pkt_src = net_pkt_alloc_on_iface(eth_if, K_NO_WAIT); + zassert_true(pkt_src != NULL, "Pkt not allocated"); + + pkt_print_cursor(pkt_src); + + /* Let's append the buffers */ + net_pkt_append_buffer(pkt_src, &b1); + + net_pkt_set_overwrite(pkt_src, true); + + /* There should be some space left */ + zassert_true(net_pkt_available_buffer(pkt_src) != 0, "No space left?"); + /* Length should be 4 */ + zassert_true(net_pkt_get_len(pkt_src) == 4, "Wrong length"); + + /* Actual space left is 12 (in b1, b2 and b4) */ + zassert_true(net_pkt_available_buffer(pkt_src) == 12, + "Wrong space left?"); + + pkt_print_cursor(pkt_src); + + /* Now let's clone the pkt + * This will test net_pkt_copy_new() as it usses it for the buffers + */ + pkt_dst = net_pkt_clone_new(pkt_src, K_NO_WAIT); + zassert_true(pkt_dst != NULL, "Pkt not clone"); + + /* Cloning does not take into account left space, + * but only occupied one + */ + zassert_true(net_pkt_available_buffer(pkt_dst) == 0, "Space left"); + zassert_true(net_pkt_get_len(pkt_src) == net_pkt_get_len(pkt_dst), + "Not same amount?"); + + /* It also did not care to copy the net_buf itself, only the content + * so, knowing that the base buffer size is bigger than necessary, + * pkt_dst has only one net_buf + */ + zassert_true(pkt_dst->buffer->frags == NULL, "Not only one buffer?"); + + /* Freeing the packet */ + pkt_src->buffer = NULL; + net_pkt_unref(pkt_src); + zassert_true(atomic_get(&pkt_src->atomic_ref) == 0, + "Pkt not properly unreferenced"); + net_pkt_unref(pkt_dst); + zassert_true(atomic_get(&pkt_dst->atomic_ref) == 0, + "Pkt not properly unreferenced"); +} + +void test_main(void) +{ + eth_if = net_if_get_default(); + + ztest_test_suite(net_pkt_tests, + ztest_unit_test(test_net_pkt_allocate_wo_buffer), + ztest_unit_test(test_net_pkt_allocate_with_buffer), + ztest_unit_test(test_net_pkt_basics_of_rw), + ztest_unit_test(test_net_pkt_advanced_basics), + ztest_unit_test(test_net_pkt_easier_rw_usage), + ztest_unit_test(test_net_pkt_copy) + ); + + ztest_run_test_suite(net_pkt_tests); +} diff --git a/tests/net/net_pkt_new/testcase.yaml b/tests/net/net_pkt_new/testcase.yaml new file mode 100644 index 0000000000000..73cfe9ee1a5bc --- /dev/null +++ b/tests/net/net_pkt_new/testcase.yaml @@ -0,0 +1,7 @@ +common: + depends_on: netif + platform_whitelist: native_posix qemu_x86 qemu_cortex_m3 +tests: + net.packet: + min_ram: 20 + tags: net From 8e01acc61e7c8595160294c18ebf0a26a60587b3 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 24 Jan 2019 12:25:39 +0100 Subject: [PATCH 68/70] net/pkt: Add a debug option to track free pkt access more easily Now that net_pkt are accessed through a common r/w API, using below a net_pkt_cursor, let's have an option that will reset this cursor once the net_pkt is freed. Result is instead of segfaulting on r/w access, these operations will bail out properly. Subsequent, and logical (unless you have a leak which is another issue) net_pkt_unref will tell you who/where the pkt was freed. Without it, you will get a segfault for instance, but that won't tell you the exact reason. This options can help you then. Signed-off-by: Tomasz Bursztyka --- subsys/net/ip/Kconfig.debug | 11 +++++++++++ subsys/net/ip/net_pkt.c | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/subsys/net/ip/Kconfig.debug b/subsys/net/ip/Kconfig.debug index 292b94ab8b910..a727c7ca5f974 100644 --- a/subsys/net/ip/Kconfig.debug +++ b/subsys/net/ip/Kconfig.debug @@ -36,6 +36,17 @@ config NET_DEBUG_NET_PKT_EXTERNALS This value is used when allocating space for tracking the memory allocations. +config NET_DEBUG_NET_PKT_NON_FRAGILE_ACCESS + bool "Reduce r/w fragility by resetting the packet cursor when freed" + default n + select NET_DEBUG_NET_PKT_ALLOC + help + This MUST not be used unless you have an hard to catch bug. This will + reset the pkt cursor when it's freed, so any subsequent r/w operations + will not segfault, but just bail out and hopefuly it will enable you + to know who/where the packet was freed already. Do not set this, by + any means, unless you are actively debugging. + if !NET_RAW_MODE module = NET_CORE diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index a2766dcdb4635..283e910fb78e3 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -817,6 +817,11 @@ void net_pkt_unref(struct net_pkt *pkt) net_pkt_frag_unref(pkt->frags); } + if (IS_ENABLED(CONFIG_NET_DEBUG_NET_PKT_NON_FRAGILE_ACCESS)) { + pkt->buffer = NULL; + net_pkt_cursor_init(pkt); + } + k_mem_slab_free(pkt->slab, (void **)&pkt); } From bb50b7a8e0416dce53b973b59149b7e7aad5429b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 30 Jan 2019 10:07:10 +0100 Subject: [PATCH 69/70] net/ip: Let's make public the 2 utility unions for ip/proto headers Though these are currently used by the core only, it will be then used by net_context as well. This one of the steps to get rid of net_pkt's appdata/appdatalen attributes. Also normalizing all ip/proto parameters name to ip_hdr and proto_hdr. Signed-off-by: Tomasz Bursztyka --- include/net/net_ip.h | 14 ++++++++++ subsys/net/ip/connection.c | 40 ++++++++++++++-------------- subsys/net/ip/connection.h | 25 +++++++----------- subsys/net/ip/dhcpv4.c | 4 +-- subsys/net/ip/ipv4.c | 4 +-- subsys/net/ip/ipv6.c | 4 +-- subsys/net/ip/net_context.c | 4 +-- subsys/net/ip/net_private.h | 4 +-- subsys/net/ip/tcp.c | 42 ++++++++++++++++-------------- tests/net/ipv6_fragment/src/main.c | 4 +-- tests/net/tcp/src/main.c | 8 +++--- tests/net/udp/src/main.c | 8 +++--- 12 files changed, 86 insertions(+), 75 deletions(-) diff --git a/include/net/net_ip.h b/include/net/net_ip.h index 9e8fb0e1c6451..8db08ba2ce8ba 100644 --- a/include/net/net_ip.h +++ b/include/net/net_ip.h @@ -312,6 +312,20 @@ struct net_tcp_hdr { u8_t optdata[0]; } __packed; +/** + * This 2 unions are here temporarly, as long as net_context.h will + * be still public and not part of the core only. + */ +union net_ip_header { + struct net_ipv4_hdr *ipv4; + struct net_ipv6_hdr *ipv6; +}; + +union net_proto_header { + struct net_udp_hdr *udp; + struct net_tcp_hdr *tcp; +}; + #define NET_UDPH_LEN 8 /* Size of UDP header */ #define NET_TCPH_LEN 20 /* Size of TCP header */ #define NET_ICMPH_LEN 4 /* Size of ICMP header */ diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index db4b3198d8a88..8621d0dfddd0d 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -205,7 +205,7 @@ static s32_t check_hash(enum net_ip_protocol proto, } static inline s32_t get_conn(struct net_pkt *pkt, - union ip_header *hdr, + union net_ip_header *ip_hdr, enum net_ip_protocol proto, u16_t src_port, u16_t dst_port, @@ -213,13 +213,13 @@ static inline s32_t get_conn(struct net_pkt *pkt, { if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { return check_hash(proto, net_pkt_family(pkt), - &hdr->ipv4->src, &hdr->ipv4->dst, + &ip_hdr->ipv4->src, &ip_hdr->ipv4->dst, src_port, dst_port, cache_value); } if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) { return check_hash(proto, net_pkt_family(pkt), - &hdr->ipv6->src, &hdr->ipv6->dst, + &ip_hdr->ipv6->src, &ip_hdr->ipv6->dst, src_port, dst_port, cache_value); } @@ -268,15 +268,15 @@ static void cache_clear(void) } static inline enum net_verdict cache_check(struct net_pkt *pkt, - union ip_header *hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, enum net_ip_protocol proto, u16_t src_port, u16_t dst_port, u32_t *cache_value, s32_t *pos) { - *pos = get_conn(pkt, hdr, proto, src_port, dst_port, cache_value); + *pos = get_conn(pkt, ip_hdr, proto, src_port, dst_port, cache_value); if (*pos >= 0) { if (conn_cache[*pos].idx >= 0) { /* Connection is in the cache */ @@ -290,7 +290,7 @@ static inline enum net_verdict cache_check(struct net_pkt *pkt, conn_cache[*pos].value); return conn->cb(conn, pkt, - hdr, proto_hdr, conn->user_data); + ip_hdr, proto_hdr, conn->user_data); } } else if (*cache_value > 0) { if (cache_check_neg(*cache_value)) { @@ -685,7 +685,7 @@ int net_conn_register(enum net_ip_protocol proto, } static bool check_addr(struct net_pkt *pkt, - union ip_header *hdr, + union net_ip_header *ip_hdr, struct sockaddr *addr, bool is_remote) { @@ -698,9 +698,9 @@ static bool check_addr(struct net_pkt *pkt, struct in6_addr *addr6; if (is_remote) { - addr6 = &hdr->ipv6->src; + addr6 = &ip_hdr->ipv6->src; } else { - addr6 = &hdr->ipv6->dst; + addr6 = &ip_hdr->ipv6->dst; } if (!net_ipv6_is_addr_unspecified( @@ -720,9 +720,9 @@ static bool check_addr(struct net_pkt *pkt, struct in_addr *addr4; if (is_remote) { - addr4 = &hdr->ipv4->src; + addr4 = &ip_hdr->ipv4->src; } else { - addr4 = &hdr->ipv4->dst; + addr4 = &ip_hdr->ipv4->dst; } if (net_sin(addr)->sin_addr.s_addr) { @@ -755,7 +755,7 @@ static inline void send_icmp_error(struct net_pkt *pkt) } static bool is_invalid_packet(struct net_pkt *pkt, - union ip_header *hdr, + union net_ip_header *ip_hdr, u16_t src_port, u16_t dst_port) { @@ -764,15 +764,15 @@ static bool is_invalid_packet(struct net_pkt *pkt, } if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { - if (net_ipv4_addr_cmp(&hdr->ipv4->src, &hdr->ipv4->dst) || - net_ipv4_is_my_addr(&hdr->ipv4->src)) { + if (net_ipv4_addr_cmp(&ip_hdr->ipv4->src, &ip_hdr->ipv4->dst) || + net_ipv4_is_my_addr(&ip_hdr->ipv4->src)) { return true; } } if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) { - if (net_ipv6_addr_cmp(&hdr->ipv6->src, &hdr->ipv6->dst) || - net_ipv6_is_my_addr(&hdr->ipv6->src)) { + if (net_ipv6_addr_cmp(&ip_hdr->ipv6->src, &ip_hdr->ipv6->dst) || + net_ipv6_is_my_addr(&ip_hdr->ipv6->src)) { return true; } } @@ -780,8 +780,10 @@ static bool is_invalid_packet(struct net_pkt *pkt, return true; } -enum net_verdict net_conn_input(struct net_pkt *pkt, union ip_header *ip_hdr, - u8_t proto, union proto_header *proto_hdr) +enum net_verdict net_conn_input(struct net_pkt *pkt, + union net_ip_header *ip_hdr, + u8_t proto, + union net_proto_header *proto_hdr) { struct net_if *pkt_iface = net_pkt_iface(pkt); int i, best_match = -1; diff --git a/subsys/net/ip/connection.h b/subsys/net/ip/connection.h index 91617054e1502..7438375924488 100644 --- a/subsys/net/ip/connection.h +++ b/subsys/net/ip/connection.h @@ -29,16 +29,6 @@ struct net_conn; struct net_conn_handle; -union ip_header { - struct net_ipv4_hdr *ipv4; - struct net_ipv6_hdr *ipv6; -}; - -union proto_header { - struct net_udp_hdr *udp; - struct net_tcp_hdr *tcp; -}; - /** * @brief Function that is called by connection subsystem when UDP/TCP * packet is received and which matches local and remote IP address @@ -46,8 +36,8 @@ union proto_header { */ typedef enum net_verdict (*net_conn_cb_t)(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data); /** @@ -145,12 +135,15 @@ int net_conn_change_callback(struct net_conn_handle *handle, * disabled, the function will always return NET_DROP. */ #if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) -enum net_verdict net_conn_input(struct net_pkt *pkt, union ip_header *ip_hdr, - u8_t proto, union proto_header *proto_hdr); +enum net_verdict net_conn_input(struct net_pkt *pkt, + union net_ip_header *ip_hdr, + u8_t proto, + union net_proto_header *proto_hdr); #else static inline enum net_verdict net_conn_input(struct net_pkt *pkt, - union ip_header *hdr, u8_t proto, - union proto_header *proto_hdr) + union net_ip_header *ip_hdr, + u8_t proto, + union net_proto_header *proto_hdr) { return NET_DROP; } diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index 039362de06d6c..302e7e47ed9a9 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -875,8 +875,8 @@ static void dhcpv4_handle_reply(struct net_if *iface, static enum net_verdict net_dhcpv4_input(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data) { NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg); diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index a75fa821b1e58..55385e9c23fea 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -192,9 +192,9 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); int real_len = net_pkt_get_len(pkt); enum net_verdict verdict = NET_DROP; - union proto_header proto_hdr; + union net_proto_header proto_hdr; struct net_ipv4_hdr *hdr; - union ip_header ip; + union net_ip_header ip; int pkt_len; net_stats_update_ipv4_recv(net_pkt_iface(pkt)); diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 4024bda37276f..8e22cbb3d910c 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -441,9 +441,9 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) u8_t ext_bitmap = 0U; u16_t ext_len = 0U; u8_t nexthdr, next_nexthdr; - union proto_header proto_hdr; + union net_proto_header proto_hdr; struct net_ipv6_hdr *hdr; - union ip_header ip; + union net_ip_header ip; int pkt_len; net_stats_update_ipv6_recv(net_pkt_iface(pkt)); diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 5e3ebe97141c5..520bbb0de9bc2 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1478,8 +1478,8 @@ int net_context_sendto_new(struct net_context *context, enum net_verdict net_context_packet_received(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data) { struct net_context *context = find_context(conn); diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 017d76dad22f9..91052a57beb54 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -147,8 +147,8 @@ void net_pkt_set_appdata_values(struct net_pkt *pkt, enum net_verdict net_context_packet_received(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data); #if defined(CONFIG_NET_IPV4) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 6d190e861a6fd..ba32d7a5b9864 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -72,13 +72,13 @@ static struct tcp_backlog_entry { #define NET_CONN_CB(name) \ static enum net_verdict _##name(struct net_conn *conn, \ struct net_pkt *pkt, \ - union ip_header *ip_hdr, \ - union proto_header *proto_hdr, \ + union net_ip_header *ip_hdr, \ + union net_proto_header *proto_hdr, \ void *user_data); \ static enum net_verdict name(struct net_conn *conn, \ struct net_pkt *pkt, \ - union ip_header *ip_hdr, \ - union proto_header *proto_hdr, \ + union net_ip_header *ip_hdr, \ + union net_proto_header *proto_hdr, \ void *user_data) \ { \ enum net_verdict result; \ @@ -91,8 +91,8 @@ static struct tcp_backlog_entry { } \ static enum net_verdict _##name(struct net_conn *conn, \ struct net_pkt *pkt, \ - union ip_header *ip_hdr, \ - union proto_header *proto_hdr, \ + union net_ip_header *ip_hdr, \ + union net_proto_header *proto_hdr, \ void *user_data) \ @@ -1581,7 +1581,7 @@ static void backlog_ack_timeout(struct k_work *work) } static void tcp_copy_ip_addr_from_hdr(sa_family_t family, - union ip_header *ip_hdr, + union net_ip_header *ip_hdr, struct net_tcp_hdr *tcp_hdr, struct sockaddr *addr, bool is_src_addr) @@ -1622,7 +1622,7 @@ static void tcp_copy_ip_addr_from_hdr(sa_family_t family, } static int tcp_backlog_find(struct net_pkt *pkt, - union ip_header *hdr, + union net_ip_header *ip_hdr, struct net_tcp_hdr *tcp_hdr, int *empty_slot) { @@ -1646,7 +1646,8 @@ static int tcp_backlog_find(struct net_pkt *pkt, } if (memcmp(&net_sin(&tcp_backlog[i].remote)->sin_addr, - &hdr->ipv4->src, sizeof(struct in_addr))) { + &ip_hdr->ipv4->src, + sizeof(struct in_addr))) { continue; } } else if (IS_ENABLED(CONFIG_NET_IPV6) && @@ -1657,7 +1658,8 @@ static int tcp_backlog_find(struct net_pkt *pkt, } if (memcmp(&net_sin6(&tcp_backlog[i].remote)->sin6_addr, - &hdr->ipv6->src, sizeof(struct in6_addr))) { + &ip_hdr->ipv6->src, + sizeof(struct in6_addr))) { continue; } } @@ -1673,7 +1675,7 @@ static int tcp_backlog_find(struct net_pkt *pkt, } static int tcp_backlog_syn(struct net_pkt *pkt, - union ip_header *ip_hdr, + union net_ip_header *ip_hdr, struct net_tcp_hdr *tcp_hdr, struct net_context *context, u16_t send_mss) @@ -1705,7 +1707,7 @@ static int tcp_backlog_syn(struct net_pkt *pkt, } static int tcp_backlog_ack(struct net_pkt *pkt, - union ip_header *ip_hdr, + union net_ip_header *ip_hdr, struct net_tcp_hdr *tcp_hdr, struct net_context *context) { @@ -1734,7 +1736,7 @@ static int tcp_backlog_ack(struct net_pkt *pkt, } static int tcp_backlog_rst(struct net_pkt *pkt, - union ip_header *ip_hdr, + union net_ip_header *ip_hdr, struct net_tcp_hdr *tcp_hdr) { int r; @@ -2010,8 +2012,8 @@ static int send_reset(struct net_context *context, * * Prototype: * enum net_verdict tcp_established(struct net_conn *conn, - * union ip_header *ip_hdr, - * union data_header *proto_hdr, + * union net_ip_header *ip_hdr, + * union net_proto_header *proto_hdr, * struct net_pkt *pkt, * void *user_data) */ @@ -2204,8 +2206,8 @@ NET_CONN_CB(tcp_established) * Prototype: * enum net_verdict tcp_synack_received(struct net_conn *conn, * struct net_pkt *pkt, - * union ip_header *ip_hdr, - * union data_header *proto_hdr, + * union net_ip_header *ip_hdr, + * union net_proto_header *proto_hdr, * void *user_data) */ NET_CONN_CB(tcp_synack_received) @@ -2298,7 +2300,7 @@ NET_CONN_CB(tcp_synack_received) return NET_DROP; } -static void get_sockaddr_ptr(union ip_header *ip_hdr, +static void get_sockaddr_ptr(union net_ip_header *ip_hdr, struct net_tcp_hdr *tcp_hdr, sa_family_t family, struct sockaddr_ptr *addr) @@ -2341,8 +2343,8 @@ static inline void copy_pool_vars(struct net_context *new_context, * Prototype: * enum net_verdict tcp_syn_rcvd(struct net_conn *conn, * struct net_pkt *pkt, - * union ip_header *ip_hdr, - * union data_header *proto_hdr, + * union net_ip_header *ip_hdr, + * union net_proto_header *proto_hdr, * void *user_data) */ NET_CONN_CB(tcp_syn_rcvd) diff --git a/tests/net/ipv6_fragment/src/main.c b/tests/net/ipv6_fragment/src/main.c index 1f780c3adcfcb..0b0c18d9f68f2 100644 --- a/tests/net/ipv6_fragment/src/main.c +++ b/tests/net/ipv6_fragment/src/main.c @@ -1125,8 +1125,8 @@ static void add_nbr(struct net_if *iface, static enum net_verdict udp_data_received(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data) { DBG("Data %p received\n", pkt); diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c index d4ff0061200ed..600ebf975f78c 100644 --- a/tests/net/tcp/src/main.c +++ b/tests/net/tcp/src/main.c @@ -229,8 +229,8 @@ static struct ud *returned_ud; static enum net_verdict test_ok(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data) { struct ud *ud = (struct ud *)user_data; @@ -256,8 +256,8 @@ static enum net_verdict test_ok(struct net_conn *conn, static enum net_verdict test_fail(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data) { /* This function should never be called as there should not diff --git a/tests/net/udp/src/main.c b/tests/net/udp/src/main.c index 4f436e9a8e0e1..be3f85bb0a5f2 100644 --- a/tests/net/udp/src/main.c +++ b/tests/net/udp/src/main.c @@ -151,8 +151,8 @@ static struct ud *returned_ud; static enum net_verdict test_ok(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data) { struct ud *ud = (struct ud *)user_data; @@ -178,8 +178,8 @@ static enum net_verdict test_ok(struct net_conn *conn, static enum net_verdict test_fail(struct net_conn *conn, struct net_pkt *pkt, - union ip_header *ip_hdr, - union proto_header *proto_hdr, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, void *user_data) { /* This function should never be called as there should not From 76fc11eac829ce7c8b0ee83e45014b4c1014912c Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 30 Jan 2019 10:25:03 +0100 Subject: [PATCH 70/70] net/context: Make recv_cb providing the ip and protocol headers If status is 0, both ip_hdr and proto_hdr will own a pointer to the relevant IP and Protocol headers. In order to know which of ipv4/ipv6 and udp/tcp one will need to use respectively net_pkt_family(pkt) and net_context_get_ip_proto(context). Having access to those headers directly, many callbacks will not need to parse the packet again no get the src/dst addresses or the src/dst ports. This will be change after this commit. Signed-off-by: Tomasz Bursztyka --- drivers/console/telnet_console.c | 2 ++ drivers/modem/wncm14a2a.c | 3 ++- drivers/wifi/eswifi/eswifi_offload.c | 3 ++- drivers/wifi/winc1500/wifi_winc1500.c | 1 + include/net/net_context.h | 4 ++++ samples/bluetooth/ipsp/src/main.c | 4 ++++ samples/net/coap_client/src/coap-client.c | 2 ++ samples/net/coap_server/src/coap-server.c | 2 ++ samples/net/leds_demo/src/leds-demo.c | 2 ++ samples/net/nats/src/nats.c | 6 +++++- samples/net/zperf/src/zperf_tcp_receiver.c | 2 ++ samples/net/zperf/src/zperf_udp_receiver.c | 2 ++ samples/net/zperf/src/zperf_udp_uploader.c | 2 ++ subsys/net/ip/net_context.c | 2 +- subsys/net/ip/tcp.c | 15 ++++++++------- subsys/net/lib/dns/llmnr_responder.c | 2 ++ subsys/net/lib/dns/mdns_responder.c | 2 ++ subsys/net/lib/dns/resolve.c | 2 ++ subsys/net/lib/sockets/sockets.c | 17 +++++++++++++---- tests/net/checksum_offload/src/main.c | 20 ++++++++------------ tests/net/context/src/main.c | 6 ++++++ tests/net/ipv6/src/main.c | 4 ++++ tests/net/traffic_class/src/main.c | 2 ++ 23 files changed, 80 insertions(+), 27 deletions(-) diff --git a/drivers/console/telnet_console.c b/drivers/console/telnet_console.c index 6140b2964aefd..322fdef88cda1 100644 --- a/drivers/console/telnet_console.c +++ b/drivers/console/telnet_console.c @@ -395,6 +395,8 @@ static inline void telnet_handle_input(struct net_pkt *pkt) static void telnet_recv(struct net_context *client, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/drivers/modem/wncm14a2a.c b/drivers/modem/wncm14a2a.c index eda04d446f3fd..7f67dd063f739 100644 --- a/drivers/modem/wncm14a2a.c +++ b/drivers/modem/wncm14a2a.c @@ -777,7 +777,8 @@ static void sockreadrecv_cb_work(struct k_work *work) pkt = sock->recv_pkt; sock->recv_pkt = NULL; if (sock->recv_cb) { - sock->recv_cb(sock->context, pkt, 0, sock->recv_user_data); + sock->recv_cb(sock->context, pkt, NULL, NULL, + 0, sock->recv_user_data); } else { net_pkt_unref(pkt); } diff --git a/drivers/wifi/eswifi/eswifi_offload.c b/drivers/wifi/eswifi/eswifi_offload.c index aa47867650c24..673318299025a 100644 --- a/drivers/wifi/eswifi/eswifi_offload.c +++ b/drivers/wifi/eswifi/eswifi_offload.c @@ -96,7 +96,8 @@ static void eswifi_off_read_work(struct k_work *work) LOG_WRN("Incomplete buffer copy"); } - socket->recv_cb(socket->context, pkt, 0, socket->user_data); + socket->recv_cb(socket->context, pkt, + NULL, NULL, 0, socket->user_data); k_sem_give(&socket->read_sem); k_yield(); diff --git a/drivers/wifi/winc1500/wifi_winc1500.c b/drivers/wifi/winc1500/wifi_winc1500.c index 55532d43f40ce..f2164acd0113f 100644 --- a/drivers/wifi/winc1500/wifi_winc1500.c +++ b/drivers/wifi/winc1500/wifi_winc1500.c @@ -776,6 +776,7 @@ static bool handle_socket_msg_recv(SOCKET sock, if (sd->recv_cb) { sd->recv_cb(sd->context, sd->rx_pkt, + NULL, NULL, 0, sd->recv_user_data); } diff --git a/include/net/net_context.h b/include/net/net_context.h index 76d502ba53e83..fc6a696cc58b7 100644 --- a/include/net/net_context.h +++ b/include/net/net_context.h @@ -76,6 +76,8 @@ struct net_context; * @param pkt Network buffer that is received. If the pkt is not NULL, * then the callback will own the buffer and it needs to to unref the pkt * as soon as it has finished working with it. On EOF, pkt will be NULL. + * @param ip_hdr a pointer to relevant IP (v4 or v6) header. + * @param proto_hdr a pointer to relevant protocol (udp or tcp) header. * @param status Value is set to 0 if some data or the connection is * at EOF, <0 if there was an error receiving data, in this case the * pkt parameter is set to NULL. @@ -83,6 +85,8 @@ struct net_context; */ typedef void (*net_context_recv_cb_t)(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data); diff --git a/samples/bluetooth/ipsp/src/main.c b/samples/bluetooth/ipsp/src/main.c index 63cd8d824c811..0ea4e849892a4 100644 --- a/samples/bluetooth/ipsp/src/main.c +++ b/samples/bluetooth/ipsp/src/main.c @@ -225,6 +225,8 @@ static inline void set_dst_addr(sa_family_t family, static void udp_received(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { @@ -268,6 +270,8 @@ static void setup_udp_recv(struct net_context *udp_recv6) static void tcp_received(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/samples/net/coap_client/src/coap-client.c b/samples/net/coap_client/src/coap-client.c index d84d97118740d..bb5c2658723f5 100644 --- a/samples/net/coap_client/src/coap-client.c +++ b/samples/net/coap_client/src/coap-client.c @@ -62,6 +62,8 @@ static int dump_payload(const struct coap_packet *response) static void udp_receive(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/samples/net/coap_server/src/coap-server.c b/samples/net/coap_server/src/coap-server.c index 3bbe10910c2bc..2a43002e8f0bb 100644 --- a/samples/net/coap_server/src/coap-server.c +++ b/samples/net/coap_server/src/coap-server.c @@ -1229,6 +1229,8 @@ static struct coap_resource *find_resouce_by_observer( static void udp_receive(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/samples/net/leds_demo/src/leds-demo.c b/samples/net/leds_demo/src/leds-demo.c index 7f73992dad78c..2ce6becf55556 100644 --- a/samples/net/leds_demo/src/leds-demo.c +++ b/samples/net/leds_demo/src/leds-demo.c @@ -458,6 +458,8 @@ static struct coap_resource resources[] = { static void udp_receive(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/samples/net/nats/src/nats.c b/samples/net/nats/src/nats.c index 26bc9c503cff5..0b321165bf0ce 100644 --- a/samples/net/nats/src/nats.c +++ b/samples/net/nats/src/nats.c @@ -536,7 +536,11 @@ int nats_publish(const struct nats *nats, }); } -static void receive_cb(struct net_context *ctx, struct net_pkt *pkt, int status, +static void receive_cb(struct net_context *ctx, + struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, + int status, void *user_data) { struct nats *nats = user_data; diff --git a/samples/net/zperf/src/zperf_tcp_receiver.c b/samples/net/zperf/src/zperf_tcp_receiver.c index c4d3355116482..90625619e1b36 100644 --- a/samples/net/zperf/src/zperf_tcp_receiver.c +++ b/samples/net/zperf/src/zperf_tcp_receiver.c @@ -32,6 +32,8 @@ static struct sockaddr_in *in4_addr_my; static void tcp_received(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/samples/net/zperf/src/zperf_udp_receiver.c b/samples/net/zperf/src/zperf_udp_receiver.c index 6111bb9b303a7..524f6471f9ca9 100644 --- a/samples/net/zperf/src/zperf_udp_receiver.c +++ b/samples/net/zperf/src/zperf_udp_receiver.c @@ -126,6 +126,8 @@ static int zperf_receiver_send_stat(const struct shell *shell, static void udp_received(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/samples/net/zperf/src/zperf_udp_uploader.c b/samples/net/zperf/src/zperf_udp_uploader.c index 7fb0aeb7d7aea..338cf743d3b92 100644 --- a/samples/net/zperf/src/zperf_udp_uploader.c +++ b/samples/net/zperf/src/zperf_udp_uploader.c @@ -78,6 +78,8 @@ static inline void zperf_upload_decode_stat(const struct shell *shell, static void stat_received(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 520bbb0de9bc2..5ed4cd7c02858 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1513,7 +1513,7 @@ enum net_verdict net_context_packet_received(struct net_conn *conn, net_pkt_appdata(pkt), net_pkt_appdatalen(pkt), net_pkt_get_len(pkt)); - context->recv_cb(context, pkt, 0, user_data); + context->recv_cb(context, pkt, ip_hdr, proto_hdr, 0, user_data); #if defined(CONFIG_NET_CONTEXT_SYNC_RECV) k_sem_give(&context->recv_data_wait); diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index ba32d7a5b9864..8d02e34485f2e 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -202,7 +202,8 @@ static void abort_connection(struct net_tcp *tcp) tcp, CONFIG_NET_TCP_RETRY_COUNT, ctx); if (ctx->recv_cb) { - ctx->recv_cb(ctx, NULL, -ECONNRESET, tcp->recv_user_data); + ctx->recv_cb(ctx, NULL, NULL, NULL, -ECONNRESET, + tcp->recv_user_data); } net_context_unref(ctx); @@ -1784,8 +1785,8 @@ static void handle_ack_timeout(struct k_work *work) net_tcp_change_state(tcp, NET_TCP_CLOSED); if (tcp->context->recv_cb) { - tcp->context->recv_cb(tcp->context, NULL, 0, - tcp->recv_user_data); + tcp->context->recv_cb(tcp->context, NULL, NULL, NULL, + 0, tcp->recv_user_data); } net_context_unref(tcp->context); @@ -1803,8 +1804,8 @@ static void handle_timewait_timeout(struct k_work *work) net_tcp_change_state(tcp, NET_TCP_CLOSED); if (tcp->context->recv_cb) { - tcp->context->recv_cb(tcp->context, NULL, 0, - tcp->recv_user_data); + tcp->context->recv_cb(tcp->context, NULL, NULL, NULL, + 0, tcp->recv_user_data); } net_context_unref(tcp->context); @@ -2082,7 +2083,7 @@ NET_CONN_CB(tcp_established) net_tcp_print_recv_info("RST", pkt, tcp_hdr->src_port); if (context->recv_cb) { - context->recv_cb(context, NULL, -ECONNRESET, + context->recv_cb(context, NULL, NULL, NULL, -ECONNRESET, context->tcp->recv_user_data); } @@ -2189,7 +2190,7 @@ NET_CONN_CB(tcp_established) if (net_tcp_get_state(context->tcp) == NET_TCP_CLOSED) { if (context->recv_cb) { - context->recv_cb(context, NULL, 0, + context->recv_cb(context, NULL, NULL, NULL, 0, context->tcp->recv_user_data); } diff --git a/subsys/net/lib/dns/llmnr_responder.c b/subsys/net/lib/dns/llmnr_responder.c index 203e6d4dcf16a..0c71af9f1ea67 100644 --- a/subsys/net/lib/dns/llmnr_responder.c +++ b/subsys/net/lib/dns/llmnr_responder.c @@ -548,6 +548,8 @@ static int dns_read(struct net_context *ctx, static void recv_cb(struct net_context *net_ctx, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/subsys/net/lib/dns/mdns_responder.c b/subsys/net/lib/dns/mdns_responder.c index 28e9829a000c6..4c7f6404518df 100644 --- a/subsys/net/lib/dns/mdns_responder.c +++ b/subsys/net/lib/dns/mdns_responder.c @@ -382,6 +382,8 @@ static int dns_read(struct net_context *ctx, static void recv_cb(struct net_context *net_ctx, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/subsys/net/lib/dns/resolve.c b/subsys/net/lib/dns/resolve.c index e123461400c38..63b94a706890a 100644 --- a/subsys/net/lib/dns/resolve.c +++ b/subsys/net/lib/dns/resolve.c @@ -512,6 +512,8 @@ static int dns_read(struct dns_resolve_context *ctx, static void cb_recv(struct net_context *net_ctx, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 7fa07dc09b68b..f3c31c04efbd1 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -42,8 +42,12 @@ static inline void *get_sock_vtable( (const struct fd_op_vtable **)vtable); } -static void zsock_received_cb(struct net_context *ctx, struct net_pkt *pkt, - int status, void *user_data); +static void zsock_received_cb(struct net_context *ctx, + struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, + int status, + void *user_data); static inline int _k_fifo_wait_non_empty(struct k_fifo *fifo, int32_t timeout) { @@ -193,8 +197,13 @@ static void zsock_accepted_cb(struct net_context *new_ctx, } } -static void zsock_received_cb(struct net_context *ctx, struct net_pkt *pkt, - int status, void *user_data) { +static void zsock_received_cb(struct net_context *ctx, + struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, + int status, + void *user_data) +{ unsigned int header_len; NET_DBG("ctx=%p, pkt=%p, st=%d, user_data=%p", ctx, pkt, status, diff --git a/tests/net/checksum_offload/src/main.c b/tests/net/checksum_offload/src/main.c index da6a0e7a77573..2a8fbde9ee30b 100644 --- a/tests/net/checksum_offload/src/main.c +++ b/tests/net/checksum_offload/src/main.c @@ -698,15 +698,13 @@ static void tx_chksum_offload_enabled_test_v4(void) static void recv_cb_offload_disabled(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { - struct net_udp_hdr hdr, *udp_hdr; - - udp_hdr = net_udp_get_hdr(pkt, &hdr); - - zassert_not_null(udp_hdr, "UDP header missing"); - zassert_not_equal(udp_hdr->chksum, 0, "Checksum is not set"); + zassert_not_null(proto_hdr->udp, "UDP header missing"); + zassert_not_equal(proto_hdr->udp->chksum, 0, "Checksum is not set"); if (net_pkt_family(pkt) == AF_INET) { struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt); @@ -722,15 +720,13 @@ static void recv_cb_offload_disabled(struct net_context *context, static void recv_cb_offload_enabled(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { - struct net_udp_hdr hdr, *udp_hdr; - - udp_hdr = net_udp_get_hdr(pkt, &hdr); - - zassert_not_null(udp_hdr, "UDP header missing"); - zassert_equal(udp_hdr->chksum, 0, "Checksum is set"); + zassert_not_null(proto_hdr->udp, "UDP header missing"); + zassert_equal(proto_hdr->udp->chksum, 0, "Checksum is set"); if (net_pkt_family(pkt) == AF_INET) { struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt); diff --git a/tests/net/context/src/main.c b/tests/net/context/src/main.c index 604e4dea88604..b9682fd693583 100644 --- a/tests/net/context/src/main.c +++ b/tests/net/context/src/main.c @@ -508,6 +508,8 @@ static void net_ctx_sendto_v4(void) static void recv_cb(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { @@ -683,6 +685,8 @@ static void net_ctx_recv_v4_again(void) static void recv_cb_another(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { @@ -738,6 +742,8 @@ static struct k_thread thread_data; static void recv_cb_timeout(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { diff --git a/tests/net/ipv6/src/main.c b/tests/net/ipv6/src/main.c index 980554141a5c1..9bddaf2e7e353 100644 --- a/tests/net/ipv6/src/main.c +++ b/tests/net/ipv6/src/main.c @@ -1299,11 +1299,15 @@ static void net_ctx_listen(struct net_context *ctx) static void recv_cb(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) { ARG_UNUSED(context); ARG_UNUSED(pkt); + ARG_UNUSED(ip_hdr); + ARG_UNUSED(proto_hdr); ARG_UNUSED(status); ARG_UNUSED(user_data); diff --git a/tests/net/traffic_class/src/main.c b/tests/net/traffic_class/src/main.c index 957b4e6d31319..e4d334519c4cb 100644 --- a/tests/net/traffic_class/src/main.c +++ b/tests/net/traffic_class/src/main.c @@ -686,6 +686,8 @@ static void traffic_class_send_data_mix_all_2(void) static void recv_cb(struct net_context *context, struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, int status, void *user_data) {