From a5f361e984311ef11b5420a65aaacc93f8e08589 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 6 Jul 2017 12:00:59 -0600 Subject: [PATCH] ICMPv6: Fix so that ICMPv6 can be used with 6LoWPAN. --- include/nuttx/net/icmpv6.h | 41 ++++++++++++++++---------- net/icmpv6/icmpv6_advertise.c | 16 ++++++---- net/icmpv6/icmpv6_input.c | 2 +- net/icmpv6/icmpv6_radvertise.c | 54 +++++++++++++--------------------- net/icmpv6/icmpv6_rsolicit.c | 19 +++++++----- net/icmpv6/icmpv6_solicit.c | 21 ++++++++----- net/neighbor/neighbor.h | 1 + 7 files changed, 84 insertions(+), 70 deletions(-) diff --git a/include/nuttx/net/icmpv6.h b/include/nuttx/net/icmpv6.h index e0e8ecba99..c576b2da9d 100644 --- a/include/nuttx/net/icmpv6.h +++ b/include/nuttx/net/icmpv6.h @@ -2,7 +2,7 @@ * include/nuttx/net/icmpv6.h * Header file for the NuttX ICMPv6 stack. * - * Copyright (C) 2007-2009, 2012, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2012, 2014, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This logic was leveraged from uIP which also has a BSD-style license: @@ -123,6 +123,13 @@ #define ICMPv6_PRFX_FLAG_L (1 << 7) /* On-link flag */ #define ICMPv6_PRFX_FLAG_A (1 << 6) /* Autonomous address-configuration flag +/* Return with size of an option (in full octects) using the size of a link + * layer address taking into account a header of the two-bytes. + */ + +#define ICMPv6_OPT_SIZE(a) (((a) + 2 + 7) & ~7) +#define ICMPv6_OPT_OCTECTS(a) (((a) + 2 + 7) >> 3) + /**************************************************************************** * Public Type Definitions ****************************************************************************/ @@ -178,11 +185,12 @@ struct icmpv6_neighbor_solicit_s uint8_t opttype; /* Option Type: ICMPv6_OPT_SRCLLADDR */ uint8_t optlen; /* Option length: 1 octet */ -#ifdef CONFIG_NET_ETHERNET uint8_t srclladdr[6]; /* Options: Source link layer address */ -#endif }; +#define SIZEOF_ICMPV6_NEIGHBOR_SOLICIT_S(n) \ + (sizeof(struct icmpv6_neighbor_solicit_s) + ICMPv6_OPT_SIZE(n) - 8) + /* This the message format for the ICMPv6 Neighbor Advertisement message */ struct icmpv6_neighbor_advertise_s @@ -194,12 +202,14 @@ struct icmpv6_neighbor_advertise_s net_ipv6addr_t tgtaddr; /* Target IPv6 address */ uint8_t opttype; /* Option Type: ICMPv6_OPT_TGTLLADDR */ - uint8_t optlen; /* Option length: 1 octet */ -#ifdef CONFIG_NET_ETHERNET + uint8_t optlen; /* Option length in octets */ uint8_t tgtlladdr[6]; /* Options: Target link layer address */ -#endif + /* Actual size detemined by optlen */ }; +#define SIZEOF_ICMPV6_NEIGHBOR_ADVERTISE_S(n) \ + (sizeof(struct icmpv6_neighbor_advertise_s) + ICMPv6_OPT_SIZE(n) - 8) + /* This the message format for the ICMPv6 Router Solicitation message */ struct icmpv6_router_solicit_s @@ -210,12 +220,13 @@ struct icmpv6_router_solicit_s uint8_t flags[4]; /* See ICMPv6_RADV_FLAG_ definitions (must be zero) */ uint8_t opttype; /* Option Type: ICMPv6_OPT_SRCLLADDR */ - uint8_t optlen; /* Option length: 1 octet */ -#ifdef CONFIG_NET_ETHERNET + uint8_t optlen; /* Option length in octets */ uint8_t srclladdr[6]; /* Options: Source link layer address */ -#endif }; +#define SIZEOF_ICMPV6_ROUTER_SOLICIT_S(n) \ + (sizeof(struct icmpv6_router_solicit_s) + ICMPv6_OPT_SIZE(n) - 8) + /* This the message format for the ICMPv6 Router Advertisement message: * Options may include: ICMPv6_OPT_SRCLLADDR, ICMPv6_OPT_MTU, and/or * ICMPv6_OPT_PREFIX @@ -231,7 +242,7 @@ struct icmpv6_router_advertise_s uint16_t lifetime; /* Router lifetime */ uint16_t reachable[2]; /* Reachable time */ uint16_t retrans[2]; /* Retransmission timer */ - uint8_t options[1]; /* Options begin here */ + /* Options begin here */ }; #define ICMPv6_RADV_MINLEN (16) @@ -280,20 +291,20 @@ struct icmpv6_srclladdr_s { uint8_t opttype; /* Octet 1: Option Type: ICMPv6_OPT_SRCLLADDR */ uint8_t optlen; /* " " ": Option length: 1 octet */ -#ifdef CONFIG_NET_ETHERNET uint8_t srclladdr[6]; /* " " ": Options: Source link layer address */ -#endif }; +#define SIZEOF_ICMPV6_SRCLLADDR_S(n) ICMPv6_OPT_SIZE(n) + struct icmpv6_tgrlladdr_s { uint8_t opttype; /* Octet 1: Option Type: ICMPv6_OPT_TGTLLADDR */ - uint8_t optlen; /* " " ": Option length: 1 octet */ -#ifdef CONFIG_NET_ETHERNET + uint8_t optlen; /* " " ": Option length in octets */ uint8_t tgtlladdr[6]; /* " " ": Options: Target link layer address */ -#endif }; +#define SIZEOF_ICMPV6_TGRLLADDR_S(n) ICMPv6_OPT_SIZE(n) + struct icmpv6_prefixinfo_s { uint8_t opttype; /* Octet 1: Option Type: ICMPv6_OPT_PREFIX */ diff --git a/net/icmpv6/icmpv6_advertise.c b/net/icmpv6/icmpv6_advertise.c index 621b8d6c14..75c4615160 100644 --- a/net/icmpv6/icmpv6_advertise.c +++ b/net/icmpv6/icmpv6_advertise.c @@ -2,7 +2,7 @@ * net/icmpv6/icmpv6_advertise.c * Send an ICMPv6 Neighbor Advertisement * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: @@ -96,6 +96,8 @@ void icmpv6_advertise(FAR struct net_driver_s *dev, { FAR struct icmpv6_iphdr_s *icmp = ICMPv6BUF; FAR struct icmpv6_neighbor_advertise_s *adv; + uint16_t l1size; + uint16_t l3size; /* Set up the IPv6 header */ @@ -105,8 +107,10 @@ void icmpv6_advertise(FAR struct net_driver_s *dev, /* Length excludes the IPv6 header */ - icmp->len[0] = (sizeof(struct icmpv6_neighbor_advertise_s) >> 8); - icmp->len[1] = (sizeof(struct icmpv6_neighbor_advertise_s) & 0xff); + l1size = NET_LL_HDRLEN(dev); + l3size = SIZEOF_ICMPV6_NEIGHBOR_ADVERTISE_S(l1size); + icmp->len[0] = (l3size >> 8); + icmp->len[1] = (l3size & 0xff); icmp->proto = IP_PROTO_ICMP6; /* Next header */ icmp->ttl = 255; /* Hop limit */ @@ -133,13 +137,13 @@ void icmpv6_advertise(FAR struct net_driver_s *dev, /* Set up the options */ adv->opttype = ICMPv6_OPT_TGTLLADDR; /* Option type */ - adv->optlen = 1; /* Option length = 1 octet */ + adv->optlen = ICMPv6_OPT_OCTECTS(l1size); /* Option length in octets */ /* Copy our link layer address into the message * REVISIT: What if the link layer is not Ethernet? */ - memcpy(adv->tgtlladdr, &dev->d_mac.ether, IFHWADDRLEN); + memcpy(adv->tgtlladdr, &dev->d_mac, l1size); /* Calculate the checksum over both the ICMP header and payload */ @@ -148,7 +152,7 @@ void icmpv6_advertise(FAR struct net_driver_s *dev, /* Set the size to the size of the IPv6 header and the payload size */ - dev->d_len = IPv6_HDRLEN + sizeof(struct icmpv6_neighbor_advertise_s); + dev->d_len = IPv6_HDRLEN + l3size; #ifdef CONFIG_NET_ETHERNET /* Add the size of the Ethernet header */ diff --git a/net/icmpv6/icmpv6_input.c b/net/icmpv6/icmpv6_input.c index 21f171fbf8..7ced607b59 100644 --- a/net/icmpv6/icmpv6_input.c +++ b/net/icmpv6/icmpv6_input.c @@ -2,7 +2,7 @@ * net/icmpv6/icmpv6_input.c * Handling incoming ICMPv6 input * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: diff --git a/net/icmpv6/icmpv6_radvertise.c b/net/icmpv6/icmpv6_radvertise.c index cec05c51a8..b0765427b9 100644 --- a/net/icmpv6/icmpv6_radvertise.c +++ b/net/icmpv6/icmpv6_radvertise.c @@ -58,31 +58,6 @@ #ifdef CONFIG_NET_ICMPv6_ROUTER -/**************************************************************************** - * Private Types - ****************************************************************************/ -/* This is the same as struct icmpv6_router_advertise_s, but with the - * source address and prefix options included for simplicity. - */ - -struct icmpv6_radvertise_s -{ - uint8_t type; /* Message Type: ICMPV6_ROUTER_ADVERTISE */ - uint8_t code; /* Further qualifies the ICMP messages */ - uint16_t chksum; /* Checksum of ICMP header and data */ - uint8_t hoplimit; /* Current hop limit */ - uint8_t flags; /* See ICMPv6_RADV_FLAG_* definitions */ - uint16_t lifetime; /* Router lifetime */ - uint16_t reachable[2]; /* Reachable time */ - uint16_t retrans[2]; /* Retransmission timer */ - - /* Options */ - - struct icmpv6_srclladdr_s srcaddr; - struct icmpv6_mtu_s mtu; - struct icmpv6_prefixinfo_s prefix; -}; - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -91,7 +66,7 @@ struct icmpv6_radvertise_s #define ICMPv6BUF ((struct icmpv6_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) #define ICMPv6ADVERTISE \ - ((struct icmpv6_radvertise_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN]) + ((struct icmpv6_router_advertise_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN]) /**************************************************************************** * Private Data @@ -134,10 +109,12 @@ static const net_ipv6addr_t g_ipv6_prefix = void icmpv6_radvertise(FAR struct net_driver_s *dev) { FAR struct icmpv6_iphdr_s *icmp = ICMPv6BUF; - FAR struct icmpv6_radvertise_s *adv; + FAR struct icmpv6_router_advertise_s *adv; FAR struct icmpv6_srclladdr_s *srcaddr; FAR struct icmpv6_mtu_s *mtu; FAR struct icmpv6_prefixinfo_s *prefix; + uint16_t l1size; + uint16_t l3size; /* Set up the IPv6 header */ @@ -147,8 +124,14 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev) /* Length excludes the IPv6 header */ - icmp->len[0] = (sizeof(struct icmpv6_radvertise_s) >> 8); - icmp->len[1] = (sizeof(struct icmpv6_radvertise_s) & 0xff); + l1size = NET_LL_HDRLEN(dev); + l3size = sizeof(icmpv6_router_advertise_s) + + SIZEOF_ICMPV6_SRCLLADDR_S(l1size) + + sizeof(struct icmpv6_mtu_s) + + sizeof(icmpv6_prefixinfo_s); + + icmp->len[0] = (l3size >> 8); + icmp->len[1] = (l3size & 0xff); icmp->proto = IP_PROTO_ICMP6; /* Next header */ icmp->ttl = 255; /* Hop limit */ @@ -173,13 +156,16 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev) /* Set up the source address option */ - srcaddr = &adv->srcaddr; + srcaddr = (FAR struct icmpv6_srclladdr_s *) + ((FAR uint8_t *)adv + sizeof(icmpv6_router_advertise_s)); srcaddr->opttype = ICMPv6_OPT_SRCLLADDR; - srcaddr->optlen = 1; - memcpy(srcaddr->srclladdr, &dev->d_mac.ether.ether_addr_octet, ETHER_ADDR_LEN); + srcaddr->optlen = ICMPv6_OPT_OCTECTS(l1size); + memcpy(srcaddr->srclladdr, &dev->d_mac, l1size); /* Set up the MTU option */ + mtu = (FAR struct icmpv6_mtu_s *) + ((FAR uint8_t *)srcaddr + SIZEOF_ICMPV6_SRCLLADDR_S(l1size)); mtu = &adv->mtu; mtu->opttype = ICMPv6_OPT_MTU; mtu->optlen = 1; @@ -189,6 +175,8 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev) /* Set up the prefix option */ + prefix = (FAR struct icmpv6_prefixinfo_s *) + ((FAR uint8_t *)mtu + sizeof(icmpv6_mtu_s)); prefix = &adv->prefix; prefix->opttype = ICMPv6_OPT_MTU; prefix->optlen = 4; @@ -210,7 +198,7 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev) /* Set the size to the size of the IPv6 header and the payload size */ - dev->d_len = IPv6_HDRLEN + sizeof(struct icmpv6_radvertise_s); + dev->d_len = IPv6_HDRLEN + sizeof(struct icmpv6_router_advertise_s); #ifdef CONFIG_NET_ETHERNET /* Add the size of the Ethernet header */ diff --git a/net/icmpv6/icmpv6_rsolicit.c b/net/icmpv6/icmpv6_rsolicit.c index 93a2631432..723ed6c1cd 100644 --- a/net/icmpv6/icmpv6_rsolicit.c +++ b/net/icmpv6/icmpv6_rsolicit.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/icmpv6/icmpv6_rsolicit.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -92,6 +92,8 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev) FAR struct icmpv6_iphdr_s *icmp; FAR struct icmpv6_router_solicit_s *sol; FAR struct eth_hdr_s *eth; + uint16_t l1size; + uint16_t l3size; /* Set up the IPv6 header (most is probably already in place) */ @@ -102,8 +104,10 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev) /* Length excludes the IPv6 header */ - icmp->len[0] = (sizeof(struct icmpv6_router_solicit_s) >> 8); - icmp->len[1] = (sizeof(struct icmpv6_router_solicit_s) & 0xff); + l1size = NET_LL_HDRLEN(dev); + l3size = SIZEOF_ICMPV6_ROUTER_SOLICIT_S(l1size); + icmp->len[0] = (l3size >> 8); + icmp->len[1] = (l3size & 0xff); icmp->proto = IP_PROTO_ICMP6; /* Next header */ icmp->ttl = 255; /* Hop limit */ @@ -130,14 +134,14 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev) /* Set up the options */ - sol->opttype = ICMPv6_OPT_SRCLLADDR; /* Option type */ - sol->optlen = 1; /* Option length = 1 octet */ + sol->opttype = ICMPv6_OPT_SRCLLADDR; /* Option type */ + sol->optlen = ICMPv6_OPT_OCTECTS(l1size); /* Option length in octets */ /* Copy our link layer address into the message * REVISIT: What if the link layer is not Ethernet? */ - memcpy(sol->srclladdr, dev->d_mac.ether.ether_addr_octet, sizeof(net_ipv6addr_t)); + memcpy(sol->srclladdr, &dev->d_mac, l1size); /* Calculate the checksum over both the ICMP header and payload */ @@ -146,7 +150,7 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev) /* Set the size to the size of the IPv6 header and the payload size */ - dev->d_len = IPv6_HDRLEN + sizeof(struct icmpv6_router_solicit_s); + dev->d_len = IPv6_HDRLEN + l3size; #ifdef CONFIG_NET_ETHERNET #ifdef CONFIG_NET_MULTILINK @@ -182,6 +186,7 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev) /* Add the size of the layer layer header to the total size of the * outgoing packet. */ + dev->d_len += netdev_ipv6_hdrlen(dev); ninfo("Outgoing ICMPv6 Router Solicitation length: %d (%d)\n", dev->d_len, (icmp->len[0] << 8) | icmp->len[1]); diff --git a/net/icmpv6/icmpv6_solicit.c b/net/icmpv6/icmpv6_solicit.c index 5eae392c52..71879609c9 100644 --- a/net/icmpv6/icmpv6_solicit.c +++ b/net/icmpv6/icmpv6_solicit.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/icmpv6/icmpv6_solicit.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -102,7 +102,8 @@ void icmpv6_solicit(FAR struct net_driver_s *dev, { FAR struct icmpv6_iphdr_s *icmp; FAR struct icmpv6_neighbor_solicit_s *sol; - FAR struct eth_hdr_s *eth; + uint16_t l1size; + uint16_t l3size; /* Set up the IPv6 header (most is probably already in place) */ @@ -113,8 +114,10 @@ void icmpv6_solicit(FAR struct net_driver_s *dev, /* Length excludes the IPv6 header */ - icmp->len[0] = (sizeof(struct icmpv6_neighbor_solicit_s) >> 8); - icmp->len[1] = (sizeof(struct icmpv6_neighbor_solicit_s) & 0xff); + l1size = NET_LL_HDRLEN(dev); + l3size = SIZEOF_ICMPV6_NEIGHBOR_SOLICIT_S(l1size); + icmp->len[0] = (l3size >> 8); + icmp->len[1] = (l3size & 0xff); icmp->proto = IP_PROTO_ICMP6; /* Next header */ icmp->ttl = 255; /* Hop limit */ @@ -145,14 +148,14 @@ void icmpv6_solicit(FAR struct net_driver_s *dev, /* Set up the options */ - sol->opttype = ICMPv6_OPT_SRCLLADDR; /* Option type */ - sol->optlen = 1; /* Option length = 1 octet */ + sol->opttype = ICMPv6_OPT_SRCLLADDR; /* Option type */ + sol->optlen = ICMPv6_OPT_OCTECTS(l1size); /* Option length in octets */ /* Copy our link layer address into the message * REVISIT: What if the link layer is not Ethernet? */ - memcpy(sol->srclladdr, &dev->d_mac.ether, IFHWADDRLEN); + memcpy(sol->srclladdr, &dev->d_mac, l1size); /* Calculate the checksum over both the ICMP header and payload */ @@ -161,13 +164,15 @@ void icmpv6_solicit(FAR struct net_driver_s *dev, /* Set the size to the size of the IPv6 header and the payload size */ - dev->d_len = IPv6_HDRLEN + sizeof(struct icmpv6_neighbor_solicit_s); + dev->d_len = IPv6_HDRLEN + l3size; #ifdef CONFIG_NET_ETHERNET #ifdef CONFIG_NET_MULTILINK if (dev->d_lltype == NET_LL_ETHERNET) #endif { + FAR struct eth_hdr_s *eth; + /* Set the destination IPv6 multicast Ethernet address: * * For IPv6 multicast addresses, the Ethernet MAC is derived by diff --git a/net/neighbor/neighbor.h b/net/neighbor/neighbor.h index a8317f6d36..378b6fa211 100644 --- a/net/neighbor/neighbor.h +++ b/net/neighbor/neighbor.h @@ -67,6 +67,7 @@ /**************************************************************************** * Public Types ****************************************************************************/ + /* Describes the link layer address */ struct neighbor_addr_s