From c5ed77120feb5530227338db4907024e26271e41 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 4 Feb 2015 15:43:54 -0600 Subject: [PATCH] ICMPv6: Separate out Neighbor Advertise message so that we can reuse it --- net/icmpv6/Make.defs | 2 +- net/icmpv6/icmpv6.h | 21 ++++ net/icmpv6/icmpv6_advertise.c | 192 ++++++++++++++++++++++++++++++++++ net/icmpv6/icmpv6_input.c | 95 ++--------------- 4 files changed, 222 insertions(+), 88 deletions(-) create mode 100644 net/icmpv6/icmpv6_advertise.c diff --git a/net/icmpv6/Make.defs b/net/icmpv6/Make.defs index 0eb0fe1ca9..4e788d0eb1 100644 --- a/net/icmpv6/Make.defs +++ b/net/icmpv6/Make.defs @@ -37,7 +37,7 @@ ifeq ($(CONFIG_NET_ICMPv6),y) # ICMPv6 source files -NET_CSRCS += icmpv6_input.c icmpv6_solicit.c +NET_CSRCS += icmpv6_input.c icmpv6_solicit.c icmpv6_advertise.c ifeq ($(CONFIG_NET_ICMPv6_PING),y) NET_CSRCS += icmpv6_ping.c diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h index 67a6be6241..554aa5aa05 100644 --- a/net/icmpv6/icmpv6.h +++ b/net/icmpv6/icmpv6.h @@ -252,6 +252,27 @@ void icmpv6_solicit(FAR struct net_driver_s *dev, void icmpv6_rsolicit(FAR struct net_driver_s *dev); #endif +/**************************************************************************** + * Name: icmpv6_advertise + * + * Description: + * Send an ICMPv6 Neighbor Advertisement + * + * Parameters: + * dev - The device driver structure containing the outgoing ICMPv6 packet + * buffer + * + * Return: + * Zero (OK) on success; A negated errno value on return. + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +int icmpv6_advertise(FAR struct net_driver_s *dev, + const net_ipv6addr_t destipaddr); + /**************************************************************************** * Function: icmpv6_wait_setup * diff --git a/net/icmpv6/icmpv6_advertise.c b/net/icmpv6/icmpv6_advertise.c new file mode 100644 index 0000000000..62edf78f34 --- /dev/null +++ b/net/icmpv6/icmpv6_advertise.c @@ -0,0 +1,192 @@ +/**************************************************************************** + * net/icmpv6/icmpv6_advertise.c + * Send an ICMPv6 Neighbor Advertisement + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Adapted for NuttX from logic in uIP which also has a BSD-like license: + * + * Original author Adam Dunkels + * Copyright () 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "utils/utils.h" +#include "icmpv6/icmpv6.h" + +#ifdef CONFIG_NET_ICMPv6 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ETHBUF ((struct eth_hdr_s *)&dev->d_buf[0]) +#define ICMPv6BUF ((struct icmpv6_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) + +#define ICMPv6ADVERTISE \ + ((struct icmpv6_neighbor_advertise_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN]) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: icmpv6_advertise + * + * Description: + * Send an ICMPv6 Neighbor Advertisement + * + * Parameters: + * dev - The device driver structure containing the outgoing ICMPv6 packet + * buffer + * + * Return: + * Zero (OK) on success; A negated errno value on return. + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +int icmpv6_advertise(FAR struct net_driver_s *dev, + const net_ipv6addr_t destipaddr) +{ + FAR struct icmpv6_iphdr_s *icmp = ICMPv6BUF; + FAR struct icmpv6_neighbor_advertise_s *adv; + + /* Set up the IPv6 header */ + + icmp->vtc = 0x60; /* Version/traffic class (MS) */ + icmp->tcf = 0; /* Traffic class (LS)/Flow label (MS) */ + icmp->flow = 0; /* Flow label (LS) */ + + /* 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); + + icmp->proto = IP_PROTO_ICMP6; /* Next header */ + icmp->ttl = 255; /* Hop limit */ + + /* Swap source for destination IP address, add our source IP address */ + + net_ipv6addr_copy(icmp->destipaddr, destipaddr); + net_ipv6addr_copy(icmp->srcipaddr, dev->d_ipv6addr); + + /* Set up the ICMPv6 Neighbor Advertise response */ + + adv = ICMPv6ADVERTISE; + adv->type = ICMPv6_NEIGHBOR_ADVERTISE; /* Message type */ + adv->code = 0; /* Message qualifier */ + adv->flags[0] = ICMPv6_NADV_FLAG_S | ICMPv6_NADV_FLAG_O; /* Solicited+Override flags. */ + adv->flags[1] = 0; + adv->flags[2] = 0; + adv->flags[3] = 0; + + /* Copy the target address into the Neighbor Advertisement message */ + + net_ipv6addr_copy(adv->tgtaddr, dev->d_ipv6addr); + + /* Set up the options */ + + adv->opttype = ICMPv6_OPT_TGTLLADDR; /* Option type */ + adv->optlen = 1; /* Option length = 1 octet */ + + /* Copy our link layer address into the message + * REVISIT: What if the link layer is not Ethernet? + */ + + memcpy(adv->tgtlladdr, &dev->d_mac, IFHWADDRLEN); + + /* Calculate the checksum over both the ICMP header and payload */ + + icmp->chksum = 0; + icmp->chksum = ~icmpv6_chksum(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); + +#ifdef CONFIG_NET_ETHERNET + /* Add the size of the Ethernet header */ + + dev->d_len += ETH_HDRLEN; + + /* Move the source and to the destination addresses in the Ethernet header + * and use our MAC as the new source address + */ + +#ifdef CONFIG_NET_MULTILINK + if (dev->d_lltype == NET_LL_ETHERNET) +#endif + { + FAR struct eth_hdr_s *eth = ETHBUF; + + memcpy(eth->dest, eth->src, ETHER_ADDR_LEN); + memcpy(eth->src, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN); + + /* Set the IPv6 Ethernet type */ + + eth->type = HTONS(ETHTYPE_IP6); + } +#endif + + /* No additional neighbor lookup is required on this packet (We are using + * a multicast address). + */ + + IFF_SET_NOARP(dev->d_flags); + + nllvdbg("Outgoing ICMPv6 Neighbor Advertise length: %d (%d)\n", + dev->d_len, (icmp->len[0] << 8) | icmp->len[1]); + +#ifdef CONFIG_NET_STATISTICS + g_netstats.icmpv6.sent++; + g_netstats.ipv6.sent++; +#endif + return OK; +} + +#endif /* CONFIG_NET_ICMPv6 */ diff --git a/net/icmpv6/icmpv6_input.c b/net/icmpv6/icmpv6_input.c index b834bb9c9e..5842e128eb 100644 --- a/net/icmpv6/icmpv6_input.c +++ b/net/icmpv6/icmpv6_input.c @@ -48,17 +48,14 @@ #include #include -#include -#include - #include #include #include -#include +#include #include "devif/devif.h" -#include "utils/utils.h" #include "neighbor/neighbor.h" +#include "utils/utils.h" #include "icmpv6/icmpv6.h" #ifdef CONFIG_NET_ICMPv6 @@ -112,6 +109,7 @@ struct icmpv6_conn_s g_icmpv6_conn; void icmpv6_input(FAR struct net_driver_s *dev) { FAR struct icmpv6_iphdr_s *icmp = ICMPv6BUF; + int ret; #ifdef CONFIG_NET_STATISTICS g_netstats.icmpv6.recv++; @@ -128,7 +126,6 @@ void icmpv6_input(FAR struct net_driver_s *dev) case ICMPv6_NEIGHBOR_SOLICIT: { FAR struct icmpv6_neighbor_solicit_s *sol; - FAR struct icmpv6_neighbor_advertise_s *adv; /* Check if we are the target of the solicitation */ @@ -137,93 +134,17 @@ void icmpv6_input(FAR struct net_driver_s *dev) { /* Yes.. Send a neighbor advertisement back to where the neighbor * solicitation came from. - * - * Set up the IPv6 header. Most is probably already in place from - * the Neighbor Solicitation. We could save some time here. */ - icmp->vtc = 0x60; /* Version/traffic class (MS) */ - icmp->tcf = 0; /* Traffic class (LS)/Flow label (MS) */ - icmp->flow = 0; /* Flow label (LS) */ - - /* 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); - - icmp->proto = IP_PROTO_ICMP6; /* Next header */ - icmp->ttl = 255; /* Hop limit */ - - /* Swap source for destination IP address, add our source IP - * address - */ - - net_ipv6addr_copy(icmp->destipaddr, icmp->srcipaddr); - net_ipv6addr_copy(icmp->srcipaddr, dev->d_ipv6addr); - - /* Set up the ICMPv6 Neighbor Advertise response */ - - adv = ICMPv6ADVERTISE; - adv->type = ICMPv6_NEIGHBOR_ADVERTISE; /* Message type */ - adv->code = 0; /* Message qualifier */ - adv->flags[0] = ICMPv6_NADV_FLAG_S | ICMPv6_NADV_FLAG_O; /* Solicited+Override flags. */ - adv->flags[1] = 0; - adv->flags[2] = 0; - adv->flags[3] = 0; - - /* Copy the target address into the Neighbor Advertisement message */ - - net_ipv6addr_copy(adv->tgtaddr, dev->d_ipv6addr); - - /* Set up the options */ - - adv->opttype = ICMPv6_OPT_TGTLLADDR; /* Option type */ - adv->optlen = 1; /* Option length = 1 octet */ - - /* Copy our link layer address into the message - * REVISIT: What if the link layer is not Ethernet? - */ - - memcpy(adv->tgtlladdr, &dev->d_mac, IFHWADDRLEN); - - /* Calculate the checksum over both the ICMP header and payload */ - - icmp->chksum = 0; - icmp->chksum = ~icmpv6_chksum(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); - -#ifdef CONFIG_NET_ETHERNET - /* Add the size of the Ethernet header */ - - dev->d_len += ETH_HDRLEN; - - /* Move the source and to the destination addresses in the - * Ethernet header and use our MAC as the new source address. - */ - -#ifdef CONFIG_NET_MULTILINK - if (dev->d_lltype == NET_LL_ETHERNET) -#endif + ret = icmpv6_advertise(dev, icmp->srcipaddr); + if (ret < 0) { - FAR struct eth_hdr_s *eth = ETHBUF; - - memcpy(eth->dest, eth->src, ETHER_ADDR_LEN); - memcpy(eth->src, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN); - - /* Set the IPv6 Ethernet type */ - - eth->type = HTONS(ETHTYPE_IP6); + goto icmpv6_drop_packet; } -#endif - /* No additional neighbor lookup is required on this packet - * (We are using a multicast address). - */ + /* All statistics have been updated */ - IFF_SET_NOARP(dev->d_flags); + return; } else {