arp_out.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /****************************************************************************
  2. * net/arp/arp_out.c
  3. *
  4. * Copyright (C) 2007-2011, 2014-2015, 2017-2018 Gregory Nutt. All rights
  5. * reserved.
  6. * Author: Gregory Nutt <gnutt@nuttx.org>
  7. *
  8. * Based on uIP which also has a BSD style license:
  9. *
  10. * Author: Adam Dunkels <adam@dunkels.com>
  11. * Copyright (c) 2001-2003, Adam Dunkels.
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions
  16. * are met:
  17. *
  18. * 1. Redistributions of source code must retain the above copyright
  19. * notice, this list of conditions and the following disclaimer.
  20. * 2. Redistributions in binary form must reproduce the above copyright
  21. * notice, this list of conditions and the following disclaimer in the
  22. * documentation and/or other materials provided with the distribution.
  23. * 3. The name of the author may not be used to endorse or promote
  24. * products derived from this software without specific prior
  25. * written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  28. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  29. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  31. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  33. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  35. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. ****************************************************************************/
  40. /****************************************************************************
  41. * Included Files
  42. ****************************************************************************/
  43. #include <nuttx/config.h>
  44. #include <string.h>
  45. #include <debug.h>
  46. #include <nuttx/net/netdev.h>
  47. #include <nuttx/net/arp.h>
  48. #include "route/route.h"
  49. #include "arp/arp.h"
  50. #ifdef CONFIG_NET_ARP
  51. /****************************************************************************
  52. * Pre-processor Definitions
  53. ****************************************************************************/
  54. #define ETHBUF ((struct eth_hdr_s *)&dev->d_buf[0])
  55. #define ARPBUF ((struct arp_hdr_s *)&dev->d_buf[ETH_HDRLEN])
  56. #define IPBUF ((struct arp_iphdr_s *)&dev->d_buf[ETH_HDRLEN])
  57. /****************************************************************************
  58. * Private Data
  59. ****************************************************************************/
  60. /* Support for broadcast address */
  61. static const struct ether_addr g_broadcast_ethaddr =
  62. {
  63. {
  64. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  65. }
  66. };
  67. static const uint16_t g_broadcast_ipaddr[2] =
  68. {
  69. 0xffff, 0xffff
  70. };
  71. /* Support for IGMP multicast addresses.
  72. *
  73. * Well-known ethernet multicast address:
  74. *
  75. * ADDRESS TYPE USAGE
  76. * 01-00-0c-cc-cc-cc 0x0802 CDP (Cisco Discovery Protocol),
  77. * VTP (Virtual Trunking Protocol)
  78. * 01-00-0c-cc-cc-cd 0x0802 Cisco Shared Spanning Tree Protocol Address
  79. * 01-80-c2-00-00-00 0x0802 Spanning Tree Protocol (for bridges) IEEE 802.1D
  80. * 01-80-c2-00-00-02 0x0809 Ethernet OAM Protocol IEEE 802.3ah
  81. * 01-00-5e-xx-xx-xx 0x0800 IPv4 IGMP Multicast Address
  82. * 33-33-00-00-00-00 0x86DD IPv6 Neighbor Discovery
  83. * 33-33-xx-xx-xx-xx 0x86DD IPv6 Multicast Address (RFC3307)
  84. *
  85. * The following is the first three octects of the IGMP address:
  86. */
  87. #ifdef CONFIG_NET_IGMP
  88. static const uint8_t g_multicast_ethaddr[3] =
  89. {
  90. 0x01, 0x00, 0x5e
  91. };
  92. #endif
  93. /****************************************************************************
  94. * Public Functions
  95. ****************************************************************************/
  96. /****************************************************************************
  97. * Name: arp_out
  98. *
  99. * Description:
  100. * This function should be called before sending out an IP packet. The
  101. * function checks the destination IP address of the IP packet to see
  102. * what Ethernet MAC address that should be used as a destination MAC
  103. * address on the Ethernet.
  104. *
  105. * If the destination IP address is in the local network (determined
  106. * by logical ANDing of netmask and our IP address), the function
  107. * checks the ARP cache to see if an entry for the destination IP
  108. * address is found. If so, an Ethernet header is pre-pended at the
  109. * beginning of the packet and the function returns.
  110. *
  111. * If no ARP cache entry is found for the destination IP address, the
  112. * packet in the d_buf is replaced by an ARP request packet for the
  113. * IP address. The IP packet is dropped and it is assumed that the
  114. * higher level protocols (e.g., TCP) eventually will retransmit the
  115. * dropped packet.
  116. *
  117. * Upon return in either the case, a packet to be sent is present in the
  118. * d_buf buffer and the d_len field holds the length of the Ethernet
  119. * frame that should be transmitted.
  120. *
  121. ****************************************************************************/
  122. void arp_out(FAR struct net_driver_s *dev)
  123. {
  124. struct ether_addr ethaddr;
  125. FAR struct eth_hdr_s *peth = ETHBUF;
  126. FAR struct arp_iphdr_s *pip = IPBUF;
  127. in_addr_t ipaddr;
  128. in_addr_t destipaddr;
  129. int ret;
  130. #if defined(CONFIG_NET_PKT) || defined(CONFIG_NET_ARP_SEND)
  131. /* Skip sending ARP requests when the frame to be transmitted was
  132. * written into a packet socket.
  133. */
  134. if (IFF_IS_NOARP(dev->d_flags))
  135. {
  136. /* Clear the indication and let the packet continue on its way. */
  137. IFF_CLR_NOARP(dev->d_flags);
  138. return;
  139. }
  140. #endif
  141. /* Find the destination IP address in the ARP table and construct
  142. * the Ethernet header. If the destination IP address isn't on the
  143. * local network, we use the default router's IP address instead.
  144. *
  145. * If not ARP table entry is found, we overwrite the original IP
  146. * packet with an ARP request for the IP address.
  147. */
  148. /* First check if destination is a local broadcast. */
  149. if (net_ipv4addr_hdrcmp(pip->eh_destipaddr, g_broadcast_ipaddr))
  150. {
  151. memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
  152. goto finish_header;
  153. }
  154. #ifdef CONFIG_NET_IGMP
  155. /* Check if the destination address is a multicast address
  156. *
  157. * - IPv4: multicast addresses lie in the class D group -- The address range
  158. * 224.0.0.0 to 239.255.255.255 (224.0.0.0/4)
  159. *
  160. * - IPv6 multicast addresses are have the high-order octet of the
  161. * addresses=0xff (ff00::/8.)
  162. */
  163. if (NTOHS(pip->eh_destipaddr[0]) >= 0xe000 &&
  164. NTOHS(pip->eh_destipaddr[0]) <= 0xefff)
  165. {
  166. /* Build the well-known IPv4 IGMP Ethernet address. The first
  167. * three bytes are fixed; the final three variable come from the
  168. * last three bytes of the IPv4 address (network order).
  169. *
  170. * Address range : 01:00:5e:00:00:00 to 01:00:5e:7f:ff:ff
  171. */
  172. FAR const uint8_t *ip = (FAR uint8_t *)pip->eh_destipaddr;
  173. peth->dest[0] = g_multicast_ethaddr[0];
  174. peth->dest[1] = g_multicast_ethaddr[1];
  175. peth->dest[2] = g_multicast_ethaddr[2];
  176. peth->dest[3] = ip[1] & 0x7f;
  177. peth->dest[4] = ip[2];
  178. peth->dest[5] = ip[3];
  179. goto finish_header;
  180. }
  181. #endif
  182. /* Check if the destination address is on the local network. */
  183. destipaddr = net_ip4addr_conv32(pip->eh_destipaddr);
  184. if (!net_ipv4addr_maskcmp(destipaddr, dev->d_ipaddr, dev->d_netmask))
  185. {
  186. /* Destination address is not on the local network */
  187. #ifdef CONFIG_NET_ROUTE
  188. /* We have a routing table.. find the correct router to use in
  189. * this case (or, as a fall-back, use the device's default router
  190. * address). We will use the router IP address instead of the
  191. * destination address when determining the MAC address.
  192. */
  193. netdev_ipv4_router(dev, destipaddr, &ipaddr);
  194. #else
  195. /* Use the device's default router IP address instead of the
  196. * destination address when determining the MAC address.
  197. */
  198. net_ipv4addr_copy(ipaddr, dev->d_draddr);
  199. #endif
  200. }
  201. /* The destination address is on the local network. Check if it is
  202. * the sub-net broadcast address.
  203. */
  204. else if (net_ipv4addr_broadcast(destipaddr, dev->d_netmask))
  205. {
  206. /* Yes.. then we won't need to know the destination MAC address */
  207. memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
  208. goto finish_header;
  209. }
  210. else
  211. {
  212. /* Else, we use the destination IP address. */
  213. net_ipv4addr_copy(ipaddr, destipaddr);
  214. }
  215. /* Check if we already have this destination address in the ARP table */
  216. ret = arp_find(ipaddr, &ethaddr);
  217. if (ret < 0)
  218. {
  219. ninfo("ARP request for IP %08lx\n", (unsigned long)ipaddr);
  220. /* The destination address was not in our ARP table, so we overwrite
  221. * the IP packet with an ARP request.
  222. */
  223. arp_format(dev, ipaddr);
  224. arp_dump(ARPBUF);
  225. return;
  226. }
  227. /* Build an Ethernet header. */
  228. memcpy(peth->dest, ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
  229. /* Finish populating the Ethernet header */
  230. finish_header:
  231. memcpy(peth->src, dev->d_mac.ether.ether_addr_octet, ETHER_ADDR_LEN);
  232. peth->type = HTONS(ETHTYPE_IP);
  233. dev->d_len += ETH_HDRLEN;
  234. }
  235. #endif /* CONFIG_NET_ARP */