From 8476da9d9b12e545b91ebf7d2229666f38f9f7d4 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 28 Jun 2017 15:34:02 +0300 Subject: [PATCH] net: icmp: Remove NET_ICMP_HDR() macro and direct access to net_buf Remove NET_ICMP_HDR() macro as we cannot safely access ICMP header via it if the network packet header spans over multiple net_buf fragments. Jira: ZEP-2306 Signed-off-by: Jukka Rissanen --- include/net/net_pkt.h | 33 ++- subsys/net/ip/icmpv4.c | 115 ++++++++-- subsys/net/ip/icmpv4.h | 7 + subsys/net/ip/icmpv6.c | 305 +++++++++++++++++++++++++-- subsys/net/ip/icmpv6.h | 41 ++-- subsys/net/ip/ipv4.c | 8 +- subsys/net/ip/ipv6.c | 405 +++++++++++++++++++++--------------- subsys/net/ip/net_pkt.c | 62 ++++++ subsys/net/ip/net_private.h | 22 ++ subsys/net/ip/rpl.c | 37 ++-- tests/net/ipv6/src/main.c | 2 + tests/net/mld/src/main.c | 2 + tests/net/rpl/src/main.c | 2 + 13 files changed, 792 insertions(+), 249 deletions(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index da4fa6b6a214..84a1ee198bba 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -333,12 +333,6 @@ static inline u8_t *net_pkt_tcp_data(struct net_pkt *pkt) net_pkt_ipv6_ext_len(pkt)]; } -static inline u8_t *net_pkt_icmp_data(struct net_pkt *pkt) -{ - return &pkt->frags->data[net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt)]; -} - static inline u8_t *net_pkt_appdata(struct net_pkt *pkt) { return pkt->appdata; @@ -414,7 +408,6 @@ static inline void net_pkt_set_ieee802154_rssi(struct net_pkt *pkt, #define NET_IPV6_HDR(pkt) ((struct net_ipv6_hdr *)net_pkt_ip_data(pkt)) #define NET_IPV4_HDR(pkt) ((struct net_ipv4_hdr *)net_pkt_ip_data(pkt)) -#define NET_ICMP_HDR(pkt) ((struct net_icmp_hdr *)net_pkt_icmp_data(pkt)) #define NET_UDP_HDR(pkt) ((struct net_udp_hdr *)(net_pkt_udp_data(pkt))) #define NET_TCP_HDR(pkt) ((struct net_tcp_hdr *)(net_pkt_tcp_data(pkt))) @@ -1310,6 +1303,32 @@ int net_pkt_split(struct net_pkt *pkt, struct net_buf *orig_frag, u16_t len, struct net_buf **fragA, struct net_buf **fragB, s32_t timeout); +/** + * @brief Return the fragment and offset within it according to network + * packet offset. + * + * @details This is typically used to get the protocol header pointer when + * we know the offset. According to this information, the corresponding fragment + * and position within that fragment is returned. + * + * @param pkt Network packet + * @param offset Offset of desired location in network packet. For example, if + * we want to know where UDP header is located after the IPv6 header, + * the offset could have a value of sizeof(struct net_ipv6_hdr). Note that this + * is a simplified example that does not take into account the possible IPv6 + * extension headers. + * @param pos Pointer to position within result fragment corresponding to + * offset param. For example, if the IPv6 header is split between two fragments, + * then if we want to know the start of UDP header, the returned pos variable + * would indicate how many bytes from second fragment the UDP header starts. + * + * @return Pointer to the fragment where the the offset is located or + * NULL if there is not enough bytes in the packet + */ +struct net_buf *net_frag_get_pos(struct net_pkt *pkt, + u16_t offset, + u16_t *pos); + /** * @brief Get information about predefined RX, TX and DATA pools. * diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 487ffcb93891..3934ca23d2f6 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -26,11 +26,93 @@ static sys_slist_t handlers; +struct net_icmp_hdr *net_icmpv4_set_hdr(struct net_pkt *pkt, + struct net_icmp_hdr *hdr) +{ + struct net_icmp_hdr *icmp_hdr; + struct net_buf *frag; + u16_t pos; + + icmp_hdr = net_pkt_icmp_data(pkt); + if (net_icmp_header_fits(pkt, icmp_hdr)) { + return icmp_hdr; + } + + frag = net_pkt_write_u8(pkt, pkt->frags, + net_pkt_ip_hdr_len(pkt), + &pos, hdr->type); + frag = net_pkt_write_u8(pkt, frag, pos, &pos, hdr->code); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->chksum), + (u8_t *)&hdr->chksum, PKT_WAIT_TIME); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_icmp_hdr *net_icmpv4_get_hdr(struct net_pkt *pkt, + struct net_icmp_hdr *hdr) +{ + struct net_icmp_hdr *icmp_hdr; + struct net_buf *frag; + u16_t pos; + + icmp_hdr = net_pkt_icmp_data(pkt); + if (net_icmp_header_fits(pkt, icmp_hdr)) { + return icmp_hdr; + } + + frag = net_frag_read_u8(pkt->frags, net_pkt_ip_hdr_len(pkt), &pos, + &hdr->type); + frag = net_frag_read_u8(frag, pos, &pos, &hdr->code); + frag = net_frag_read(frag, pos, &pos, sizeof(hdr->chksum), + (u8_t *)&hdr->chksum); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_buf *net_icmpv4_set_chksum(struct net_pkt *pkt, + struct net_buf *frag) +{ + struct net_icmp_hdr *icmp_hdr; + u16_t chksum = 0; + u16_t pos; + + icmp_hdr = net_pkt_icmp_data(pkt); + if (net_icmp_header_fits(pkt, icmp_hdr)) { + icmp_hdr->chksum = 0; + icmp_hdr->chksum = ~net_calc_chksum_icmpv4(pkt); + + return frag; + } + + frag = net_pkt_write(pkt, frag, + net_pkt_ip_hdr_len(pkt) + + 1 + 1 /* type + code */, &pos, + sizeof(chksum), (u8_t *)&chksum, PKT_WAIT_TIME); + + chksum = ~net_calc_chksum_icmpv4(pkt); + + frag = net_pkt_write(pkt, frag, pos - 2, &pos, sizeof(chksum), + (u8_t *)&chksum, PKT_WAIT_TIME); + + NET_ASSERT(frag); + + return frag; +} + static inline enum net_verdict handle_echo_request(struct net_pkt *pkt) { /* Note that we send the same data packets back and just swap * the addresses etc. */ + struct net_icmp_hdr hdr, *icmp_hdr; struct in_addr addr; #if defined(CONFIG_NET_DEBUG_ICMPV4) @@ -47,10 +129,12 @@ static inline enum net_verdict handle_echo_request(struct net_pkt *pkt) &NET_IPV4_HDR(pkt)->dst); net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr); - NET_ICMP_HDR(pkt)->type = NET_ICMPV4_ECHO_REPLY; - NET_ICMP_HDR(pkt)->code = 0; - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt); + icmp_hdr = net_icmpv4_get_hdr(pkt, &hdr); + icmp_hdr->type = NET_ICMPV4_ECHO_REPLY; + icmp_hdr->code = 0; + icmp_hdr->chksum = 0; + net_icmpv4_set_hdr(pkt, icmp_hdr); + net_icmpv4_set_chksum(pkt, pkt->frags); #if defined(CONFIG_NET_DEBUG_ICMPV4) snprintk(out, sizeof(out), "%s", @@ -75,6 +159,9 @@ static inline void setup_ipv4_header(struct net_pkt *pkt, u8_t extra_len, u8_t ttl, u8_t icmp_type, u8_t icmp_code) { + struct net_buf *frag = pkt->frags; + u16_t pos; + NET_IPV4_HDR(pkt)->vhl = 0x45; NET_IPV4_HDR(pkt)->tos = 0x00; NET_IPV4_HDR(pkt)->len[0] = 0; @@ -91,11 +178,10 @@ static inline void setup_ipv4_header(struct net_pkt *pkt, u8_t extra_len, NET_IPV4_HDR(pkt)->chksum = 0; NET_IPV4_HDR(pkt)->chksum = ~net_calc_chksum_ipv4(pkt); - NET_ICMP_HDR(pkt)->type = icmp_type; - NET_ICMP_HDR(pkt)->code = icmp_code; - - memset(net_pkt_icmp_data(pkt) + sizeof(struct net_icmp_hdr), 0, - NET_ICMPV4_UNUSED_LEN); + frag = net_pkt_write_u8(pkt, frag, net_pkt_ip_hdr_len(pkt), &pos, + icmp_type); + frag = net_pkt_write_u8(pkt, frag, pos, &pos, icmp_code); + net_pkt_write_be32(pkt, frag, pos, &pos, 0); } int net_icmpv4_send_echo_request(struct net_if *iface, @@ -133,8 +219,7 @@ int net_icmpv4_send_echo_request(struct net_if *iface, NET_ICMPV4_ECHO_REQ(pkt)->identifier = htons(identifier); NET_ICMPV4_ECHO_REQ(pkt)->sequence = htons(sequence); - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt); + net_icmpv4_set_chksum(pkt, pkt->frags); #if defined(CONFIG_NET_DEBUG_ICMPV4) do { @@ -174,7 +259,10 @@ int net_icmpv4_send_error(struct net_pkt *orig, u8_t type, u8_t code) int err = -EIO; if (NET_IPV4_HDR(orig)->proto == IPPROTO_ICMP) { - if (NET_ICMP_HDR(orig)->code < 8) { + struct net_icmp_hdr icmp_hdr[1]; + + if (!net_icmpv4_get_hdr(orig, icmp_hdr) || + icmp_hdr->code < 8) { /* We must not send ICMP errors back */ err = -EINVAL; goto drop_no_pkt; @@ -241,8 +329,7 @@ int net_icmpv4_send_error(struct net_pkt *orig, u8_t type, u8_t code) net_pkt_ll_dst(pkt)->addr = net_pkt_ll_src(orig)->addr; net_pkt_ll_dst(pkt)->len = net_pkt_ll_src(orig)->len; - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt); + net_icmpv4_set_chksum(pkt, pkt->frags); #if defined(CONFIG_NET_DEBUG_ICMPV4) do { diff --git a/subsys/net/ip/icmpv4.h b/subsys/net/ip/icmpv4.h index 102df26ef202..7e339c06e4dc 100644 --- a/subsys/net/ip/icmpv4.h +++ b/subsys/net/ip/icmpv4.h @@ -76,6 +76,13 @@ void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler); enum net_verdict net_icmpv4_input(struct net_pkt *pkt, u8_t type, u8_t code); +struct net_icmp_hdr *net_icmpv4_get_hdr(struct net_pkt *pkt, + struct net_icmp_hdr *hdr); +struct net_icmp_hdr *net_icmpv4_set_hdr(struct net_pkt *pkt, + struct net_icmp_hdr *hdr); +struct net_buf *net_icmpv4_set_chksum(struct net_pkt *pkt, + struct net_buf *frag); + #if defined(CONFIG_NET_IPV4) void net_icmpv4_init(void); #else diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index 845c132f4652..9fd61a55cd4b 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -78,6 +78,10 @@ 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 = 0; + u16_t pos; + NET_IPV6_HDR(pkt)->vtc = 0x60; NET_IPV6_HDR(pkt)->tcflow = 0; NET_IPV6_HDR(pkt)->flow = 0; @@ -90,13 +94,14 @@ static inline void setup_ipv6_header(struct net_pkt *pkt, u16_t extra_len, net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); - NET_ICMP_HDR(pkt)->type = icmp_type; - NET_ICMP_HDR(pkt)->code = icmp_code; + 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 */ - memset(net_pkt_icmp_data(pkt) + sizeof(struct net_icmp_hdr), 0, - NET_ICMPV6_UNUSED_LEN); + net_pkt_write(pkt, frag, pos, &pos, 4, (u8_t *)unused, PKT_WAIT_TIME); } #if defined(CONFIG_NET_DEBUG_ICMPV6) @@ -124,8 +129,270 @@ static inline void echo_reply_debug(struct net_pkt *pkt) #define echo_reply_debug(pkt) #endif /* CONFIG_NET_DEBUG_ICMPV6 */ +struct net_buf *net_icmpv6_set_chksum(struct net_pkt *pkt, + struct net_buf *frag) +{ + struct net_icmp_hdr *icmp_hdr; + u16_t chksum = 0; + u16_t pos; + + icmp_hdr = net_pkt_icmp_data(pkt); + if (net_icmp_header_fits(pkt, icmp_hdr)) { + icmp_hdr->chksum = 0; + icmp_hdr->chksum = ~net_calc_chksum_icmpv6(pkt); + + return frag; + } + + frag = net_pkt_write(pkt, frag, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + 1 + 1 /* type + code */, + &pos, sizeof(chksum), (u8_t *)&chksum, + PKT_WAIT_TIME); + + chksum = ~net_calc_chksum_icmpv6(pkt); + + frag = net_pkt_write(pkt, frag, pos - 2, &pos, sizeof(chksum), + (u8_t *)&chksum, PKT_WAIT_TIME); + + NET_ASSERT(frag); + + return frag; +} + +struct net_icmp_hdr *net_icmpv6_get_hdr(struct net_pkt *pkt, + struct net_icmp_hdr *hdr) +{ + struct net_icmp_hdr *icmp_hdr; + struct net_buf *frag; + u16_t pos; + + /* If the ICMP header can fit the first fragment, then access it + * directly (fast path), otherwise read the values one by one + * using net_frag_read*() functions (slow path). + */ + + icmp_hdr = net_pkt_icmp_data(pkt); + if (net_icmp_header_fits(pkt, icmp_hdr)) { + return icmp_hdr; + } + + frag = net_frag_read_u8(pkt->frags, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), &pos, &hdr->type); + frag = net_frag_read_u8(frag, pos, &pos, &hdr->code); + frag = net_frag_read(frag, pos, &pos, sizeof(hdr->chksum), + (u8_t *)&hdr->chksum); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_icmp_hdr *net_icmpv6_set_hdr(struct net_pkt *pkt, + struct net_icmp_hdr *hdr) +{ + struct net_buf *frag; + u16_t pos; + + if (net_icmp_header_fits(pkt, hdr)) { + return hdr; + } + + frag = net_pkt_write(pkt, pkt->frags, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), &pos, + sizeof(hdr->type), &hdr->type, PKT_WAIT_TIME); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->code), + &hdr->code, PKT_WAIT_TIME); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->chksum), + (u8_t *)&hdr->chksum, PKT_WAIT_TIME); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_icmpv6_ns_hdr *net_icmpv6_get_ns_hdr(struct net_pkt *pkt, + struct net_icmpv6_ns_hdr *hdr) +{ + struct net_buf *frag; + u8_t *opt_data; + u16_t pos; + + /* No helpers for various ICMP sub-options. First get the pointer + * where the sub-option is located, then check if it is located in + * first fragment (fast path). If the header is not in first fragment, + * then read the values separately (slow path). + */ + + opt_data = net_pkt_icmp_opt_data(pkt, sizeof(struct net_icmp_hdr)); + if (net_header_fits(pkt, opt_data, sizeof(*hdr))) { + return (struct net_icmpv6_ns_hdr *)opt_data; + } + + frag = net_frag_read(pkt->frags, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_icmp_hdr) + 4 /* reserved */, + &pos, sizeof(struct in6_addr), (u8_t *)&hdr->tgt); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_icmpv6_ns_hdr *net_icmpv6_set_ns_hdr(struct net_pkt *pkt, + struct net_icmpv6_ns_hdr *hdr) +{ + const u32_t reserved = 0; + struct net_buf *frag; + u8_t *opt_data; + u16_t pos; + + opt_data = net_pkt_icmp_opt_data(pkt, sizeof(struct net_icmp_hdr)); + if (net_header_fits(pkt, opt_data, sizeof(*hdr))) { + return (struct net_icmpv6_ns_hdr *)opt_data; + } + + 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(reserved), (u8_t *)&reserved, + PKT_WAIT_TIME); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(struct in6_addr), + (u8_t *)&hdr->tgt, PKT_WAIT_TIME); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_icmpv6_nd_opt_hdr *net_icmpv6_get_nd_opt_hdr(struct net_pkt *pkt, + struct net_icmpv6_nd_opt_hdr *hdr) +{ + struct net_buf *frag; + u8_t *opt_data; + u16_t pos; + + opt_data = net_pkt_icmp_opt_data(pkt, sizeof(struct net_icmp_hdr) + + net_pkt_ipv6_ext_opt_len(pkt)); + if (net_header_fits(pkt, opt_data, sizeof(*hdr))) { + return (struct net_icmpv6_nd_opt_hdr *)opt_data; + } + + frag = net_frag_read_u8(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, &hdr->type); + frag = net_frag_read_u8(frag, pos, &pos, &hdr->len); + if (!frag) { + return NULL; + } + + return hdr; +} + +struct net_icmpv6_na_hdr *net_icmpv6_get_na_hdr(struct net_pkt *pkt, + struct net_icmpv6_na_hdr *hdr) +{ + struct net_buf *frag; + u8_t *opt_data; + u16_t pos; + + opt_data = net_pkt_icmp_opt_data(pkt, sizeof(struct net_icmp_hdr)); + if (net_header_fits(pkt, opt_data, sizeof(*hdr))) { + return (struct net_icmpv6_na_hdr *)opt_data; + } + + frag = net_frag_read_u8(pkt->frags, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_icmp_hdr), + &pos, &hdr->flags); + frag = net_frag_skip(frag, pos, &pos, 3); /* reserved */ + frag = net_frag_read(frag, pos, &pos, sizeof(struct in6_addr), + (u8_t *)&hdr->tgt); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_icmpv6_na_hdr *net_icmpv6_set_na_hdr(struct net_pkt *pkt, + struct net_icmpv6_na_hdr *hdr) +{ + const u8_t reserved[3] = { 0 }; + struct net_buf *frag; + u8_t *opt_data; + u16_t pos; + + opt_data = net_pkt_icmp_opt_data(pkt, sizeof(struct net_icmp_hdr)); + if (net_header_fits(pkt, opt_data, sizeof(*hdr))) { + return (struct net_icmpv6_na_hdr *)opt_data; + } + + 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->flags), &hdr->flags, + PKT_WAIT_TIME); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(reserved), + (u8_t *)reserved, PKT_WAIT_TIME); + frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(struct in6_addr), + (u8_t *)&hdr->tgt, PKT_WAIT_TIME); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + +struct net_icmpv6_ra_hdr *net_icmpv6_get_ra_hdr(struct net_pkt *pkt, + struct net_icmpv6_ra_hdr *hdr) +{ + struct net_buf *frag; + u8_t *opt_data; + u16_t pos; + + opt_data = net_pkt_icmp_opt_data(pkt, sizeof(struct net_icmp_hdr)); + if (net_header_fits(pkt, opt_data, sizeof(*hdr))) { + return (struct net_icmpv6_ra_hdr *)opt_data; + } + + frag = net_frag_read_u8(pkt->frags, net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_icmp_hdr), + &pos, &hdr->cur_hop_limit); + frag = net_frag_read_u8(frag, pos, &pos, &hdr->flags); + frag = net_frag_read(frag, pos, &pos, sizeof(hdr->router_lifetime), + (u8_t *)&hdr->router_lifetime); + frag = net_frag_read(frag, pos, &pos, sizeof(hdr->reachable_time), + (u8_t *)&hdr->reachable_time); + frag = net_frag_read(frag, pos, &pos, sizeof(hdr->retrans_timer), + (u8_t *)&hdr->retrans_timer); + if (!frag) { + NET_ASSERT(frag); + return NULL; + } + + return hdr; +} + static enum net_verdict handle_echo_request(struct net_pkt *orig) { + struct net_icmp_hdr hdr, *icmp_hdr; struct net_pkt *pkt; struct net_buf *frag; struct net_if *iface; @@ -166,11 +433,6 @@ static enum net_verdict handle_echo_request(struct net_pkt *orig) NET_IPV6_HDR(pkt)->flow = 0; NET_IPV6_HDR(pkt)->hop_limit = net_if_ipv6_get_hop_limit(iface); - /* ICMPv6 fields */ - NET_ICMP_HDR(pkt)->type = NET_ICMPV6_ECHO_REPLY; - NET_ICMP_HDR(pkt)->code = 0; - NET_ICMP_HDR(pkt)->chksum = 0; - if (net_is_ipv6_addr_mcast(&NET_IPV6_HDR(pkt)->dst)) { net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &NET_IPV6_HDR(orig)->src); @@ -206,8 +468,13 @@ static enum net_verdict handle_echo_request(struct net_pkt *orig) */ net_pkt_ll_dst(pkt)->addr = NULL; - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv6(pkt); + /* ICMPv6 fields */ + icmp_hdr = net_icmpv6_get_hdr(pkt, &hdr); + 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, pkt->frags); echo_reply_debug(pkt); @@ -239,7 +506,10 @@ int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, int err = -EIO; if (NET_IPV6_HDR(orig)->nexthdr == IPPROTO_ICMPV6) { - if (NET_ICMP_HDR(orig)->code < 128) { + struct net_icmp_hdr icmp_hdr[1]; + + if (!net_icmpv6_get_hdr(orig, icmp_hdr) || + icmp_hdr->code < 128) { /* We must not send ICMP errors back */ err = -EINVAL; goto drop_no_pkt; @@ -299,7 +569,7 @@ int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, /* Depending on error option, we store the param into the ICMP message. */ if (type == NET_ICMPV6_PARAM_PROBLEM) { - sys_put_be32(param, net_pkt_icmp_data(pkt) + + sys_put_be32(param, (u8_t *)net_pkt_icmp_data(pkt) + sizeof(struct net_icmp_hdr)); } @@ -324,8 +594,9 @@ int net_icmpv6_send_error(struct net_pkt *orig, u8_t type, u8_t code, net_pkt_ll_dst(pkt)->addr = net_pkt_ll_src(orig)->addr; net_pkt_ll_dst(pkt)->len = net_pkt_ll_src(orig)->len; - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv6(pkt); + /* Clear and then set the chksum */ + frag = net_icmpv6_set_chksum(pkt, pkt->frags); + NET_ASSERT(frag); #if defined(CONFIG_NET_DEBUG_ICMPV6) do { @@ -379,8 +650,8 @@ int net_icmpv6_send_echo_request(struct net_if *iface, net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, src); net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, dst); - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv6(pkt); + /* Clear and then set the chksum */ + net_icmpv6_set_chksum(pkt, pkt->frags); if (net_ipv6_finalize_raw(pkt, IPPROTO_ICMPV6) < 0) { goto drop; diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index 9e7659f2e467..5f1cd2f9dd0e 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -75,27 +75,6 @@ struct net_icmpv6_nd_opt_6co { struct in6_addr prefix; } __packed; -#define NET_ICMPV6_NS_HDR(pkt) \ - ((struct net_icmpv6_ns_hdr *)(net_pkt_icmp_data(pkt) + \ - sizeof(struct net_icmp_hdr))) - -#define NET_ICMPV6_ND_OPT_HDR_HDR(pkt) \ - ((struct net_icmpv6_nd_opt_hdr *)(net_pkt_icmp_data(pkt) + \ - sizeof(struct net_icmp_hdr) + \ - net_pkt_ipv6_ext_opt_len(pkt))) - -#define NET_ICMPV6_NA_HDR(pkt) \ - ((struct net_icmpv6_na_hdr *)(net_pkt_icmp_data(pkt) + \ - sizeof(struct net_icmp_hdr))) - -#define NET_ICMPV6_RS_HDR(pkt) \ - ((struct net_icmpv6_rs_hdr *)(net_pkt_icmp_data(pkt) + \ - sizeof(struct net_icmp_hdr))) - -#define NET_ICMPV6_RA_HDR(pkt) \ - ((struct net_icmpv6_ra_hdr *)(net_pkt_icmp_data(pkt) + \ - sizeof(struct net_icmp_hdr))) - #define NET_ICMPV6_ND_O_FLAG(flag) ((flag) & 0x40) #define NET_ICMPV6_ND_M_FLAG(flag) ((flag) & 0x80) @@ -193,6 +172,26 @@ 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, u8_t type, u8_t code); + +struct net_icmp_hdr *net_icmpv6_get_hdr(struct net_pkt *pkt, + struct net_icmp_hdr *hdr); +struct net_icmp_hdr *net_icmpv6_set_hdr(struct net_pkt *pkt, + struct net_icmp_hdr *hdr); +struct net_buf *net_icmpv6_set_chksum(struct net_pkt *pkt, + struct net_buf *frag); +struct net_icmpv6_ns_hdr *net_icmpv6_get_ns_hdr(struct net_pkt *pkt, + struct net_icmpv6_ns_hdr *hdr); +struct net_icmpv6_ns_hdr *net_icmpv6_set_ns_hdr(struct net_pkt *pkt, + struct net_icmpv6_ns_hdr *hdr); +struct net_icmpv6_nd_opt_hdr *net_icmpv6_get_nd_opt_hdr(struct net_pkt *pkt, + struct net_icmpv6_nd_opt_hdr *hdr); +struct net_icmpv6_na_hdr *net_icmpv6_get_na_hdr(struct net_pkt *pkt, + struct net_icmpv6_na_hdr *hdr); +struct net_icmpv6_na_hdr *net_icmpv6_set_na_hdr(struct net_pkt *pkt, + struct net_icmpv6_na_hdr *hdr); +struct net_icmpv6_ra_hdr *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 diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index 2ca17a1457b3..db4aa4c50775 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -134,12 +134,14 @@ const struct in_addr *net_ipv4_broadcast_address(void) static inline enum net_verdict process_icmpv4_pkt(struct net_pkt *pkt, struct net_ipv4_hdr *ipv4) { - struct net_icmp_hdr *hdr = NET_ICMP_HDR(pkt); + struct net_icmp_hdr hdr, *icmp_hdr; + + icmp_hdr = net_icmpv4_get_hdr(pkt, &hdr); NET_DBG("ICMPv4 packet received type %d code %d", - hdr->type, hdr->code); + icmp_hdr->type, icmp_hdr->code); - return net_icmpv4_input(pkt, hdr->type, hdr->code); + return net_icmpv4_input(pkt, icmp_hdr->type, icmp_hdr->code); } enum net_verdict net_ipv4_process_pkt(struct net_pkt *pkt) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 3d10f100c3ed..eaeb824f4f87 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -93,17 +93,32 @@ static void ipv6_nbr_set_state(struct net_nbr *nbr, static inline bool net_is_solicited(struct net_pkt *pkt) { - return NET_ICMPV6_NA_HDR(pkt)->flags & NET_ICMPV6_NA_FLAG_SOLICITED; + struct net_icmpv6_na_hdr hdr, *na_hdr; + + na_hdr = net_icmpv6_get_na_hdr(pkt, &hdr); + NET_ASSERT(na_hdr); + + return na_hdr->flags & NET_ICMPV6_NA_FLAG_SOLICITED; } static inline bool net_is_router(struct net_pkt *pkt) { - return NET_ICMPV6_NA_HDR(pkt)->flags & NET_ICMPV6_NA_FLAG_ROUTER; + struct net_icmpv6_na_hdr hdr, *na_hdr; + + na_hdr = net_icmpv6_get_na_hdr(pkt, &hdr); + NET_ASSERT(na_hdr); + + return na_hdr->flags & NET_ICMPV6_NA_FLAG_ROUTER; } static inline bool net_is_override(struct net_pkt *pkt) { - return NET_ICMPV6_NA_HDR(pkt)->flags & NET_ICMPV6_NA_FLAG_OVERRIDE; + struct net_icmpv6_na_hdr hdr, *na_hdr; + + na_hdr = net_icmpv6_get_na_hdr(pkt, &hdr); + NET_ASSERT(na_hdr); + + return na_hdr->flags & NET_ICMPV6_NA_FLAG_OVERRIDE; } static inline struct net_nbr *get_nbr(int idx) @@ -697,9 +712,7 @@ int net_ipv6_finalize_raw(struct net_pkt *pkt, u8_t next_header) #endif if (next_header == IPPROTO_ICMPV6) { - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum(pkt, - IPPROTO_ICMPV6); + net_icmpv6_set_chksum(pkt, pkt->frags); } return 0; @@ -1062,6 +1075,10 @@ static inline void set_llao(struct net_linkaddr *lladdr, 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; @@ -1071,40 +1088,55 @@ static void setup_headers(struct net_pkt *pkt, u8_t nd6_len, NET_IPV6_HDR(pkt)->nexthdr = IPPROTO_ICMPV6; NET_IPV6_HDR(pkt)->hop_limit = NET_IPV6_ND_HOP_LIMIT; - NET_ICMP_HDR(pkt)->type = icmp_type; - NET_ICMP_HDR(pkt)->code = 0; + /* 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 void handle_ns_neighbor(struct net_pkt *pkt, - struct net_icmpv6_nd_opt_hdr *hdr) +static inline void handle_ns_neighbor(struct net_pkt *pkt, u8_t ll_len, + u16_t sllao_offset) { - struct net_linkaddr lladdr = { - .len = 8 * hdr->len - 2, - .addr = (u8_t *)hdr + 2, - }; + 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) { + return; + } + + nbr_lladdr.len = lladdr.len; + nbr_lladdr.addr = lladdr.addr; /** * IEEE802154 lladdress is 8 bytes long, so it requires * 2 * 8 bytes - 2 - padding. * The formula above needs to be adjusted. */ - if (net_pkt_ll_src(pkt)->len < lladdr.len) { - lladdr.len = net_pkt_ll_src(pkt)->len; + if (net_pkt_ll_src(pkt)->len < nbr_lladdr.len) { + nbr_lladdr.len = net_pkt_ll_src(pkt)->len; } - nbr_add(pkt, &lladdr, false, NET_IPV6_NBR_STATE_INCOMPLETE); + nbr_add(pkt, &nbr_lladdr, false, NET_IPV6_NBR_STATE_INCOMPLETE); } int net_ipv6_send_na(struct net_if *iface, struct in6_addr *src, struct in6_addr *dst, struct in6_addr *tgt, u8_t flags) { + struct net_icmpv6_na_hdr hdr, *na_hdr; struct net_pkt *pkt; struct net_buf *frag; u8_t llao_len; pkt = net_pkt_get_reserve_tx(net_if_get_ll_reserve(iface, dst), - K_FOREVER); + K_FOREVER); NET_ASSERT_INFO(pkt, "Out of TX packets"); @@ -1127,27 +1159,32 @@ int net_ipv6_send_na(struct net_if *iface, struct in6_addr *src, setup_headers(pkt, sizeof(struct net_icmpv6_na_hdr) + llao_len, NET_ICMPV6_NA); + net_buf_add(frag, sizeof(struct net_icmpv6_na_hdr) + llao_len); + + na_hdr = net_icmpv6_get_na_hdr(pkt, &hdr); + NET_ASSERT_INFO(na_hdr, "Too short fragment for NA"); + net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, src); net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, dst); - net_ipaddr_copy(&NET_ICMPV6_NA_HDR(pkt)->tgt, tgt); + net_ipaddr_copy(&na_hdr->tgt, tgt); set_llao(&net_pkt_iface(pkt)->link_addr, - net_pkt_icmp_data(pkt) + sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_na_hdr), + (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); - NET_ICMPV6_NA_HDR(pkt)->flags = flags; + na_hdr->flags = flags; + net_icmpv6_set_na_hdr(pkt, na_hdr); pkt->frags->len = NET_IPV6ICMPH_LEN + sizeof(struct net_icmpv6_na_hdr) + llao_len; - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv6(pkt); + net_icmpv6_set_chksum(pkt, pkt->frags); dbg_addr_sent_tgt("Neighbor Advertisement", &NET_IPV6_HDR(pkt)->src, &NET_IPV6_HDR(pkt)->dst, - &NET_ICMPV6_NS_HDR(pkt)->tgt); + &na_hdr->tgt); if (net_send_data(pkt) < 0) { goto drop; @@ -1167,66 +1204,75 @@ int net_ipv6_send_na(struct net_if *iface, struct in6_addr *src, static enum net_verdict handle_ns_input(struct net_pkt *pkt) { u16_t total_len = net_pkt_get_len(pkt); - struct net_icmpv6_nd_opt_hdr *hdr; + struct net_icmpv6_nd_opt_hdr ndopthdr, *nd_opt_hdr; + struct net_icmpv6_ns_hdr nshdr, *ns_hdr; struct net_if_addr *ifaddr; u8_t flags = 0, prev_opt_len = 0; int ret; size_t left_len; + ns_hdr = net_icmpv6_get_ns_hdr(pkt, &nshdr); + NET_ASSERT(ns_hdr); + dbg_addr_recv_tgt("Neighbor Solicitation", &NET_IPV6_HDR(pkt)->src, &NET_IPV6_HDR(pkt)->dst, - &NET_ICMPV6_NS_HDR(pkt)->tgt); + &ns_hdr->tgt); net_stats_update_ipv6_nd_recv(); if ((total_len < (sizeof(struct net_ipv6_hdr) + sizeof(struct net_icmp_hdr) + sizeof(struct net_icmpv6_ns_hdr))) || - (NET_ICMP_HDR(pkt)->code != 0) || - (NET_IPV6_HDR(pkt)->hop_limit != NET_IPV6_ND_HOP_LIMIT) || - net_is_ipv6_addr_mcast(&NET_ICMPV6_NS_HDR(pkt)->tgt)) { - 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)), - NET_ICMP_HDR(pkt)->code, NET_IPV6_HDR(pkt)->hop_limit); - goto drop; + (NET_IPV6_HDR(pkt)->hop_limit != NET_IPV6_ND_HOP_LIMIT)) { + if (net_is_ipv6_addr_mcast(&ns_hdr->tgt)) { + struct net_icmp_hdr hdr, *icmp_hdr; + + icmp_hdr = net_icmpv6_get_hdr(pkt, &hdr); + if (!icmp_hdr || 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, + NET_IPV6_HDR(pkt)->hop_limit); + goto drop; + } + } } net_pkt_set_ipv6_ext_opt_len(pkt, sizeof(struct net_icmpv6_ns_hdr)); - hdr = NET_ICMPV6_ND_OPT_HDR_HDR(pkt); - - /* The parsing gets tricky if the ND struct is split - * between two fragments. FIXME later. - */ - if (pkt->frags->len < ((u8_t *)hdr - pkt->frags->data)) { - NET_DBG("NS struct split between fragments"); - goto drop; - } - left_len = pkt->frags->len - (sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr)); + nd_opt_hdr = net_icmpv6_get_nd_opt_hdr(pkt, &ndopthdr); + NET_ASSERT(nd_opt_hdr); - while (net_pkt_ipv6_ext_opt_len(pkt) < left_len && - left_len < pkt->frags->len) { + left_len = net_pkt_get_len(pkt) - (sizeof(struct net_ipv6_hdr) + + sizeof(struct net_icmp_hdr)); - if (!hdr->len) { + while (nd_opt_hdr && net_pkt_ipv6_ext_opt_len(pkt) < left_len) { + if (!nd_opt_hdr->len) { break; } - switch (hdr->type) { + switch (nd_opt_hdr->type) { case NET_ICMPV6_ND_OPT_SLLAO: if (net_is_ipv6_addr_unspecified( &NET_IPV6_HDR(pkt)->src)) { goto drop; } - handle_ns_neighbor(pkt, hdr); + 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); break; default: - NET_DBG("Unknown ND option 0x%x", hdr->type); + NET_DBG("Unknown ND option 0x%x", nd_opt_hdr->type); break; } @@ -1234,21 +1280,21 @@ 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) + - (hdr->len << 3)); + (nd_opt_hdr->len << 3)); if (prev_opt_len >= net_pkt_ipv6_ext_opt_len(pkt)) { NET_ERR("Corrupted NS message"); goto drop; } - hdr = NET_ICMPV6_ND_OPT_HDR_HDR(pkt); + nd_opt_hdr = net_icmpv6_get_nd_opt_hdr(pkt, &ndopthdr); } ifaddr = net_if_ipv6_addr_lookup_by_iface(net_pkt_iface(pkt), - &NET_ICMPV6_NS_HDR(pkt)->tgt); + &ns_hdr->tgt); if (!ifaddr) { NET_DBG("No such interface address %s", - net_sprint_ipv6_addr(&NET_ICMPV6_NS_HDR(pkt)->tgt)); + net_sprint_ipv6_addr(&ns_hdr->tgt)); goto drop; } @@ -1298,8 +1344,7 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) if (net_is_ipv6_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, - &NET_ICMPV6_NS_HDR(pkt)->tgt); + net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, &ns_hdr->tgt); flags = NET_ICMPV6_NA_FLAG_SOLICITED | NET_ICMPV6_NA_FLAG_OVERRIDE; goto send_na; @@ -1310,8 +1355,7 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) &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, - &NET_ICMPV6_NS_HDR(pkt)->tgt); + net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, &ns_hdr->tgt); flags = NET_ICMPV6_NA_FLAG_SOLICITED | NET_ICMPV6_NA_FLAG_OVERRIDE; goto send_na; @@ -1441,22 +1485,23 @@ void net_ipv6_nbr_set_reachable_timer(struct net_if *iface, struct net_nbr *nbr) #if defined(CONFIG_NET_IPV6_NBR_CACHE) static inline bool handle_na_neighbor(struct net_pkt *pkt, - struct net_icmpv6_nd_opt_hdr *hdr, - u8_t *tllao) + 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 }; struct net_linkaddr_storage *cached_lladdr; struct net_pkt *pending; - - ARG_UNUSED(hdr); + struct net_buf *frag; + u16_t pos; nbr = nbr_lookup(&net_neighbor.table, net_pkt_iface(pkt), - &NET_ICMPV6_NS_HDR(pkt)->tgt); + &na_hdr->tgt); NET_DBG("Neighbor lookup %p iface %p addr %s", nbr, net_pkt_iface(pkt), - net_sprint_ipv6_addr(&NET_ICMPV6_NS_HDR(pkt)->tgt)); + net_sprint_ipv6_addr(&na_hdr->tgt)); if (!nbr) { nbr_print(); @@ -1465,26 +1510,36 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, return false; } + if (tllao_offset) { + lladdr.len = net_pkt_iface(pkt)->link_addr.len; + + frag = net_frag_read(pkt->frags, tllao_offset, + &pos, lladdr.len, lladdr.addr); + if (!frag && pos == 0xffff) { + return false; + } + } + if (nbr->idx == NET_NBR_LLADDR_UNKNOWN) { - struct net_linkaddr lladdr; + struct net_linkaddr nbr_lladdr; - if (!tllao) { + if (!tllao_offset) { NET_DBG("No target link layer address."); return false; } - lladdr.len = net_pkt_iface(pkt)->link_addr.len; - lladdr.addr = &tllao[NET_ICMPV6_OPT_DATA_OFFSET]; + nbr_lladdr.len = lladdr.len; + nbr_lladdr.addr = lladdr.addr; - if (net_nbr_link(nbr, net_pkt_iface(pkt), &lladdr)) { + if (net_nbr_link(nbr, net_pkt_iface(pkt), &nbr_lladdr)) { nbr_free(nbr); return false; } NET_DBG("[%d] nbr %p state %d IPv6 %s ll %s", nbr->idx, nbr, net_ipv6_nbr_data(nbr)->state, - net_sprint_ipv6_addr(&NET_ICMPV6_NS_HDR(pkt)->tgt), - net_sprint_ll_addr(lladdr.addr, lladdr.len)); + net_sprint_ipv6_addr(&na_hdr->tgt), + net_sprint_ll_addr(nbr_lladdr.addr, nbr_lladdr.len)); } cached_lladdr = net_nbr_get_lladdr(nbr->idx); @@ -1493,26 +1548,24 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, return false; } - if (tllao) { - lladdr_changed = memcmp(&tllao[NET_ICMPV6_OPT_DATA_OFFSET], + if (tllao_offset) { + lladdr_changed = memcmp(lladdr.addr, cached_lladdr->addr, cached_lladdr->len); } /* Update the cached address if we do not yet known it */ if (net_ipv6_nbr_data(nbr)->state == NET_IPV6_NBR_STATE_INCOMPLETE) { - if (!tllao) { + if (!tllao_offset) { return false; } if (lladdr_changed) { - dbg_update_neighbor_lladdr_raw( - &tllao[NET_ICMPV6_OPT_DATA_OFFSET], - cached_lladdr, - &NET_ICMPV6_NS_HDR(pkt)->tgt); + dbg_update_neighbor_lladdr_raw(lladdr.addr, + cached_lladdr, + &na_hdr->tgt); - net_linkaddr_set(cached_lladdr, - &tllao[NET_ICMPV6_OPT_DATA_OFFSET], + net_linkaddr_set(cached_lladdr, lladdr.addr, cached_lladdr->len); } @@ -1548,16 +1601,13 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, } if (net_is_override(pkt) || - (!net_is_override(pkt) && tllao && !lladdr_changed)) { + (!net_is_override(pkt) && tllao_offset && !lladdr_changed)) { if (lladdr_changed) { dbg_update_neighbor_lladdr_raw( - &tllao[NET_ICMPV6_OPT_DATA_OFFSET], - cached_lladdr, - &NET_ICMPV6_NS_HDR(pkt)->tgt); + lladdr.addr, cached_lladdr, &na_hdr->tgt); - net_linkaddr_set(cached_lladdr, - &tllao[NET_ICMPV6_OPT_DATA_OFFSET], + net_linkaddr_set(cached_lladdr, lladdr.addr, cached_lladdr->len); } @@ -1612,16 +1662,20 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, static enum net_verdict handle_na_input(struct net_pkt *pkt) { u16_t total_len = net_pkt_get_len(pkt); - struct net_icmpv6_nd_opt_hdr *hdr; - struct net_if_addr *ifaddr; - u8_t *tllao = NULL; + u16_t tllao_offset = 0; u8_t prev_opt_len = 0; + struct net_icmpv6_nd_opt_hdr ndopthdr, *nd_opt_hdr; + struct net_icmpv6_na_hdr nahdr, *na_hdr; + struct net_if_addr *ifaddr; size_t left_len; + na_hdr = net_icmpv6_get_na_hdr(pkt, &nahdr); + NET_ASSERT(na_hdr); + dbg_addr_recv_tgt("Neighbor Advertisement", &NET_IPV6_HDR(pkt)->src, &NET_IPV6_HDR(pkt)->dst, - &NET_ICMPV6_NS_HDR(pkt)->tgt); + &na_hdr->tgt); net_stats_update_ipv6_nd_recv(); @@ -1629,42 +1683,40 @@ 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_ICMP_HDR(pkt)->code != 0) || (NET_IPV6_HDR(pkt)->hop_limit != NET_IPV6_ND_HOP_LIMIT) || - net_is_ipv6_addr_mcast(&NET_ICMPV6_NS_HDR(pkt)->tgt) || + net_is_ipv6_addr_mcast(&na_hdr->tgt) || (net_is_solicited(pkt) && net_is_ipv6_addr_mcast(&NET_IPV6_HDR(pkt)->dst))) { - goto drop; + struct net_icmp_hdr hdr, *icmp_hdr; + + icmp_hdr = net_icmpv6_get_hdr(pkt, &hdr); + if (!icmp_hdr || icmp_hdr->code != 0) { + goto drop; + } } net_pkt_set_ipv6_ext_opt_len(pkt, sizeof(struct net_icmpv6_na_hdr)); - hdr = NET_ICMPV6_ND_OPT_HDR_HDR(pkt); - - /* The parsing gets tricky if the ND struct is split - * between two fragments. FIXME later. - */ - if (pkt->frags->len < ((u8_t *)hdr - pkt->frags->data)) { - NET_DBG("NA struct split between fragments"); - goto drop; - } - left_len = pkt->frags->len - (sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr)); + nd_opt_hdr = net_icmpv6_get_nd_opt_hdr(pkt, &ndopthdr); - while (net_pkt_ipv6_ext_opt_len(pkt) < left_len && - left_len < pkt->frags->len) { + left_len = net_pkt_get_len(pkt) - (sizeof(struct net_ipv6_hdr) + + sizeof(struct net_icmp_hdr)); - if (!hdr->len) { + while (nd_opt_hdr && net_pkt_ipv6_ext_opt_len(pkt) < left_len) { + if (!nd_opt_hdr->len) { break; } - switch (hdr->type) { + switch (nd_opt_hdr->type) { case NET_ICMPV6_ND_OPT_TLLAO: - tllao = (u8_t *)hdr; + tllao_offset = 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; break; default: - NET_DBG("Unknown ND option 0x%x", hdr->type); + NET_DBG("Unknown ND option 0x%x", nd_opt_hdr->type); break; } @@ -1672,34 +1724,34 @@ 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) + - (hdr->len << 3)); + (nd_opt_hdr->len << 3)); if (prev_opt_len >= net_pkt_ipv6_ext_opt_len(pkt)) { NET_ERR("Corrupted NA message"); goto drop; } - hdr = NET_ICMPV6_ND_OPT_HDR_HDR(pkt); + nd_opt_hdr = net_icmpv6_get_nd_opt_hdr(pkt, &ndopthdr); + NET_ASSERT_INFO(nd_opt_hdr, "End-of-opt, this is expected."); } ifaddr = net_if_ipv6_addr_lookup_by_iface(net_pkt_iface(pkt), - &NET_ICMPV6_NA_HDR(pkt)->tgt); + &na_hdr->tgt); if (ifaddr) { NET_DBG("Interface %p already has address %s", net_pkt_iface(pkt), - net_sprint_ipv6_addr(&NET_ICMPV6_NA_HDR(pkt)->tgt)); + 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), - &NET_ICMPV6_NA_HDR(pkt)->tgt); + dad_failed(net_pkt_iface(pkt), &na_hdr->tgt); } #endif /* CONFIG_NET_IPV6_DAD */ goto drop; } - if (!handle_na_neighbor(pkt, hdr, tllao)) { + if (!handle_na_neighbor(pkt, na_hdr, tllao_offset)) { goto drop; } @@ -1722,6 +1774,7 @@ int net_ipv6_send_ns(struct net_if *iface, struct in6_addr *tgt, bool is_my_address) { + struct net_icmpv6_ns_hdr hdr, *ns_hdr; struct net_pkt *pkt; struct net_buf *frag; struct net_nbr *nbr; @@ -1741,6 +1794,7 @@ int net_ipv6_send_ns(struct net_if *iface, 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); net_pkt_ll_clear(pkt); @@ -1749,6 +1803,11 @@ int net_ipv6_send_ns(struct net_if *iface, setup_headers(pkt, sizeof(struct net_icmpv6_ns_hdr) + llao_len, NET_ICMPV6_NS); + net_buf_add(frag, sizeof(struct net_icmpv6_ns_hdr)); + + ns_hdr = net_icmpv6_get_ns_hdr(pkt, &hdr); + NET_ASSERT(ns_hdr); + if (!dst) { net_ipv6_addr_create_solicited_node(tgt, &NET_IPV6_HDR(pkt)->dst); @@ -1756,9 +1815,8 @@ int net_ipv6_send_ns(struct net_if *iface, net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, dst); } - NET_ICMPV6_NS_HDR(pkt)->reserved = 0; - - net_ipaddr_copy(&NET_ICMPV6_NS_HDR(pkt)->tgt, tgt); + net_ipaddr_copy(&ns_hdr->tgt, tgt); + net_icmpv6_set_ns_hdr(pkt, ns_hdr); if (is_my_address) { /* DAD */ @@ -1766,11 +1824,6 @@ int net_ipv6_send_ns(struct net_if *iface, net_ipv6_unspecified_address()); NET_IPV6_HDR(pkt)->len[1] -= llao_len; - - net_buf_add(frag, - sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_ns_hdr)); } else { if (src) { net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, src); @@ -1786,33 +1839,26 @@ int net_ipv6_send_ns(struct net_if *iface, goto drop; } + net_buf_add(frag, llao_len); + set_llao(&net_pkt_iface(pkt)->link_addr, - net_pkt_icmp_data(pkt) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_ns_hdr), + (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); - - net_buf_add(frag, - sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_ns_hdr) + llao_len); } - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv6(pkt); + net_icmpv6_set_chksum(pkt, pkt->frags); - nbr = nbr_lookup(&net_neighbor.table, net_pkt_iface(pkt), - &NET_ICMPV6_NS_HDR(pkt)->tgt); + nbr = nbr_lookup(&net_neighbor.table, net_pkt_iface(pkt), &ns_hdr->tgt); if (!nbr) { nbr_print(); - nbr = nbr_new(net_pkt_iface(pkt), - &NET_ICMPV6_NS_HDR(pkt)->tgt, false, + nbr = nbr_new(net_pkt_iface(pkt), &ns_hdr->tgt, false, NET_IPV6_NBR_STATE_INCOMPLETE); if (!nbr) { NET_DBG("Could not create new neighbor %s", - net_sprint_ipv6_addr( - &NET_ICMPV6_NS_HDR(pkt)->tgt)); + net_sprint_ipv6_addr(&ns_hdr->tgt)); goto drop; } } @@ -1837,7 +1883,7 @@ 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, - &NET_ICMPV6_NS_HDR(pkt)->tgt); + &ns_hdr->tgt); if (net_send_data(pkt) < 0) { NET_DBG("Cannot send NS %p (pending %p)", pkt, pending); @@ -1896,25 +1942,19 @@ int net_ipv6_send_rs(struct net_if *iface) 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_pkt_iface(pkt)->link_addr, - net_pkt_icmp_data(pkt) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_rs_hdr), + (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); - - net_buf_add(frag, sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_rs_hdr) + - llao_len); - } else { - net_buf_add(frag, sizeof(struct net_ipv6_hdr) + - sizeof(struct net_icmp_hdr) + - sizeof(struct net_icmpv6_rs_hdr)); } - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv6(pkt); + net_icmpv6_set_chksum(pkt, pkt->frags); dbg_addr_sent("Router Solicitation", &NET_IPV6_HDR(pkt)->src, @@ -2220,6 +2260,7 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt) { u16_t total_len = net_pkt_get_len(pkt); struct net_nbr *nbr = NULL; + struct net_icmpv6_ra_hdr hdr, *ra_hdr; struct net_if_router *router; struct net_buf *frag; u16_t router_lifetime; @@ -2241,10 +2282,14 @@ 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_ICMP_HDR(pkt)->code != 0) || (NET_IPV6_HDR(pkt)->hop_limit != NET_IPV6_ND_HOP_LIMIT) || !net_is_ipv6_ll_addr(&NET_IPV6_HDR(pkt)->src)) { - goto drop; + struct net_icmp_hdr icmphdr, *icmp_hdr; + + icmp_hdr = net_icmpv6_get_hdr(pkt, &icmphdr); + if (!icmp_hdr || icmp_hdr->code != 0) { + goto drop; + } } frag = pkt->frags; @@ -2270,9 +2315,12 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt) goto drop; } + ra_hdr = net_icmpv6_get_ra_hdr(pkt, &hdr); + NET_ASSERT(ra_hdr); + if (reachable_time && (net_if_ipv6_get_reachable_time(net_pkt_iface(pkt)) != - NET_ICMPV6_RA_HDR(pkt)->reachable_time)) { + ra_hdr->reachable_time)) { net_if_ipv6_set_base_reachable_time(net_pkt_iface(pkt), reachable_time); @@ -2637,10 +2685,13 @@ static enum net_verdict handle_mld_query(struct net_pkt *pkt) net_stats_update_ipv6_mld_recv(); /* offset tells now where the ICMPv6 header is starting */ - offset = net_pkt_icmp_data(pkt) - net_pkt_ip_data(pkt); - offset += sizeof(struct net_icmp_hdr); + 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(pkt->frags, offset, &pos, &max_rsp_code); + 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 */ @@ -2654,12 +2705,16 @@ 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_ICMP_HDR(pkt)->code != 0) || (NET_IPV6_HDR(pkt)->hop_limit != 1))) { - NET_DBG("Preliminary check failed %u/%u, code %u, hop %u", - total_len, pkt_len, - NET_ICMP_HDR(pkt)->code, NET_IPV6_HDR(pkt)->hop_limit); - goto drop; + struct net_icmp_hdr hdr, *icmp_hdr; + + icmp_hdr = net_icmpv6_get_hdr(pkt, &hdr); + if (!icmp_hdr || 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); + goto drop; + } } /* Currently we only support a unspecified address query. */ @@ -3484,12 +3539,16 @@ int net_ipv6_send_fragmented_pkt(struct net_if *iface, struct net_pkt *pkt, static inline enum net_verdict process_icmpv6_pkt(struct net_pkt *pkt, struct net_ipv6_hdr *ipv6) { - struct net_icmp_hdr *hdr = NET_ICMP_HDR(pkt); + struct net_icmp_hdr hdr, *icmp_hdr; + + icmp_hdr = net_icmpv6_get_hdr(pkt, &hdr); + NET_ASSERT(icmp_hdr); NET_DBG("ICMPv6 %s received type %d code %d", - net_icmpv6_type2str(hdr->type), hdr->type, hdr->code); + net_icmpv6_type2str(icmp_hdr->type), icmp_hdr->type, + icmp_hdr->code); - return net_icmpv6_input(pkt, hdr->type, hdr->code); + return net_icmpv6_input(pkt, icmp_hdr->type, icmp_hdr->code); } static inline struct net_pkt *check_unknown_option(struct net_pkt *pkt, diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 561414f201f7..3e830cd14060 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -1658,6 +1658,68 @@ void net_pkt_print(void) } #endif /* CONFIG_NET_DEBUG_NET_PKT */ +struct net_buf *net_frag_get_pos(struct net_pkt *pkt, + u16_t offset, + u16_t *pos) +{ + struct net_buf *frag; + + frag = net_frag_skip(pkt->frags, offset, pos, 0); + if (!frag) { + return NULL; + } + + return frag; +} + +struct net_icmp_hdr *net_pkt_icmp_data(struct net_pkt *pkt) +{ + struct net_buf *frag; + u16_t offset; + + frag = net_frag_get_pos(pkt, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt), + &offset); + if (!frag) { + /* We tried to read past the end of the data */ + NET_ASSERT_INFO(frag, + "IP hdr %d ext len %d offset %d total %zd", + net_pkt_ip_hdr_len(pkt), + net_pkt_ipv6_ext_len(pkt), + offset, net_buf_frags_len(pkt->frags)); + return NULL; + } + + return (struct net_icmp_hdr *)(frag->data + offset); +} + +u8_t *net_pkt_icmp_opt_data(struct net_pkt *pkt, size_t opt_len) +{ + struct net_buf *frag; + u16_t offset; + + frag = net_frag_get_pos(pkt, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + opt_len, + &offset); + if (!frag) { + /* We tried to read past the end of the data */ + NET_ASSERT_INFO(frag, + "IP hdr %d ext len %d offset %d pos %zd " + "total %zd", + net_pkt_ip_hdr_len(pkt), + net_pkt_ipv6_ext_len(pkt), + offset, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + opt_len, + net_buf_frags_len(pkt->frags)); + return NULL; + } + + return frag->data + offset; +} + void net_pkt_init(void) { NET_DBG("Allocating %u RX (%zu bytes), %u TX (%zu bytes), " diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 6a87746e9671..dac33ebebb73 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -35,6 +35,28 @@ extern char *net_sprint_ll_addr_buf(const u8_t *ll, u8_t ll_len, extern u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto); bool net_header_fits(struct net_pkt *pkt, u8_t *hdr, size_t hdr_size); +struct net_icmp_hdr *net_pkt_icmp_data(struct net_pkt *pkt); +u8_t *net_pkt_icmp_opt_data(struct net_pkt *pkt, size_t opt_len); + +/* Check if ICMP header can be directly accessed from memory. + * If returned value is NULL, then the header was split into + * multiple fragments and user must use net_pkt_read/write() etc to get/set + * the ICMP header values. + * If returned value is not NULL, then the first fragment will + * hold the ICMP header and returned value will point to start of ICMP header + * inside net_pkt. + */ +static inline +struct net_icmp_hdr *net_icmp_header_fits(struct net_pkt *pkt, + struct net_icmp_hdr *hdr) +{ + if (net_header_fits(pkt, (u8_t *)hdr, sizeof(*hdr))) { + return hdr; + } + + return NULL; +} + #if defined(CONFIG_NET_IPV4) extern u16_t net_calc_chksum_ipv4(struct net_pkt *pkt); #endif /* CONFIG_NET_IPV4 */ diff --git a/subsys/net/ip/rpl.c b/subsys/net/ip/rpl.c index 3595ae9725c4..9487c00f853e 100644 --- a/subsys/net/ip/rpl.c +++ b/subsys/net/ip/rpl.c @@ -2767,12 +2767,14 @@ static enum net_verdict handle_dio(struct net_pkt *pkt) } /* offset tells now where the ICMPv6 header is starting */ - offset = net_pkt_icmp_data(pkt) - net_pkt_ip_data(pkt); - - offset += sizeof(struct net_icmp_hdr); + frag = net_frag_get_pos(pkt, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_icmp_hdr), + &offset); /* First the DIO option. */ - frag = net_frag_read_u8(pkt->frags, offset, &pos, &dio.instance_id); + frag = net_frag_read_u8(frag, offset, &pos, &dio.instance_id); frag = net_frag_read_u8(frag, pos, &pos, &dio.version); frag = net_frag_read_be16(frag, pos, &pos, &dio.rank); @@ -3147,8 +3149,7 @@ static inline int dao_forward(struct net_if *iface, net_pkt_set_family(pkt, AF_INET6); net_pkt_set_iface(pkt, iface); - NET_ICMP_HDR(pkt)->chksum = 0; - NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv6(pkt); + net_icmpv6_set_chksum(pkt, pkt->frags); ret = net_send_data(pkt); if (ret >= 0) { @@ -3274,11 +3275,17 @@ static enum net_verdict handle_dao(struct net_pkt *pkt) net_rpl_info(pkt, "Destination Advertisement Object"); /* offset tells now where the ICMPv6 header is starting */ - offset = net_pkt_icmp_data(pkt) - net_pkt_ip_data(pkt); - - offset += sizeof(struct net_icmp_hdr); + 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_u8(pkt->frags, offset, &pos, &instance_id); + frag = net_frag_read_u8(frag, offset, &pos, &instance_id); + if (!frag) { + NET_DBG("Cannot get instance id"); + return NET_DROP; + } instance = net_rpl_get_instance(instance_id); if (!instance) { @@ -3538,11 +3545,13 @@ static enum net_verdict handle_dao_ack(struct net_pkt *pkt) net_rpl_info(pkt, "Destination Advertisement Object Ack"); /* offset tells now where the ICMPv6 header is starting */ - offset = net_pkt_icmp_data(pkt) - net_pkt_ip_data(pkt); - - offset += sizeof(struct net_icmp_hdr); + 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_u8(pkt->frags, offset, &pos, &instance_id); + frag = net_frag_read_u8(frag, offset, &pos, &instance_id); if (!frag && pos == 0xffff) { /* Read error */ return NET_DROP; diff --git a/tests/net/ipv6/src/main.c b/tests/net/ipv6/src/main.c index b901a680a3c4..e7a490d95b7b 100644 --- a/tests/net/ipv6/src/main.c +++ b/tests/net/ipv6/src/main.c @@ -188,6 +188,8 @@ static struct net_pkt *prepare_ra_message(void) return pkt; } +#define NET_ICMP_HDR(pkt) ((struct net_icmp_hdr *)net_pkt_icmp_data(pkt)) + static int tester_send(struct net_if *iface, struct net_pkt *pkt) { struct net_icmp_hdr *icmp; diff --git a/tests/net/mld/src/main.c b/tests/net/mld/src/main.c index 0122e0a7719e..e41798211ca2 100644 --- a/tests/net/mld/src/main.c +++ b/tests/net/mld/src/main.c @@ -91,6 +91,8 @@ static void net_test_iface_init(struct net_if *iface) NET_LINK_ETHERNET); } +#define NET_ICMP_HDR(pkt) ((struct net_icmp_hdr *)net_pkt_icmp_data(pkt)) + static int tester_send(struct net_if *iface, struct net_pkt *pkt) { struct net_icmp_hdr *icmp = NET_ICMP_HDR(pkt); diff --git a/tests/net/rpl/src/main.c b/tests/net/rpl/src/main.c index b5bb941986aa..63b0355ebe17 100644 --- a/tests/net/rpl/src/main.c +++ b/tests/net/rpl/src/main.c @@ -119,6 +119,8 @@ static void set_pkt_ll_addr(struct device *dev, struct net_pkt *pkt) src->addr = rpl->mac_addr; } +#define NET_ICMP_HDR(pkt) ((struct net_icmp_hdr *)net_pkt_icmp_data(pkt)) + static int tester_send(struct net_if *iface, struct net_pkt *pkt) { if (!pkt->frags) {