summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2015-01-20 14:37:02 -0600
committerGregory Nutt <gnutt@nuttx.org>2015-01-20 14:37:02 -0600
commit9349fcdfc5acae9361c7ef1fa57e831429187e52 (patch)
tree3207b5b78b98ddf46684b7d8555fe45a52100cff
parent6b1909e4fe37e0f4b7e9dc79a5cb152100f5de34 (diff)
downloadnuttx-9349fcdfc5acae9361c7ef1fa57e831429187e52.tar.gz
nuttx-9349fcdfc5acae9361c7ef1fa57e831429187e52.tar.bz2
nuttx-9349fcdfc5acae9361c7ef1fa57e831429187e52.zip
Networking: Add logic to search the Neighbor Table and update the destination address in the output Ethernet header OR to send an ICMPv6 Neighbor Solicitation if there is no entry in the Neighbor table for the IPv6 address
-rw-r--r--nuttx/include/nuttx/net/arp.h14
-rw-r--r--nuttx/include/nuttx/net/netdev.h34
-rw-r--r--nuttx/net/icmpv6/Make.defs2
-rw-r--r--nuttx/net/icmpv6/icmpv6.h70
-rw-r--r--nuttx/net/icmpv6/icmpv6_solicit.c195
-rw-r--r--nuttx/net/neighbor/Make.defs1
-rw-r--r--nuttx/net/neighbor/neighbor_lookup.c6
-rw-r--r--nuttx/net/neighbor/neighbor_out.c245
8 files changed, 552 insertions, 15 deletions
diff --git a/nuttx/include/nuttx/net/arp.h b/nuttx/include/nuttx/net/arp.h
index 09678594a..e9f58b507 100644
--- a/nuttx/include/nuttx/net/arp.h
+++ b/nuttx/include/nuttx/net/arp.h
@@ -161,20 +161,20 @@ void arp_arpin(struct net_driver_s *dev);
* Name: arp_out
*
* Description:
- * This function should be called before sending out an IP packet. The
- * function checks the destination IP address of the IP packet to see
+ * This function should be called before sending out an IPv4 packet. The
+ * function checks the destination IPv4 address of the IPv4 packet to see
* what Ethernet MAC address that should be used as a destination MAC
* address on the Ethernet.
*
- * If the destination IP address is in the local network (determined
- * by logical ANDing of netmask and our IP address), the function
- * checks the ARP cache to see if an entry for the destination IP
+ * If the destination IPv4 address is in the local network (determined
+ * by logical ANDing of netmask and our IPv4 address), the function
+ * checks the ARP cache to see if an entry for the destination IPv4
* address is found. If so, an Ethernet header is pre-pended at the
* beginning of the packet and the function returns.
*
- * If no ARP cache entry is found for the destination IP address, the
+ * If no ARP cache entry is found for the destination IIPv4P address, the
* packet in the d_buf[] is replaced by an ARP request packet for the
- * IP address. The IP packet is dropped and it is assumed that the
+ * IPv4 address. The IPv4 packet is dropped and it is assumed that the
* higher level protocols (e.g., TCP) eventually will retransmit the
* dropped packet.
*
diff --git a/nuttx/include/nuttx/net/netdev.h b/nuttx/include/nuttx/net/netdev.h
index b6953c819..a759eac4d 100644
--- a/nuttx/include/nuttx/net/netdev.h
+++ b/nuttx/include/nuttx/net/netdev.h
@@ -344,7 +344,39 @@ int ipv6_input(FAR struct net_driver_s *dev);
****************************************************************************/
int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback);
-int devif_timer(FAR struct net_driver_s *dev, devif_poll_callback_t callback, int hsec);
+int devif_timer(FAR struct net_driver_s *dev, devif_poll_callback_t callback,
+ int hsec);
+
+/****************************************************************************
+ * Name: neighbor_out
+ *
+ * Description:
+ * This function should be called before sending out an IPv6 packet. The
+ * function checks the destination IPv6 address of the IPv6 packet to see
+ * what Ethernet MAC address that should be used as a destination MAC
+ * address on the Ethernet.
+ *
+ * If the destination IPv6 address is in the local network (determined
+ * by logical ANDing of netmask and our IPv6 address), the function
+ * checks the Neighbor Table to see if an entry for the destination IPv6
+ * address is found. If so, an Ethernet header is pre-pended at the
+ * beginning of the packet and the function returns.
+ *
+ * If no Neighbor Table entry is found for the destination IPv6 address,
+ * the packet in the d_buf[] is replaced by an ICMPv6 Neighbor Solict
+ * request packet for the IPv6 address. The IPv6 packet is dropped and
+ * it is assumed that the higher level protocols (e.g., TCP) eventually
+ * will retransmit the dropped packet.
+ *
+ * Upon return in either the case, a packet to be sent is present in the
+ * d_buf[] buffer and the d_len field holds the length of the Ethernet
+ * frame that should be transmitted.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+void neighbor_out(FAR struct net_driver_s *dev);
+#endif /* CONFIG_NET_IPv6 */
/****************************************************************************
* Carrier detection
diff --git a/nuttx/net/icmpv6/Make.defs b/nuttx/net/icmpv6/Make.defs
index 93c49558e..e25d5706a 100644
--- a/nuttx/net/icmpv6/Make.defs
+++ b/nuttx/net/icmpv6/Make.defs
@@ -37,7 +37,7 @@ ifeq ($(CONFIG_NET_ICMPv6),y)
# ICMPv6 source files
-NET_CSRCS += icmpv6_input.c
+NET_CSRCS += icmpv6_input.c icmpv6_solicit.c
ifeq ($(CONFIG_NET_ICMPv6_PING),y)
NET_CSRCS += icmpv6_ping.c icmpv6_poll.c icmpv6_send.c
diff --git a/nuttx/net/icmpv6/icmpv6.h b/nuttx/net/icmpv6/icmpv6.h
index c5740e8f0..082374023 100644
--- a/nuttx/net/icmpv6/icmpv6.h
+++ b/nuttx/net/icmpv6/icmpv6.h
@@ -72,22 +72,86 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
-/* Defined in icmpv6_input.c ************************************************/
+/****************************************************************************
+ * Name: icmpv6_input
+ *
+ * Description:
+ * Handle incoming ICMPv6 input
+ *
+ * Parameters:
+ * dev - The device driver structure containing the received ICMPv6
+ * packet
+ *
+ * Return:
+ * None
+ *
+ * Assumptions:
+ * Called from the interrupt level or with interrupts disabled.
+ *
+ ****************************************************************************/
void icmpv6_input(FAR struct net_driver_s *dev);
-/* Defined in icmpv6_poll.c *************************************************/
+/****************************************************************************
+ * Name: icmpv6_poll
+ *
+ * Description:
+ * Poll a UDP "connection" structure for availability of TX data
+ *
+ * Parameters:
+ * dev - The device driver structure to use in the send operation
+ *
+ * Return:
+ * None
+ *
+ * Assumptions:
+ * Called from the interrupt level or with interrupts disabled.
+ *
+ ****************************************************************************/
#ifdef CONFIG_NET_ICMPv6_PING
void icmpv6_poll(FAR struct net_driver_s *dev);
#endif /* CONFIG_NET_ICMPv6_PING */
-/* Defined in icmpv6_send.c *************************************************/
+/****************************************************************************
+ * Name: icmpv6_send
+ *
+ * Description:
+ * Setup to send an ICMPv6 packet
+ *
+ * Parameters:
+ * dev - The device driver structure to use in the send operation
+ *
+ * Return:
+ * None
+ *
+ * Assumptions:
+ * Called from the interrupt level or with interrupts disabled.
+ *
+ ****************************************************************************/
#ifdef CONFIG_NET_ICMPv6_PING
void icmpv6_send(FAR struct net_driver_s *dev, FAR net_ipv6addr_t *destaddr);
#endif /* CONFIG_NET_ICMPv6_PING */
+/****************************************************************************
+ * Name: icmpv6_solicit
+ *
+ * Description:
+ * Set up to send an ICMPv6 Neighbor Solicitation message
+ *
+ * Parameters:
+ * dev - Reference to an Ethernet device driver structure
+ * ipaddr - IP address of Neighbor to be solicited
+ *
+ * Return:
+ * None
+ *
+ ****************************************************************************/
+
+void icmpv6_solicit(FAR struct net_driver_s *dev,
+ FAR const net_ipv6addr_t ipaddr);
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/nuttx/net/icmpv6/icmpv6_solicit.c b/nuttx/net/icmpv6/icmpv6_solicit.c
new file mode 100644
index 000000000..c0732c922
--- /dev/null
+++ b/nuttx/net/icmpv6/icmpv6_solicit.c
@@ -0,0 +1,195 @@
+/****************************************************************************
+ * net/icmpv6/icmpv6_solicit.c
+ *
+ * Copyright (C) 2015 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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
+ * COPYRIGHT OWNER OR CONTRIBUTORS 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 <nuttx/config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <debug.h>
+
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/netstats.h>
+
+#include "devif/devif.h"
+#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 ICMPv6SOLICIT \
+ ((struct icmpv6_neighbor_solicit_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const uint16_t g_icmpv_mcastaddr[6] =
+{
+ 0xff02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: icmpv6_solicit
+ *
+ * Description:
+ * Set up to send an ICMPv6 Neighbor Solicitation message
+ *
+ * Parameters:
+ * dev - Reference to an Ethernet device driver structure
+ * ipaddr - IP address of Neighbor to be solicited
+ *
+ * Return:
+ * None
+ *
+ ****************************************************************************/
+
+void icmpv6_solicit(FAR struct net_driver_s *dev,
+ FAR const net_ipv6addr_t ipaddr)
+{
+ FAR struct icmpv6_iphdr_s *icmp;
+ FAR struct icmpv6_neighbor_solicit_s *sol;
+ FAR struct eth_hdr_s *eth;
+
+ /* Set up the IPv6 header (most is probably already in place) */
+
+ icmp = ICMPv6BUF;
+ 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_solicit_s) >> 8);
+ icmp->len[1] = (sizeof(struct icmpv6_neighbor_solicit_s) & 0xff);
+
+ icmp->proto = IP_PROTO_ICMP6; /* Next header */
+ icmp->ttl = IP_TTL; /* Hop limit */
+
+ /* Set the multicast destination IP address */
+
+ memcpy(icmp->destipaddr, g_icmpv_mcastaddr, 6*sizeof(uint16_t));
+ icmp->destipaddr[6] = ipaddr[6] | 0xff00;
+ icmp->destipaddr[7] = ipaddr[7];
+
+ /* Add out IPv6 address as the source address */
+
+ net_ipv6addr_copy(icmp->srcipaddr, dev->d_ipv6addr);
+
+ /* Set up the ICMPv6 Neighbor Solicitation message */
+
+ sol = ICMPv6SOLICIT;
+ sol->type = ICMPv6_NEIGHBOR_SOLICIT; /* Message type */
+ sol->code = 0; /* Message qualifier */
+ sol->flags[0] = 0; /* flags */
+ sol->flags[1] = 0;
+ sol->flags[2] = 0;
+ sol->flags[3] = 0;
+ sol->opttype = ICMPv6_OPT_SRCLLADDR; /* Option type */
+ sol->optlen = 1; /* Option length = 1 octet */
+
+ /* Copy our link layer address into the message
+ * REVISIT: What if the link layer is not Ethernet?
+ */
+
+ memcpy(&(sol->srclladdr), &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_solicit_s);
+
+#ifdef CONFIG_NET_ETHERNET
+#ifdef CONFIG_NET_MULTILINK
+ if (dev->d_lltype == NET_LL_ETHERNET)
+#endif
+ {
+ /* Add the size of the Ethernet header */
+
+ dev->d_len += ETH_HDRLEN;
+
+ /* Set the destination IPv6 multicast Ethernet address:
+ *
+ * For IPv6 multicast addresses, the Ethernet MAC is derived by
+ * the four low-order octets OR'ed with the MAC 33:33:00:00:00:00,
+ * so for example the IPv6 address FF02:DEAD:BEEF::1:3 would map
+ * to the Ethernet MAC address 33:33:00:01:00:03.
+ *
+ * NOTES: This appears correct for the ICMPv6 Router Solicitation
+ * Message, but the ICMPv6 Neighbor Solicitation message seems to
+ * use 33:33:ff:01:00:03.
+ */
+
+ eth = ETHBUF;
+ eth->dest[0] = 0x33;
+ eth->dest[1] = 0x33;
+ eth->dest[2] = 0xff;
+ eth->dest[3] = ipaddr[6] >> 8;
+ eth->dest[4] = ipaddr[7] & 0xff;
+ eth->dest[5] = ipaddr[7] >> 8;
+
+ /* Move our source Ethernet addresses into the Ethernet header */
+
+ memcpy(eth->src, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN);
+ }
+#endif
+
+ nllvdbg("Outgoing ICMPv6 Neighbor Solicitation length: %d (%d)\n",
+ dev->d_len, (icmp->len[0] << 8) | icmp->len[1]);
+
+#ifdef CONFIG_NET_STATISTICS
+ g_netstats.icmpv6.sent++;
+ g_netstats.ip.sent++;
+#endif
+}
+
+#endif /* CONFIG_NET_ICMPv6 */
diff --git a/nuttx/net/neighbor/Make.defs b/nuttx/net/neighbor/Make.defs
index 19cbb13e1..cf13cbb73 100644
--- a/nuttx/net/neighbor/Make.defs
+++ b/nuttx/net/neighbor/Make.defs
@@ -39,6 +39,7 @@ ifeq ($(CONFIG_NET_IPv6),y)
NET_CSRCS += neighbor_initialize.c neighbor_add.c neighbor_lookup.c
NET_CSRCS += neighbor_update.c neighbor_periodic.c neighbor_findentry.c
+NET_CSRCS += neighbor_out.c
# Include utility build support
diff --git a/nuttx/net/neighbor/neighbor_lookup.c b/nuttx/net/neighbor/neighbor_lookup.c
index 4c7d9b04a..dc42e54e1 100644
--- a/nuttx/net/neighbor/neighbor_lookup.c
+++ b/nuttx/net/neighbor/neighbor_lookup.c
@@ -61,11 +61,11 @@
*
* Input Parameters:
* ipaddr - The IPv6 address to use in the lookup;
+ * lladdr - The location to return the link layer address
*
* Returned Value:
- * A read-only reference to the link layer address in the Neighbor Table is
- * returned on success. NULL is returned if there is no matching entry in
- * the Neighbor Table.
+ * Returns OK if the address was successfully obtain; a negated errno
+ * value is returned on failure.
*
****************************************************************************/
diff --git a/nuttx/net/neighbor/neighbor_out.c b/nuttx/net/neighbor/neighbor_out.c
new file mode 100644
index 000000000..94cad10d2
--- /dev/null
+++ b/nuttx/net/neighbor/neighbor_out.c
@@ -0,0 +1,245 @@
+/****************************************************************************
+ * net/neighbor/neighbor_out.c
+ *
+ * Copyright (C) 2015 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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
+ * COPYRIGHT OWNER OR CONTRIBUTORS 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 <nuttx/config.h>
+
+#include <string.h>
+#include <debug.h>
+
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+
+#include "route/route.h"
+#include "icmpv6/icmpv6.h"
+#include "neighbor/neighbor.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ETHBUF ((struct eth_hdr_s *)dev->d_buf)
+#define IPv6BUF ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Support for broadcast address */
+
+static const struct ether_addr g_broadcast_ethaddr =
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
+
+/* Support for IGMP multicast addresses.
+ *
+ * Well-known ethernet multicast address:
+ *
+ * ADDRESS TYPE USAGE
+ * 01-00-0c-cc-cc-cc 0x0802 CDP (Cisco Discovery Protocol), VTP (Virtual Trunking Protocol)
+ * 01-00-0c-cc-cc-cd 0x0802 Cisco Shared Spanning Tree Protocol Address
+ * 01-80-c2-00-00-00 0x0802 Spanning Tree Protocol (for bridges) IEEE 802.1D
+ * 01-80-c2-00-00-02 0x0809 Ethernet OAM Protocol IEEE 802.3ah
+ * 01-00-5e-xx-xx-xx 0x0800 IPv4 IGMP Multicast Address
+ * 33-33-00-00-00-00 0x86DD IPv6 Neighbor Discovery
+ * 33-33-xx-xx-xx-xx 0x86DD IPv6 Multicast Address (RFC3307)
+ *
+ * The following is the first three octects of the IGMP address:
+ */
+
+#ifdef CONFIG_NET_IGMP
+static const uint8_t g_multicast_ethaddr[3] = {0x01, 0x00, 0x5e};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: neighbor_out
+ *
+ * Description:
+ * This function should be called before sending out an IPv6 packet. The
+ * function checks the destination IPv6 address of the IPv6 packet to see
+ * what Ethernet MAC address that should be used as a destination MAC
+ * address on the Ethernet.
+ *
+ * If the destination IPv6 address is in the local network (determined
+ * by logical ANDing of netmask and our IPv6 address), the function
+ * checks the Neighbor Table to see if an entry for the destination IPv6
+ * address is found. If so, an Ethernet header is pre-pended at the
+ * beginning of the packet and the function returns.
+ *
+ * If no Neighbor Table entry is found for the destination IPv6 address,
+ * the packet in the d_buf[] is replaced by an ICMPv6 Neighbor Solict
+ * request packet for the IPv6 address. The IPv6 packet is dropped and
+ * it is assumed that the higher level protocols (e.g., TCP) eventually
+ * will retransmit the dropped packet.
+ *
+ * Upon return in either the case, a packet to be sent is present in the
+ * d_buf[] buffer and the d_len field holds the length of the Ethernet
+ * frame that should be transmitted.
+ *
+ ****************************************************************************/
+
+void neighbor_out(FAR struct net_driver_s *dev)
+{
+ FAR const struct neighbor_addr_s *naddr;
+ FAR struct eth_hdr_s *eth = ETHBUF;
+ FAR struct ipv6_hdr_s *ip = IPv6BUF;
+ net_ipv6addr_t ipaddr;
+
+#if defined(CONFIG_NET_PKT) || defined(CONFIG_NET_NEIGHBOR_SEND)
+ /* Skip sending ARP requests when the frame to be transmitted was
+ * written into a packet socket.
+ */
+
+ if ((dev->d_flags & IFF_NOARP) != 0)
+ {
+ /* Clear the indication and let the packet continue on its way. */
+
+ dev->d_flags &= ~IFF_NOARP;
+ return;
+ }
+#endif
+
+ /* Find the destination IPv6 address in the ARP table and construct
+ * the Ethernet header. If the destination IPv6 address isn't on the
+ * local network, we use the default router's IPv6 address instead.
+ *
+ * If not ARP table entry is found, we overwrite the original IPv6
+ * packet with an ARP request for the IPv6 address.
+ */
+
+ /* First check if destination is a IPv6 multicast address. IPv6
+ * multicast addresses in IPv6 have the prefix ff00::/8
+ *
+ * Bits 120-127: Prefix
+ * Bits 116-119: Flags (1, 2, or 3 defined)
+ * Bits 112-115: Scope
+ *
+ * REVISIT: Need to revisit IPv6 broadcast support. Broadcast
+ * IP addresses are not used with IPv6; multicast is used instead.
+ * Does this mean that all multicast address should go to the
+ * broadcast Ethernet address?
+ */
+
+ if ((ip->destipaddr[0] & 0xff00) == 0xff00)
+ {
+ memcpy(eth->dest, g_broadcast_ethaddr.ether_addr_octet,
+ ETHER_ADDR_LEN);
+ }
+
+#ifdef CONFIG_NET_IGMP
+ /* Check if the destination address is a multicast address
+ *
+ * IPv6 multicast addresses are have the high-order octet of the
+ * addresses=0xff (ff00::/8.)
+ *
+ * REVISIT: See comments above. How do we distinguish broadcast
+ * from IGMP multicast?
+ */
+#warning Missing logic
+#endif
+
+ else
+ {
+ /* Check if the destination address is on the local network. */
+
+ if (!net_ipv6addr_maskcmp(ip->destipaddr, dev->d_ipv6addr,
+ dev->d_ipv6netmask))
+ {
+ /* Destination address is not on the local network */
+
+#ifdef CONFIG_NET_ROUTE
+ /* We have a routing table.. find the correct router to use in
+ * this case (or, as a fall-back, use the device's default router
+ * address). We will use the router IPv6 address instead of the
+ * destination address when determining the MAC address.
+ */
+
+ netdev_ipv6_router(dev, ip->destipaddr, ipaddr);
+#else
+ /* Use the device's default router IPv6 address instead of the
+ * destination address when determining the MAC address.
+ */
+
+ net_ipv6addr_copy(ipaddr, dev->d_ipv6draddr);
+#endif
+ }
+ else
+ {
+ /* Else, we use the destination IPv6 address. */
+
+ net_ipv6addr_copy(ipaddr, ip->destipaddr);
+ }
+
+ /* Check if we already have this destination address in the Neighbor Table */
+
+ naddr = neighbor_lookup(ipaddr);
+ if (!naddr)
+ {
+ nllvdbg("IPv6 Neighbor solicitation for IPv6\n");
+
+ /* The destination address was not in our Neighbor Table, so we
+ * overwrite the IPv6 packet with an ICMDv6 Neighbor Solicitation
+ * message.
+ */
+
+ icmpv6_solicit(dev, ipaddr);
+ return;
+ }
+
+ /* Build an Ethernet header. */
+
+ memcpy(eth->dest, naddr->na_addr.ether_addr_octet, ETHER_ADDR_LEN);
+ }
+
+ /* Finish populating the Ethernet header */
+
+ memcpy(eth->src, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN);
+ eth->type = HTONS(ETHTYPE_IP6);
+ dev->d_len += ETH_HDRLEN;
+}