From 753daa65f9181b8ea89a1597b7aaa30a45910f44 Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Fri, 17 Nov 2017 15:32:19 +0200 Subject: [PATCH] net: pkt: Compute TX payload data length Compute the length of the TX payload that is transported in one IPv4 or IPv6 datagram taking into account UDP, ICMP or TCP headers in addition to any IPv6 extension headers added by RPL. The TCP implementation in Zephyr is known to currently carry at maximum 8 bytes of options. If the protocol is not known to the stack, assume that the application handles any protocol headers as well as the data. Also, if the net_pkt does not have a context associated, length check on the data is omitted when appending. Although payload length is calculated also for TCP, the TCP MSS value is used as before. Define IPv4 minimum MTU as 576 octets, See RFC 791, Sections 3.1. and 3.2. Signed-off-by: Patrik Flykt --- include/net/net_ip.h | 1 + include/net/net_pkt.h | 2 + subsys/net/ip/net_pkt.c | 84 +++++++++++++++++++++++++++-------------- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/include/net/net_ip.h b/include/net/net_ip.h index c8352227cfb..34b24806910 100644 --- a/include/net/net_ip.h +++ b/include/net/net_ip.h @@ -179,6 +179,7 @@ extern const struct in6_addr in6addr_loopback; #define INADDR_ANY_INIT { { { INADDR_ANY } } } #define NET_IPV6_MTU 1280 +#define NET_IPV4_MTU 576 /** IPv6 extension headers types */ #define NET_IPV6_NEXTHDR_HBHO 0 diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index bb27314e1f1..9ebf537b02a 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -73,6 +73,8 @@ struct net_pkt { struct net_linkaddr lladdr_src; struct net_linkaddr lladdr_dst; + u16_t data_len; /* amount of payload data that can be added */ + u16_t appdatalen; u8_t ll_reserve; /* link layer header length */ u8_t ip_hdr_len; /* pre-filled in order to avoid func call */ diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 5cc470af951..cbc34dd5ce9 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -38,6 +38,7 @@ #include "net_private.h" #include "tcp.h" +#include "rpl.h" #if defined(CONFIG_NET_TCP) #define APP_PROTO_LEN NET_TCPH_LEN @@ -519,14 +520,48 @@ static struct net_pkt *net_pkt_get(struct k_mem_slab *slab, pkt = net_pkt_get_reserve(slab, net_if_get_ll_reserve(iface, addr6), timeout); #endif - if (pkt) { + if (pkt && slab != &rx_pkts) { + sa_family_t family; + uint16_t iface_len, data_len = 0; + enum net_ip_protocol proto; + net_pkt_set_context(pkt, context); net_pkt_set_iface(pkt, iface); - if (context) { - net_pkt_set_family(pkt, - net_context_get_family(context)); + iface_len = net_if_get_mtu(iface); + + family = net_context_get_family(context); + net_pkt_set_family(pkt, family); + + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { + data_len = max(iface_len, NET_IPV6_MTU); } + + if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { + data_len = max(iface_len, NET_IPV4_MTU); + } + + proto = net_context_get_ip_proto(context); + + if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) { + data_len -= NET_TCPH_LEN; + data_len -= NET_TCP_MAX_OPT_SIZE; + } + + if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) { + data_len -= NET_UDPH_LEN; + +#if defined(CONFIG_NET_RPL_INSERT_HBH_OPTION) + data_len -= NET_RPL_HOP_BY_HOP_LEN; +#endif + + } + + if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) { + data_len -= NET_ICMPH_LEN; + } + + pkt->data_len = data_len; } return pkt; @@ -1164,7 +1199,7 @@ u16_t net_pkt_append(struct net_pkt *pkt, u16_t len, const u8_t *data, { struct net_buf *frag; struct net_context *ctx; - size_t max_len; + u16_t max_len, appended; if (!pkt || !data) { return 0; @@ -1179,41 +1214,32 @@ u16_t net_pkt_append(struct net_pkt *pkt, u16_t len, const u8_t *data, net_pkt_frag_add(pkt, frag); } - /* Make sure we don't send more data in one packet than - * MTU allows. - * This check really belongs to net_pkt_append_bytes(), - * but instead done here for efficiency, we assume - * (at least for now) that that callers of - * net_pkt_append_bytes() are smart enough to not - * overflow MTU. - */ - max_len = 0x10000; - ctx = net_pkt_context(pkt); if (ctx) { + /* Make sure we don't send more data in one packet than + * protocol or MTU allows when there is a context for the + * packet. + */ + max_len = pkt->data_len; + #if defined(CONFIG_NET_TCP) if (ctx->tcp) { max_len = ctx->tcp->send_mss; - } else + } #endif - { - struct net_if *iface = net_context_get_iface(ctx); - max_len = net_if_get_mtu(iface); - /* Optimize for number of jumps in the code ("if" - * instead of "if/else"). - */ - max_len -= NET_IPV4TCPH_LEN; - if (net_context_get_family(ctx) != AF_INET) { - max_len -= NET_IPV6TCPH_LEN - NET_IPV4TCPH_LEN; - } + + if (len > max_len) { + len = max_len; } } - if (len > max_len) { - len = max_len; + appended = net_pkt_append_bytes(pkt, data, len, timeout); + + if (ctx) { + pkt->data_len -= appended; } - return net_pkt_append_bytes(pkt, data, len, timeout); + return appended; } /* Helper routine to retrieve single byte from fragment and move