1 /**
2 * @file
3 *
4 * Ethernet output for IPv6. Uses ND tables for link-layer addressing.
5 */
6
7 /*
8 * Copyright (c) 2010 Inico Technologies Ltd.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 *
33 * This file is part of the lwIP TCP/IP stack.
34 *
35 * Author: Ivan Delamer <delamer@inicotech.com>
36 *
37 *
38 * Please coordinate changes and requests with Ivan Delamer
39 * <delamer@inicotech.com>
40 */
41
42 #include "lwip/opt.h"
43
44 #if LWIP_IPV6 && LWIP_ETHERNET
45
46 #include "lwip/ethip6.h"
47 #include "lwip/nd6.h"
48 #include "lwip/pbuf.h"
49 #include "lwip/ip6.h"
50 #include "lwip/ip6_addr.h"
51 #include "lwip/inet_chksum.h"
52 #include "lwip/netif.h"
53 #include "lwip/icmp6.h"
54 #include "lwip/prot/ethernet.h"
55 #include "netif/ethernet.h"
56
57 #include <string.h>
58
59 /**
60 * Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
61 *
62 * For IPv6 multicast, corresponding Ethernet addresses
63 * are selected and the packet is transmitted on the link.
64 *
65 * For unicast addresses, ask the ND6 module what to do. It will either let us
66 * send the the packet right away, or queue the packet for later itself, unless
67 * an error occurs.
68 *
69 * @todo anycast addresses
70 *
71 * @param netif The lwIP network interface which the IP packet will be sent on.
72 * @param q The pbuf(s) containing the IP packet to be sent.
73 * @param ip6addr The IP address of the packet destination.
74 *
75 * @return
76 * - ERR_OK or the return value of @ref nd6_get_next_hop_addr_or_queue.
77 */
78 err_t
ethip6_output(struct netif * netif,struct pbuf * q,const ip6_addr_t * ip6addr)79 ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
80 {
81 struct eth_addr dest;
82 const u8_t *hwaddr;
83 err_t result;
84
85 LWIP_ASSERT_CORE_LOCKED();
86
87 #if DRIVER_STATUS_CHECK
88 if (netif_is_ready(netif) == 0) {
89 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_output: netif driver not ready\n"));
90 /* Drop the packet here and return success */
91 return ERR_OK;
92 }
93 #endif
94
95 /* The destination IP address must be properly zoned from here on down. */
96 IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif);
97
98 /* multicast destination IP address? */
99 if (ip6_addr_ismulticast(ip6addr)) {
100 /* Hash IP multicast address to MAC address.*/
101 dest.addr[0] = 0x33;
102 dest.addr[1] = 0x33;
103 dest.addr[2] = ((const u8_t *)(&(ip6addr->addr[3])))[0];
104 dest.addr[3] = ((const u8_t *)(&(ip6addr->addr[3])))[1];
105 dest.addr[4] = ((const u8_t *)(&(ip6addr->addr[3])))[2];
106 dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3];
107
108 /* Send out. */
109 return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
110 }
111
112 if (ip6_addr_isany(ip6addr)) {
113 /* can not process any address, as it will lead in to random leaks and wont be able to simulate the problem,,,
114 rest needs to identify in what all cases any cast can have problem...
115 */
116 return ERR_RTE;
117 }
118
119 /* We have a unicast destination IP address */
120 /* @todo anycast? */
121
122 /* Ask ND6 what to do with the packet. */
123 result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr);
124 if (result != ERR_OK) {
125 return result;
126 }
127
128 /* If no hardware address is returned, nd6 has queued the packet for later. */
129 if (hwaddr == NULL) {
130 return ERR_OK;
131 }
132
133 /* Send out the packet using the returned hardware address. */
134 SMEMCPY(dest.addr, hwaddr, 6);
135 return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
136 }
137
138 #endif /* LWIP_IPV6 && LWIP_ETHERNET */
139