From cf9ad748baf69ead3b9decb9dd4ba235bfe6837f Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 30 Sep 2019 12:17:03 +0300 Subject: [PATCH] net: ipv4: Add IPv4 options length to net pkt IPv4 header options length will be stored in ipv4_opts_len in net_pkt structure. Now IPv4 header length will be in net_pkt ip_hdr_len + ipv4_opts_len. So modified relevant places of ip header length calculation for IPv4. Signed-off-by: Ravi kumar Veeramally --- include/net/net_pkt.h | 48 ++++++++++++++++++++++++++++++-- subsys/net/ip/ipv4.c | 18 +++++++++--- subsys/net/ip/net_pkt.c | 2 ++ subsys/net/ip/tcp.c | 6 ++-- subsys/net/ip/udp.c | 14 +++++----- subsys/net/ip/utils.c | 10 ++++--- subsys/net/lib/sockets/sockets.c | 4 ++- 7 files changed, 81 insertions(+), 21 deletions(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index 1b000ec8100..01d931ed20a 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -188,6 +188,15 @@ struct net_pkt { u8_t ipv4_ttl; }; + union { +#if defined(CONFIG_NET_IPV4) + u8_t ipv4_opts_len; /* Length if IPv4 Header Options */ +#endif +#if defined(CONFIG_NET_IPV6) + u16_t ipv6_ext_len; /* length of extension headers */ +#endif + }; + #if NET_TC_COUNT > 1 /** Network packet priority, can be left out in which case packet * is not prioritised. @@ -205,8 +214,6 @@ struct net_pkt { #endif /* CONFIG_NET_VLAN */ #if defined(CONFIG_NET_IPV6) - u16_t ipv6_ext_len; /* length of extension headers */ - /* Where is the start of the last header before payload data * in IPv6 packet. This is offset value from start of the IPv6 * packet. Note that this value should be updated by who ever @@ -387,6 +394,17 @@ static inline void net_pkt_set_ipv4_ttl(struct net_pkt *pkt, { pkt->ipv4_ttl = ttl; } + +static inline u8_t net_pkt_ipv4_opts_len(struct net_pkt *pkt) +{ + return pkt->ipv4_opts_len; +} + +static inline void net_pkt_set_ipv4_opts_len(struct net_pkt *pkt, + u8_t opts_len) +{ + pkt->ipv4_opts_len = opts_len; +} #else static inline u8_t net_pkt_ipv4_ttl(struct net_pkt *pkt) { @@ -401,6 +419,19 @@ static inline void net_pkt_set_ipv4_ttl(struct net_pkt *pkt, ARG_UNUSED(pkt); ARG_UNUSED(ttl); } + +static inline u8_t net_pkt_ipv4_opts_len(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + return 0; +} + +static inline void net_pkt_set_ipv4_opts_len(struct net_pkt *pkt, + u8_t opts_len) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(opts_len); +} #endif #if defined(CONFIG_NET_IPV6) @@ -526,6 +557,19 @@ static inline void net_pkt_set_ipv6_hop_limit(struct net_pkt *pkt, } #endif /* CONFIG_NET_IPV6 */ +static inline u16_t net_pkt_ip_opts_len(struct net_pkt *pkt) +{ +#if defined(CONFIG_NET_IPV6) + return pkt->ipv6_ext_len; +#elif defined(CONFIG_NET_IPV4) + return pkt->ipv4_opts_len; +#else + ARG_UNUSED(pkt); + + return 0; +#endif +} + #if defined(CONFIG_NET_IPV6_FRAGMENT) static inline u16_t net_pkt_ipv6_fragment_start(struct net_pkt *pkt) { diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index 47129298193..6e179ff0c9d 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -79,6 +79,12 @@ int net_ipv4_finalize(struct net_pkt *pkt, u8_t next_header_proto) return -ENOBUFS; } + if (net_pkt_ipv4_opts_len(pkt)) { + ipv4_hdr->vhl = 0x40 | (0x0F & + ((net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv4_opts_len(pkt)) / 4U)); + } + ipv4_hdr->len = htons(net_pkt_get_len(pkt)); ipv4_hdr->proto = next_header_proto; @@ -112,6 +118,7 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) struct net_ipv4_hdr *hdr; union net_ip_header ip; u8_t hdr_len; + u8_t opts_len; int pkt_len; net_stats_update_ipv4_recv(net_pkt_iface(pkt)); @@ -140,7 +147,10 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) goto drop; } - net_pkt_set_ip_hdr_len(pkt, hdr_len); + net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr)); + + opts_len = hdr_len - sizeof(struct net_ipv4_hdr); + net_pkt_set_ipv4_opts_len(pkt, opts_len); pkt_len = ntohs(hdr->len); if (real_len < pkt_len) { @@ -188,9 +198,9 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) net_pkt_acknowledge_data(pkt, &ipv4_access); - if (hdr_len > sizeof(struct net_ipv4_hdr)) { - /* There are probably options, let's skip them */ - if (net_pkt_skip(pkt, hdr_len - sizeof(struct net_ipv4_hdr))) { + if (opts_len) { + /* Only few options are handled in EchoRequest, rest skipped */ + if (net_pkt_skip(pkt, opts_len)) { NET_DBG("Header too big? %u", hdr_len); goto drop; } diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 32f752dd6c3..dfd2596c8d9 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -1704,6 +1704,8 @@ static void clone_pkt_attributes(struct net_pkt *pkt, struct net_pkt *clone_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)); + net_pkt_set_ipv4_opts_len(clone_pkt, + net_pkt_ipv4_opts_len(pkt)); } else if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) { net_pkt_set_ipv6_hop_limit(clone_pkt, diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 7b0a7c155b3..5a6db91fb8e 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -873,7 +873,7 @@ int net_tcp_send_pkt(struct net_pkt *pkt) net_pkt_set_overwrite(pkt, true); if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt))) { + net_pkt_ip_opts_len(pkt))) { return -EMSGSIZE; } @@ -908,7 +908,7 @@ int net_tcp_send_pkt(struct net_pkt *pkt) if (calc_chksum) { net_pkt_cursor_init(pkt); net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt)); + net_pkt_ip_opts_len(pkt)); /* No need to get tcp_hdr again */ tcp_hdr->chksum = net_calc_chksum_tcp(pkt); @@ -1076,7 +1076,7 @@ bool net_tcp_ack_received(struct net_context *ctx, u32_t ack) net_pkt_set_overwrite(pkt, true); if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt))) { + net_pkt_ip_opts_len(pkt))) { sys_slist_remove(list, NULL, head); net_pkt_unref(pkt); continue; diff --git a/subsys/net/ip/udp.c b/subsys/net/ip/udp.c index 6adb0f8b5d4..8476ba802b1 100644 --- a/subsys/net/ip/udp.c +++ b/subsys/net/ip/udp.c @@ -39,16 +39,16 @@ 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; + u16_t length = 0; udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(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); + length = net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt) - + net_pkt_ip_opts_len(pkt); + udp_hdr->len = htons(length); if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { @@ -75,7 +75,7 @@ struct net_udp_hdr *net_udp_get_hdr(struct net_pkt *pkt, net_pkt_cursor_init(pkt); if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt))) { + net_pkt_ip_opts_len(pkt))) { udp_hdr = NULL; goto out; } @@ -104,7 +104,7 @@ struct net_udp_hdr *net_udp_set_hdr(struct net_pkt *pkt, net_pkt_cursor_init(pkt); if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt))) { + net_pkt_ip_opts_len(pkt))) { udp_hdr = NULL; goto out; } @@ -156,7 +156,7 @@ struct net_udp_hdr *net_udp_input(struct net_pkt *pkt, if (ntohs(udp_hdr->len) != (net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt) - - net_pkt_ipv6_ext_len(pkt))) { + net_pkt_ip_opts_len(pkt))) { NET_DBG("DROP: Invalid hdr length"); goto drop; } diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c index 072babf2f3b..08e606711b3 100644 --- a/subsys/net/ip/utils.c +++ b/subsys/net/ip/utils.c @@ -566,7 +566,8 @@ u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto) if (proto != IPPROTO_ICMP) { len = 2 * sizeof(struct in_addr); sum = net_pkt_get_len(pkt) - - net_pkt_ip_hdr_len(pkt) + proto; + net_pkt_ip_hdr_len(pkt) - + net_pkt_ipv4_opts_len(pkt) + proto; } } else if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) { @@ -588,8 +589,7 @@ u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto) 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)); + net_pkt_skip(pkt, len + net_pkt_ip_opts_len(pkt)); sum = pkt_calc_chksum(pkt, sum); @@ -607,7 +607,9 @@ u16_t net_calc_chksum_ipv4(struct net_pkt *pkt) { u16_t sum; - sum = calc_chksum(0, pkt->buffer->data, net_pkt_ip_hdr_len(pkt)); + sum = calc_chksum(0, pkt->buffer->data, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv4_opts_len(pkt)); sum = (sum == 0U) ? 0xffff : htons(sum); diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 435cba5697b..921101b2680 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -644,7 +644,9 @@ static int sock_get_pkt_src_addr(struct net_pkt *pkt, ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data( pkt, &ipv4_access); - if (!ipv4_hdr || net_pkt_acknowledge_data(pkt, &ipv4_access)) { + if (!ipv4_hdr || + net_pkt_acknowledge_data(pkt, &ipv4_access) || + net_pkt_skip(pkt, net_pkt_ipv4_opts_len(pkt))) { ret = -ENOBUFS; goto error; }