123

Committer:
hudakz
Date:
Mon Sep 15 11:12:30 2014 +0000
Revision:
0:5350a66d5279
rev. 00

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:5350a66d5279 1 /**
hudakz 0:5350a66d5279 2 * \addtogroup uip
hudakz 0:5350a66d5279 3 * @{
hudakz 0:5350a66d5279 4 */
hudakz 0:5350a66d5279 5 /**
hudakz 0:5350a66d5279 6 * \defgroup uiparp uIP Address Resolution Protocol
hudakz 0:5350a66d5279 7 * @{
hudakz 0:5350a66d5279 8 *
hudakz 0:5350a66d5279 9 * The Address Resolution Protocol ARP is used for mapping between IP
hudakz 0:5350a66d5279 10 * addresses and link level addresses such as the Ethernet MAC
hudakz 0:5350a66d5279 11 * addresses. ARP uses broadcast queries to ask for the link level
hudakz 0:5350a66d5279 12 * address of a known IP address and the host which is configured with
hudakz 0:5350a66d5279 13 * the IP address for which the query was meant, will respond with its
hudakz 0:5350a66d5279 14 * link level address.
hudakz 0:5350a66d5279 15 *
hudakz 0:5350a66d5279 16 * \note This ARP implementation only supports Ethernet.
hudakz 0:5350a66d5279 17 */
hudakz 0:5350a66d5279 18 /**
hudakz 0:5350a66d5279 19 * \file
hudakz 0:5350a66d5279 20 * Implementation of the ARP Address Resolution Protocol.
hudakz 0:5350a66d5279 21 * \author Adam Dunkels <adam@dunkels.com>
hudakz 0:5350a66d5279 22 *
hudakz 0:5350a66d5279 23 */
hudakz 0:5350a66d5279 24 /*
hudakz 0:5350a66d5279 25 * Copyright (c) 2001-2003, Adam Dunkels.
hudakz 0:5350a66d5279 26 * All rights reserved.
hudakz 0:5350a66d5279 27 *
hudakz 0:5350a66d5279 28 * Redistribution and use in source and binary forms, with or without
hudakz 0:5350a66d5279 29 * modification, are permitted provided that the following conditions
hudakz 0:5350a66d5279 30 * are met:
hudakz 0:5350a66d5279 31 * 1. Redistributions of source code must retain the above copyright
hudakz 0:5350a66d5279 32 * notice, this list of conditions and the following disclaimer.
hudakz 0:5350a66d5279 33 * 2. Redistributions in binary form must reproduce the above copyright
hudakz 0:5350a66d5279 34 * notice, this list of conditions and the following disclaimer in the
hudakz 0:5350a66d5279 35 * documentation and/or other materials provided with the distribution.
hudakz 0:5350a66d5279 36 * 3. The name of the author may not be used to endorse or promote
hudakz 0:5350a66d5279 37 * products derived from this software without specific prior
hudakz 0:5350a66d5279 38 * written permission.
hudakz 0:5350a66d5279 39 *
hudakz 0:5350a66d5279 40 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
hudakz 0:5350a66d5279 41 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
hudakz 0:5350a66d5279 42 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
hudakz 0:5350a66d5279 43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
hudakz 0:5350a66d5279 44 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
hudakz 0:5350a66d5279 45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
hudakz 0:5350a66d5279 46 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
hudakz 0:5350a66d5279 47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
hudakz 0:5350a66d5279 48 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
hudakz 0:5350a66d5279 49 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
hudakz 0:5350a66d5279 50 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
hudakz 0:5350a66d5279 51 *
hudakz 0:5350a66d5279 52 * This file is part of the uIP TCP/IP stack.
hudakz 0:5350a66d5279 53 *
hudakz 0:5350a66d5279 54 * $Id: uip_arp.c,v 1.8 2006/06/02 23:36:21 adam Exp $
hudakz 0:5350a66d5279 55 *
hudakz 0:5350a66d5279 56 */
hudakz 0:5350a66d5279 57 #include "uip_arp.h"
hudakz 0:5350a66d5279 58
hudakz 0:5350a66d5279 59 #include <string.h>
hudakz 0:5350a66d5279 60
hudakz 0:5350a66d5279 61 struct arp_hdr
hudakz 0:5350a66d5279 62 {
hudakz 0:5350a66d5279 63 struct uip_eth_hdr ethhdr;
hudakz 0:5350a66d5279 64 u16_t hwtype;
hudakz 0:5350a66d5279 65 u16_t protocol;
hudakz 0:5350a66d5279 66 u8_t hwlen;
hudakz 0:5350a66d5279 67 u8_t protolen;
hudakz 0:5350a66d5279 68 u16_t opcode;
hudakz 0:5350a66d5279 69 struct uip_eth_addr shwaddr;
hudakz 0:5350a66d5279 70 u16_t sipaddr[2];
hudakz 0:5350a66d5279 71 struct uip_eth_addr dhwaddr;
hudakz 0:5350a66d5279 72 u16_t dipaddr[2];
hudakz 0:5350a66d5279 73 };
hudakz 0:5350a66d5279 74
hudakz 0:5350a66d5279 75 struct ethip_hdr
hudakz 0:5350a66d5279 76 {
hudakz 0:5350a66d5279 77 struct uip_eth_hdr ethhdr;
hudakz 0:5350a66d5279 78
hudakz 0:5350a66d5279 79 /* IP header. */
hudakz 0:5350a66d5279 80 u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
hudakz 0:5350a66d5279 81 u16_t ipchksum;
hudakz 0:5350a66d5279 82 u16_t srcipaddr[2], destipaddr[2];
hudakz 0:5350a66d5279 83 };
hudakz 0:5350a66d5279 84
hudakz 0:5350a66d5279 85 #define ARP_REQUEST 1
hudakz 0:5350a66d5279 86 #define ARP_REPLY 2
hudakz 0:5350a66d5279 87
hudakz 0:5350a66d5279 88 #define ARP_HWTYPE_ETH 1
hudakz 0:5350a66d5279 89
hudakz 0:5350a66d5279 90 struct arp_entry
hudakz 0:5350a66d5279 91 {
hudakz 0:5350a66d5279 92 u16_t ipaddr[2];
hudakz 0:5350a66d5279 93 struct uip_eth_addr ethaddr;
hudakz 0:5350a66d5279 94 u8_t time;
hudakz 0:5350a66d5279 95 };
hudakz 0:5350a66d5279 96
hudakz 0:5350a66d5279 97 static const struct uip_eth_addr broadcast_ethaddr = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
hudakz 0:5350a66d5279 98 static const u16_t broadcast_ipaddr[2] = { 0xffff, 0xffff };
hudakz 0:5350a66d5279 99
hudakz 0:5350a66d5279 100 static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
hudakz 0:5350a66d5279 101 static u16_t ipaddr[2];
hudakz 0:5350a66d5279 102 static u8_t i, c;
hudakz 0:5350a66d5279 103
hudakz 0:5350a66d5279 104 static u8_t arptime;
hudakz 0:5350a66d5279 105 static u8_t tmpage;
hudakz 0:5350a66d5279 106
hudakz 0:5350a66d5279 107 #define BUF ((struct arp_hdr*) &uip_buf[0])
hudakz 0:5350a66d5279 108 #define IPBUF ((struct ethip_hdr*) &uip_buf[0])
hudakz 0:5350a66d5279 109 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 110
hudakz 0:5350a66d5279 111 /**
hudakz 0:5350a66d5279 112 * Initialize the ARP module.
hudakz 0:5350a66d5279 113 *
hudakz 0:5350a66d5279 114 */
hudakz 0:5350a66d5279 115
hudakz 0:5350a66d5279 116 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 117 void uip_arp_init(void) {
hudakz 0:5350a66d5279 118 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
hudakz 0:5350a66d5279 119 memset(arp_table[i].ipaddr, 0, 4);
hudakz 0:5350a66d5279 120 }
hudakz 0:5350a66d5279 121 }
hudakz 0:5350a66d5279 122
hudakz 0:5350a66d5279 123 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 124 /**
hudakz 0:5350a66d5279 125 * Periodic ARP processing function.
hudakz 0:5350a66d5279 126 *
hudakz 0:5350a66d5279 127 * This function performs periodic timer processing in the ARP module
hudakz 0:5350a66d5279 128 * and should be called at regular intervals. The recommended interval
hudakz 0:5350a66d5279 129 * is 10 seconds between the calls.
hudakz 0:5350a66d5279 130 *
hudakz 0:5350a66d5279 131 */
hudakz 0:5350a66d5279 132
hudakz 0:5350a66d5279 133 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 134 void uip_arp_timer(void) {
hudakz 0:5350a66d5279 135 struct arp_entry* tabptr;
hudakz 0:5350a66d5279 136
hudakz 0:5350a66d5279 137 ++arptime;
hudakz 0:5350a66d5279 138 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
hudakz 0:5350a66d5279 139 tabptr = &arp_table[i];
hudakz 0:5350a66d5279 140 if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 && arptime - tabptr->time >= UIP_ARP_MAXAGE) {
hudakz 0:5350a66d5279 141 memset(tabptr->ipaddr, 0, 4);
hudakz 0:5350a66d5279 142 }
hudakz 0:5350a66d5279 143 }
hudakz 0:5350a66d5279 144 }
hudakz 0:5350a66d5279 145
hudakz 0:5350a66d5279 146 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 147 static void uip_arp_update(u16_t* ipaddr, struct uip_eth_addr* ethaddr) {
hudakz 0:5350a66d5279 148 register struct arp_entry* tabptr;
hudakz 0:5350a66d5279 149 /* Walk through the ARP mapping table and try to find an entry to
hudakz 0:5350a66d5279 150 update. If none is found, the IP -> MAC address mapping is
hudakz 0:5350a66d5279 151 inserted in the ARP table. */
hudakz 0:5350a66d5279 152
hudakz 0:5350a66d5279 153 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
hudakz 0:5350a66d5279 154 tabptr = &arp_table[i];
hudakz 0:5350a66d5279 155
hudakz 0:5350a66d5279 156 /* Only check those entries that are actually in use. */
hudakz 0:5350a66d5279 157 if(tabptr->ipaddr[0] != 0 && tabptr->ipaddr[1] != 0) {
hudakz 0:5350a66d5279 158
hudakz 0:5350a66d5279 159 /* Check if the source IP address of the incoming packet matches
hudakz 0:5350a66d5279 160 the IP address in this ARP table entry. */
hudakz 0:5350a66d5279 161 if(ipaddr[0] == tabptr->ipaddr[0] && ipaddr[1] == tabptr->ipaddr[1]) {
hudakz 0:5350a66d5279 162
hudakz 0:5350a66d5279 163 /* An old entry found, update this and return. */
hudakz 0:5350a66d5279 164 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
hudakz 0:5350a66d5279 165 tabptr->time = arptime;
hudakz 0:5350a66d5279 166
hudakz 0:5350a66d5279 167 return;
hudakz 0:5350a66d5279 168 }
hudakz 0:5350a66d5279 169 }
hudakz 0:5350a66d5279 170 }
hudakz 0:5350a66d5279 171
hudakz 0:5350a66d5279 172 /* If we get here, no existing ARP table entry was found, so we
hudakz 0:5350a66d5279 173 create one. */
hudakz 0:5350a66d5279 174 /* First, we try to find an unused entry in the ARP table. */
hudakz 0:5350a66d5279 175 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
hudakz 0:5350a66d5279 176 tabptr = &arp_table[i];
hudakz 0:5350a66d5279 177 if(tabptr->ipaddr[0] == 0 && tabptr->ipaddr[1] == 0) {
hudakz 0:5350a66d5279 178 break;
hudakz 0:5350a66d5279 179 }
hudakz 0:5350a66d5279 180 }
hudakz 0:5350a66d5279 181
hudakz 0:5350a66d5279 182 /* If no unused entry is found, we try to find the oldest entry and
hudakz 0:5350a66d5279 183 throw it away. */
hudakz 0:5350a66d5279 184 if(i == UIP_ARPTAB_SIZE) {
hudakz 0:5350a66d5279 185 tmpage = 0;
hudakz 0:5350a66d5279 186 c = 0;
hudakz 0:5350a66d5279 187 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
hudakz 0:5350a66d5279 188 tabptr = &arp_table[i];
hudakz 0:5350a66d5279 189 if(arptime - tabptr->time > tmpage) {
hudakz 0:5350a66d5279 190 tmpage = arptime - tabptr->time;
hudakz 0:5350a66d5279 191 c = i;
hudakz 0:5350a66d5279 192 }
hudakz 0:5350a66d5279 193 }
hudakz 0:5350a66d5279 194
hudakz 0:5350a66d5279 195 i = c;
hudakz 0:5350a66d5279 196 tabptr = &arp_table[i];
hudakz 0:5350a66d5279 197 }
hudakz 0:5350a66d5279 198
hudakz 0:5350a66d5279 199 /* Now, i is the ARP table entry which we will fill with the new
hudakz 0:5350a66d5279 200 information. */
hudakz 0:5350a66d5279 201 memcpy(tabptr->ipaddr, ipaddr, 4);
hudakz 0:5350a66d5279 202 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
hudakz 0:5350a66d5279 203 tabptr->time = arptime;
hudakz 0:5350a66d5279 204 }
hudakz 0:5350a66d5279 205
hudakz 0:5350a66d5279 206 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 207 /**
hudakz 0:5350a66d5279 208 * ARP processing for incoming IP packets
hudakz 0:5350a66d5279 209 *
hudakz 0:5350a66d5279 210 * This function should be called by the device driver when an IP
hudakz 0:5350a66d5279 211 * packet has been received. The function will check if the address is
hudakz 0:5350a66d5279 212 * in the ARP cache, and if so the ARP cache entry will be
hudakz 0:5350a66d5279 213 * refreshed. If no ARP cache entry was found, a new one is created.
hudakz 0:5350a66d5279 214 *
hudakz 0:5350a66d5279 215 * This function expects an IP packet with a prepended Ethernet header
hudakz 0:5350a66d5279 216 * in the uip_buf[] buffer, and the length of the packet in the global
hudakz 0:5350a66d5279 217 * variable uip_len.
hudakz 0:5350a66d5279 218 */
hudakz 0:5350a66d5279 219 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 220
hudakz 0:5350a66d5279 221 //#if 0
hudakz 0:5350a66d5279 222 void uip_arp_ipin(void) {
hudakz 0:5350a66d5279 223 uip_len -= sizeof(struct uip_eth_hdr);
hudakz 0:5350a66d5279 224
hudakz 0:5350a66d5279 225 /* Only insert/update an entry if the source IP address of the
hudakz 0:5350a66d5279 226 incoming IP packet comes from a host on the local network. */
hudakz 0:5350a66d5279 227 if((IPBUF->srcipaddr[0] & uip_netmask[0]) != (uip_hostaddr[0] & uip_netmask[0])) {
hudakz 0:5350a66d5279 228 return;
hudakz 0:5350a66d5279 229 }
hudakz 0:5350a66d5279 230
hudakz 0:5350a66d5279 231 if((IPBUF->srcipaddr[1] & uip_netmask[1]) != (uip_hostaddr[1] & uip_netmask[1])) {
hudakz 0:5350a66d5279 232 return;
hudakz 0:5350a66d5279 233 }
hudakz 0:5350a66d5279 234
hudakz 0:5350a66d5279 235 uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
hudakz 0:5350a66d5279 236
hudakz 0:5350a66d5279 237 return;
hudakz 0:5350a66d5279 238 }
hudakz 0:5350a66d5279 239
hudakz 0:5350a66d5279 240 //#endif /* 0 */
hudakz 0:5350a66d5279 241 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 242 /**
hudakz 0:5350a66d5279 243 * ARP processing for incoming ARP packets.
hudakz 0:5350a66d5279 244 *
hudakz 0:5350a66d5279 245 * This function should be called by the device driver when an ARP
hudakz 0:5350a66d5279 246 * packet has been received. The function will act differently
hudakz 0:5350a66d5279 247 * depending on the ARP packet type: if it is a reply for a request
hudakz 0:5350a66d5279 248 * that we previously sent out, the ARP cache will be filled in with
hudakz 0:5350a66d5279 249 * the values from the ARP reply. If the incoming ARP packet is an ARP
hudakz 0:5350a66d5279 250 * request for our IP address, an ARP reply packet is created and put
hudakz 0:5350a66d5279 251 * into the uip_buf[] buffer.
hudakz 0:5350a66d5279 252 *
hudakz 0:5350a66d5279 253 * When the function returns, the value of the global variable uip_len
hudakz 0:5350a66d5279 254 * indicates whether the device driver should send out a packet or
hudakz 0:5350a66d5279 255 * not. If uip_len is zero, no packet should be sent. If uip_len is
hudakz 0:5350a66d5279 256 * non-zero, it contains the length of the outbound packet that is
hudakz 0:5350a66d5279 257 * present in the uip_buf[] buffer.
hudakz 0:5350a66d5279 258 *
hudakz 0:5350a66d5279 259 * This function expects an ARP packet with a prepended Ethernet
hudakz 0:5350a66d5279 260 * header in the uip_buf[] buffer, and the length of the packet in the
hudakz 0:5350a66d5279 261 * global variable uip_len.
hudakz 0:5350a66d5279 262 */
hudakz 0:5350a66d5279 263
hudakz 0:5350a66d5279 264 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 265 void uip_arp_arpin(void) {
hudakz 0:5350a66d5279 266 if(uip_len < sizeof(struct arp_hdr)) {
hudakz 0:5350a66d5279 267 uip_len = 0;
hudakz 0:5350a66d5279 268 return;
hudakz 0:5350a66d5279 269 }
hudakz 0:5350a66d5279 270
hudakz 0:5350a66d5279 271 uip_len = 0;
hudakz 0:5350a66d5279 272
hudakz 0:5350a66d5279 273 switch(BUF->opcode) {
hudakz 0:5350a66d5279 274 case HTONS(ARP_REQUEST):
hudakz 0:5350a66d5279 275 /* ARP request. If it asked for our address, we send out a
hudakz 0:5350a66d5279 276 reply. */
hudakz 0:5350a66d5279 277 if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
hudakz 0:5350a66d5279 278
hudakz 0:5350a66d5279 279 /* First, we register the one who made the request in our ARP
hudakz 0:5350a66d5279 280 table, since it is likely that we will do more communication
hudakz 0:5350a66d5279 281 with this host in the future. */
hudakz 0:5350a66d5279 282 uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
hudakz 0:5350a66d5279 283
hudakz 0:5350a66d5279 284 /* The reply opcode is 2. */
hudakz 0:5350a66d5279 285 BUF->opcode = HTONS(2);
hudakz 0:5350a66d5279 286
hudakz 0:5350a66d5279 287 memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
hudakz 0:5350a66d5279 288 memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
hudakz 0:5350a66d5279 289 memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
hudakz 0:5350a66d5279 290 memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
hudakz 0:5350a66d5279 291
hudakz 0:5350a66d5279 292 BUF->dipaddr[0] = BUF->sipaddr[0];
hudakz 0:5350a66d5279 293 BUF->dipaddr[1] = BUF->sipaddr[1];
hudakz 0:5350a66d5279 294 BUF->sipaddr[0] = uip_hostaddr[0];
hudakz 0:5350a66d5279 295 BUF->sipaddr[1] = uip_hostaddr[1];
hudakz 0:5350a66d5279 296
hudakz 0:5350a66d5279 297 BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
hudakz 0:5350a66d5279 298 uip_len = sizeof(struct arp_hdr);
hudakz 0:5350a66d5279 299 }
hudakz 0:5350a66d5279 300 break;
hudakz 0:5350a66d5279 301
hudakz 0:5350a66d5279 302 case HTONS(ARP_REPLY):
hudakz 0:5350a66d5279 303 /* ARP reply. We insert or update the ARP table if it was meant
hudakz 0:5350a66d5279 304 for us. */
hudakz 0:5350a66d5279 305 if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
hudakz 0:5350a66d5279 306 uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
hudakz 0:5350a66d5279 307 }
hudakz 0:5350a66d5279 308 break;
hudakz 0:5350a66d5279 309 }
hudakz 0:5350a66d5279 310
hudakz 0:5350a66d5279 311 return;
hudakz 0:5350a66d5279 312 }
hudakz 0:5350a66d5279 313
hudakz 0:5350a66d5279 314 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 315 /**
hudakz 0:5350a66d5279 316 * Prepend Ethernet header to an outbound IP packet and see if we need
hudakz 0:5350a66d5279 317 * to send out an ARP request.
hudakz 0:5350a66d5279 318 *
hudakz 0:5350a66d5279 319 * This function should be called before sending out an IP packet. The
hudakz 0:5350a66d5279 320 * function checks the destination IP address of the IP packet to see
hudakz 0:5350a66d5279 321 * what Ethernet MAC address that should be used as a destination MAC
hudakz 0:5350a66d5279 322 * address on the Ethernet.
hudakz 0:5350a66d5279 323 *
hudakz 0:5350a66d5279 324 * If the destination IP address is in the local network (determined
hudakz 0:5350a66d5279 325 * by logical ANDing of netmask and our IP address), the function
hudakz 0:5350a66d5279 326 * checks the ARP cache to see if an entry for the destination IP
hudakz 0:5350a66d5279 327 * address is found. If so, an Ethernet header is prepended and the
hudakz 0:5350a66d5279 328 * function returns. If no ARP cache entry is found for the
hudakz 0:5350a66d5279 329 * destination IP address, the packet in the uip_buf[] is replaced by
hudakz 0:5350a66d5279 330 * an ARP request packet for the IP address. The IP packet is dropped
hudakz 0:5350a66d5279 331 * and it is assumed that they higher level protocols (e.g., TCP)
hudakz 0:5350a66d5279 332 * eventually will retransmit the dropped packet.
hudakz 0:5350a66d5279 333 *
hudakz 0:5350a66d5279 334 * If the destination IP address is not on the local network, the IP
hudakz 0:5350a66d5279 335 * address of the default router is used instead.
hudakz 0:5350a66d5279 336 *
hudakz 0:5350a66d5279 337 * When the function returns, a packet is present in the uip_buf[]
hudakz 0:5350a66d5279 338 * buffer, and the length of the packet is in the global variable
hudakz 0:5350a66d5279 339 * uip_len.
hudakz 0:5350a66d5279 340 */
hudakz 0:5350a66d5279 341
hudakz 0:5350a66d5279 342 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 343 void uip_arp_out(void) {
hudakz 0:5350a66d5279 344 struct arp_entry* tabptr;
hudakz 0:5350a66d5279 345
hudakz 0:5350a66d5279 346 /* Find the destination IP address in the ARP table and construct
hudakz 0:5350a66d5279 347 the Ethernet header. If the destination IP addres isn't on the
hudakz 0:5350a66d5279 348 local network, we use the default router's IP address instead.
hudakz 0:5350a66d5279 349
hudakz 0:5350a66d5279 350 If not ARP table entry is found, we overwrite the original IP
hudakz 0:5350a66d5279 351 packet with an ARP request for the IP address. */
hudakz 0:5350a66d5279 352
hudakz 0:5350a66d5279 353 /* First check if destination is a local broadcast. */
hudakz 0:5350a66d5279 354 if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) {
hudakz 0:5350a66d5279 355 memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
hudakz 0:5350a66d5279 356 }
hudakz 0:5350a66d5279 357 else {
hudakz 0:5350a66d5279 358
hudakz 0:5350a66d5279 359 /* Check if the destination address is on the local network. */
hudakz 0:5350a66d5279 360 if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) {
hudakz 0:5350a66d5279 361
hudakz 0:5350a66d5279 362 /* Destination address was not on the local network, so we need to
hudakz 0:5350a66d5279 363 use the default router's IP address instead of the destination
hudakz 0:5350a66d5279 364 address when determining the MAC address. */
hudakz 0:5350a66d5279 365 uip_ipaddr_copy(ipaddr, uip_draddr);
hudakz 0:5350a66d5279 366 }
hudakz 0:5350a66d5279 367 else {
hudakz 0:5350a66d5279 368
hudakz 0:5350a66d5279 369 /* Else, we use the destination IP address. */
hudakz 0:5350a66d5279 370 uip_ipaddr_copy(ipaddr, IPBUF->destipaddr);
hudakz 0:5350a66d5279 371 }
hudakz 0:5350a66d5279 372
hudakz 0:5350a66d5279 373 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
hudakz 0:5350a66d5279 374 tabptr = &arp_table[i];
hudakz 0:5350a66d5279 375 if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) {
hudakz 0:5350a66d5279 376 break;
hudakz 0:5350a66d5279 377 }
hudakz 0:5350a66d5279 378 }
hudakz 0:5350a66d5279 379
hudakz 0:5350a66d5279 380 if(i == UIP_ARPTAB_SIZE) {
hudakz 0:5350a66d5279 381
hudakz 0:5350a66d5279 382 /* The destination address was not in our ARP table, so we
hudakz 0:5350a66d5279 383 overwrite the IP packet with an ARP request. */
hudakz 0:5350a66d5279 384 memset(BUF->ethhdr.dest.addr, 0xff, 6);
hudakz 0:5350a66d5279 385 memset(BUF->dhwaddr.addr, 0x00, 6);
hudakz 0:5350a66d5279 386 memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
hudakz 0:5350a66d5279 387 memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
hudakz 0:5350a66d5279 388
hudakz 0:5350a66d5279 389 uip_ipaddr_copy(BUF->dipaddr, ipaddr);
hudakz 0:5350a66d5279 390 uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);
hudakz 0:5350a66d5279 391 BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */
hudakz 0:5350a66d5279 392 BUF->hwtype = HTONS(ARP_HWTYPE_ETH);
hudakz 0:5350a66d5279 393 BUF->protocol = HTONS(UIP_ETHTYPE_IP);
hudakz 0:5350a66d5279 394 BUF->hwlen = 6;
hudakz 0:5350a66d5279 395 BUF->protolen = 4;
hudakz 0:5350a66d5279 396 BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
hudakz 0:5350a66d5279 397
hudakz 0:5350a66d5279 398 uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];
hudakz 0:5350a66d5279 399
hudakz 0:5350a66d5279 400 uip_len = sizeof(struct arp_hdr);
hudakz 0:5350a66d5279 401 return;
hudakz 0:5350a66d5279 402 }
hudakz 0:5350a66d5279 403
hudakz 0:5350a66d5279 404 /* Build an ethernet header. */
hudakz 0:5350a66d5279 405 memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
hudakz 0:5350a66d5279 406 }
hudakz 0:5350a66d5279 407
hudakz 0:5350a66d5279 408 memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
hudakz 0:5350a66d5279 409
hudakz 0:5350a66d5279 410 IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);
hudakz 0:5350a66d5279 411
hudakz 0:5350a66d5279 412 uip_len += sizeof(struct uip_eth_hdr);
hudakz 0:5350a66d5279 413 }
hudakz 0:5350a66d5279 414
hudakz 0:5350a66d5279 415 /*-----------------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 416 /** @} */
hudakz 0:5350a66d5279 417 /** @} */