clean up old IOS handles on startup (dhewg)
[libogc.git] / libdb / uIP / uip_arp.c
blob44cb1f5300d378c9582e27ad0b60d43665f79e4b
1 /**
2 * \addtogroup uip
3 * @{
4 */
6 /**
7 * \defgroup uiparp uIP Address Resolution Protocol
8 * @{
9 *
10 * The Address Resolution Protocol ARP is used for mapping between IP
11 * addresses and link level addresses such as the Ethernet MAC
12 * addresses. ARP uses broadcast queries to ask for the link level
13 * address of a known IP address and the host which is configured with
14 * the IP address for which the query was meant, will respond with its
15 * link level address.
17 * \note This ARP implementation only supports Ethernet.
20 /**
21 * \file
22 * Implementation of the ARP Address Resolution Protocol.
23 * \author Adam Dunkels <adam@dunkels.com>
28 * Copyright (c) 2001-2003, Adam Dunkels.
29 * All rights reserved.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. The name of the author may not be used to endorse or promote
40 * products derived from this software without specific prior
41 * written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
49 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 * This file is part of the uIP TCP/IP stack.
61 #include "uip_pbuf.h"
62 #include "uip_netif.h"
63 #include "uip_arp.h"
65 #include <string.h>
67 #if UIP_LOGGING == 1
68 #include <stdio.h>
69 #define UIP_LOG(m) uip_log(__FILE__,__LINE__,m)
70 #else
71 #define UIP_LOG(m)
72 #endif /* UIP_LOGGING == 1 */
74 #if UIP_STATISTICS == 1
75 struct uip_stats uip_stat;
76 #define UIP_STAT(s) s
77 #else
78 #define UIP_STAT(s)
79 #endif /* UIP_STATISTICS == 1 */
82 #define ARP_TRY_HARD 0x01
84 #define ARP_MAXAGE 240
85 #define ARP_MAXPENDING 2
87 #define ARP_REQUEST 1
88 #define ARP_REPLY 2
90 #define ARP_HWTYPE_ETH 1
92 #define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)
93 #define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)
95 #define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
96 #define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
98 enum arp_state {
99 ARP_STATE_EMPTY,
100 ARP_STATE_PENDING,
101 ARP_STATE_STABLE,
102 ARP_STATE_EXPIRED
105 struct arp_entry {
106 struct uip_ip_addr ipaddr;
107 struct uip_eth_addr ethaddr;
108 enum arp_state state;
109 u8_t time;
112 static const struct uip_eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
113 static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
114 /*-----------------------------------------------------------------------------------*/
116 * Initialize the ARP module.
119 /*-----------------------------------------------------------------------------------*/
120 void
121 uip_arp_init(void)
123 s32_t i;
124 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
125 arp_table[i].state = ARP_STATE_EMPTY;
126 arp_table[i].time = 0;
129 /*-----------------------------------------------------------------------------------*/
131 * Periodic ARP processing function.
133 * This function performs periodic timer processing in the ARP module
134 * and should be called at regular intervals. The recommended interval
135 * is 10 seconds between the calls.
138 /*-----------------------------------------------------------------------------------*/
139 void
140 uip_arp_timer(void)
142 u8_t i;
144 for(i=0;i<UIP_ARPTAB_SIZE;i++) {
145 arp_table[i].time++;
146 if(arp_table[i].state==ARP_STATE_STABLE && arp_table[i].time>=ARP_MAXAGE) {
147 arp_table[i].state = ARP_STATE_EXPIRED;
148 } else if(arp_table[i].state==ARP_STATE_PENDING) {
149 if(arp_table[i].time>=ARP_MAXPENDING) arp_table[i].state = ARP_STATE_EXPIRED;
152 if(arp_table[i].state==ARP_STATE_EXPIRED) arp_table[i].state = ARP_STATE_EMPTY;
156 static s8_t uip_arp_findentry(struct uip_ip_addr *ipaddr,u8_t flags)
158 s8_t old_pending = UIP_ARPTAB_SIZE, old_stable = UIP_ARPTAB_SIZE;
159 s8_t empty = UIP_ARPTAB_SIZE;
160 u8_t i = 0,age_pending = 0,age_stable = 0;
162 /* Walk through the ARP mapping table and try to find an entry to
163 update. If none is found, the IP -> MAC address mapping is
164 inserted in the ARP table. */
165 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
166 if(empty==UIP_ARPTAB_SIZE && arp_table[i].state==ARP_STATE_EMPTY) {
167 empty = i;
168 } else if(arp_table[i].state==ARP_STATE_PENDING) {
169 if(ipaddr && ip_addr_cmp(ipaddr,&arp_table[i].ipaddr)) return i;
170 else if(arp_table[i].time>=age_pending) {
171 old_pending = i;
172 age_pending = arp_table[i].time;
174 } else if(arp_table[i].state==ARP_STATE_STABLE) {
175 if(ipaddr && ip_addr_cmp(ipaddr,&arp_table[i].ipaddr)) return i;
176 else if(arp_table[i].time>=age_stable) {
177 old_stable = i;
178 age_stable = arp_table[i].time;
182 if(empty==UIP_ARPTAB_SIZE && !(flags&ARP_TRY_HARD)) return UIP_ERR_MEM;
184 if(empty<UIP_ARPTAB_SIZE) i = empty;
185 else if(old_stable<UIP_ARPTAB_SIZE) i = old_stable;
186 else if(old_pending<UIP_ARPTAB_SIZE) i = old_pending;
187 else return UIP_ERR_MEM;
189 arp_table[i].time = 0;
190 arp_table[i].state = ARP_STATE_EMPTY;
191 if(ipaddr!=NULL) ip_addr_set(&arp_table[i].ipaddr,ipaddr);
193 return (s8_t)i;
196 /*-----------------------------------------------------------------------------------*/
197 static s8_t uip_arp_update(struct uip_netif *netif,struct uip_ip_addr *ipaddr, struct uip_eth_addr *ethaddr,u8_t flags)
199 s8_t i,k;
201 if(ip_addr_isany(ipaddr) ||
202 ip_addr_isbroadcast(ipaddr,netif) ||
203 ip_addr_ismulticast(ipaddr)) return UIP_ERR_ARG;
205 i = uip_arp_findentry(ipaddr,flags);
206 if(i<0) return i;
208 arp_table[i].time = 0;
209 arp_table[i].state = ARP_STATE_STABLE;
210 for(k=0;k<netif->hwaddr_len;k++) arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
212 return UIP_ERR_OK;
214 /*-----------------------------------------------------------------------------------*/
216 * ARP processing for incoming IP packets
218 * This function should be called by the device driver when an IP
219 * packet has been received. The function will check if the address is
220 * in the ARP cache, and if so the ARP cache entry will be
221 * refreshed. If no ARP cache entry was found, a new one is created.
223 * This function expects an IP packet with a prepended Ethernet header
224 * in the uip_buf[] buffer, and the length of the packet in the global
225 * variable uip_len.
227 /*-----------------------------------------------------------------------------------*/
228 void
229 uip_arp_ipin(struct uip_netif *netif,struct uip_pbuf *p)
231 struct uip_ethip_hdr *hdr;
233 hdr = p->payload;
234 if(!ip_addr_netcmp(&hdr->ip.src,&netif->ip_addr,&netif->netmask)) return;
236 uip_arp_update(netif,&hdr->ip.src,&hdr->ethhdr.src,0);
239 /*-----------------------------------------------------------------------------------*/
241 * ARP processing for incoming ARP packets.
243 * This function should be called by the device driver when an ARP
244 * packet has been received. The function will act differently
245 * depending on the ARP packet type: if it is a reply for a request
246 * that we previously sent out, the ARP cache will be filled in with
247 * the values from the ARP reply. If the incoming ARP packet is an ARP
248 * request for our IP address, an ARP reply packet is created and put
249 * into the uip_buf[] buffer.
251 * When the function returns, the value of the global variable uip_len
252 * indicates whether the device driver should send out a packet or
253 * not. If uip_len is zero, no packet should be sent. If uip_len is
254 * non-zero, it contains the length of the outbound packet that is
255 * present in the uip_buf[] buffer.
257 * This function expects an ARP packet with a prepended Ethernet
258 * header in the uip_buf[] buffer, and the length of the packet in the
259 * global variable uip_len.
261 /*-----------------------------------------------------------------------------------*/
262 void
263 uip_arp_arpin(struct uip_netif *netif,struct uip_eth_addr *ethaddr,struct uip_pbuf *p)
265 u8_t i,for_us;
266 struct uip_ip_addr sipaddr,dipaddr;
267 struct uip_arp_hdr *hdr;
269 if(p->tot_len<sizeof(struct uip_arp_hdr)) {
270 uip_pbuf_free(p);
271 return;
274 hdr = p->payload;
276 *(struct uip_ip_addr2*)((void*)&sipaddr) = hdr->sipaddr;
277 *(struct uip_ip_addr2*)((void*)&dipaddr) = hdr->dipaddr;
279 if(netif->ip_addr.addr==0) for_us = 0;
280 else for_us = ip_addr_cmp(&dipaddr,&netif->ip_addr);
282 if(for_us) uip_arp_update(netif,&sipaddr,&hdr->shwaddr,ARP_TRY_HARD);
283 else uip_arp_update(netif,&sipaddr,&hdr->shwaddr,0);
285 switch(htons(hdr->opcode)) {
286 case ARP_REQUEST:
287 if(for_us) {
288 hdr->opcode = htons(ARP_REPLY);
289 hdr->dipaddr = hdr->sipaddr;
290 hdr->sipaddr = *(struct uip_ip_addr2*)((void*)&netif->ip_addr);
292 for(i=0;i<netif->hwaddr_len;i++) {
293 hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
294 hdr->shwaddr.addr[i] = ethaddr->addr[i];
295 hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];
296 hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
299 hdr->hwtype = htons(ARP_HWTYPE_ETH);
300 ARPH_HWLEN_SET(hdr,netif->hwaddr_len);
302 hdr->protocol = htons(UIP_ETHTYPE_IP);
303 ARPH_PROTOLEN_SET(hdr,sizeof(struct uip_ip_addr));
305 netif->linkoutput(netif,p);
306 } else {
307 UIP_LOG("uip_arp_arpin: ip packet not for us.\n");
309 break;
310 case ARP_REPLY:
311 break;
312 default:
313 UIP_LOG("uip_arp_arpin: ARP unknown opcode type.\n");
314 break;
316 uip_pbuf_free(p);
318 /*-----------------------------------------------------------------------------------*/
320 * Prepend Ethernet header to an outbound IP packet and see if we need
321 * to send out an ARP request.
323 * This function should be called before sending out an IP packet. The
324 * function checks the destination IP address of the IP packet to see
325 * what Ethernet MAC address that should be used as a destination MAC
326 * address on the Ethernet.
328 * If the destination IP address is in the local network (determined
329 * by logical ANDing of netmask and our IP address), the function
330 * checks the ARP cache to see if an entry for the destination IP
331 * address is found. If so, an Ethernet header is prepended and the
332 * function returns. If no ARP cache entry is found for the
333 * destination IP address, the packet in the uip_buf[] is replaced by
334 * an ARP request packet for the IP address. The IP packet is dropped
335 * and it is assumed that they higher level protocols (e.g., TCP)
336 * eventually will retransmit the dropped packet.
338 * If the destination IP address is not on the local network, the IP
339 * address of the default router is used instead.
341 * When the function returns, a packet is present in the uip_buf[]
342 * buffer, and the length of the packet is in the global variable
343 * uip_len.
345 /*-----------------------------------------------------------------------------------*/
346 s8_t uip_arp_out(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_pbuf *q)
348 u8_t i;
349 struct uip_eth_addr *dest,*srcaddr,mcastaddr;
350 struct uip_eth_hdr *ethhdr;
352 if(uip_pbuf_header(q,sizeof(struct uip_eth_hdr))!=0) {
353 UIP_LOG("uip_arp_out: could not allocate room for header.\n");
354 return UIP_ERR_BUF;
357 dest = NULL;
358 if(ip_addr_isbroadcast(ipaddr,netif)) {
359 dest = (struct uip_eth_addr*)&ethbroadcast;
360 } else if(ip_addr_ismulticast(ipaddr)) {
361 /* Hash IP multicast address to MAC address.*/
362 mcastaddr.addr[0] = 0x01;
363 mcastaddr.addr[1] = 0x00;
364 mcastaddr.addr[2] = 0x5e;
365 mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
366 mcastaddr.addr[4] = ip4_addr3(ipaddr);
367 mcastaddr.addr[5] = ip4_addr4(ipaddr);
368 /* destination Ethernet address is multicast */
369 dest = &mcastaddr;
370 } else {
371 if(!ip_addr_netcmp(ipaddr,&netif->ip_addr,&netif->netmask)) {
372 if(netif->gw.addr!=0) ipaddr = &netif->gw;
373 else return UIP_ERR_RTE;
375 return uip_arp_arpquery(netif,ipaddr,q);
378 srcaddr = (struct uip_eth_addr*)netif->hwaddr;
379 ethhdr = q->payload;
380 for(i=0;i<netif->hwaddr_len;i++) {
381 ethhdr->dest.addr[i] = dest->addr[i];
382 ethhdr->src.addr[i] = srcaddr->addr[i];
385 ethhdr->type = htons(UIP_ETHTYPE_IP);
386 return netif->linkoutput(netif,q);
388 /*-----------------------------------------------------------------------------------*/
390 s8_t uip_arp_arpquery(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_pbuf *q)
392 s8_t i,k;
393 s8_t err = UIP_ERR_MEM;
394 struct uip_eth_addr *srcaddr = (struct uip_eth_addr*)netif->hwaddr;
396 if(ip_addr_isbroadcast(ipaddr,netif) ||
397 ip_addr_ismulticast(ipaddr) ||
398 ip_addr_isany(ipaddr)) return UIP_ERR_ARG;
400 i = uip_arp_findentry(ipaddr,ARP_TRY_HARD);
401 if(i<0) return i;
403 if(arp_table[i].state==ARP_STATE_EMPTY) arp_table[i].state = ARP_STATE_PENDING;
404 if(arp_table[i].state==ARP_STATE_PENDING || q==NULL) err = uip_arp_arprequest(netif,ipaddr);
406 if(q!=NULL) {
407 if(arp_table[i].state==ARP_STATE_STABLE) {
409 struct uip_eth_hdr *hdr = q->payload;
410 for(k=0;k<netif->hwaddr_len;k++) {
411 hdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];
412 hdr->src.addr[k] = srcaddr->addr[k];
415 hdr->type = htons(UIP_ETHTYPE_IP);
416 err = netif->linkoutput(netif,q);
417 } else if(arp_table[i].state==ARP_STATE_PENDING) {
418 UIP_LOG("uip_arp_query: Ethernet destination address unknown, queueing disabled, packet dropped.\n");
421 return err;
424 s8_t uip_arp_arprequest(struct uip_netif *netif,struct uip_ip_addr *ipaddr)
426 s8_t k;
427 s8_t err = UIP_ERR_MEM;
428 struct uip_arp_hdr *hdr;
429 struct uip_pbuf *p;
430 struct uip_eth_addr *srcaddr = (struct uip_eth_addr*)netif->hwaddr;
432 p = uip_pbuf_alloc(UIP_PBUF_LINK,sizeof(struct uip_arp_hdr),UIP_PBUF_RAM);
433 if(p==NULL) return err;
435 hdr = p->payload;
436 hdr->opcode = htons(ARP_REQUEST);
438 for(k=0;k<netif->hwaddr_len;k++) {
439 hdr->shwaddr.addr[k] = srcaddr->addr[k];
440 hdr->dhwaddr.addr[k] = 0;
443 hdr->dipaddr = *(struct uip_ip_addr2*)((void*)ipaddr);
444 hdr->sipaddr = *(struct uip_ip_addr2*)((void*)&netif->ip_addr);
446 hdr->hwtype = htons(ARP_HWTYPE_ETH);
447 ARPH_HWLEN_SET(hdr,netif->hwaddr_len);
449 hdr->protocol = htons(UIP_ETHTYPE_IP);
450 ARPH_PROTOLEN_SET(hdr,sizeof(struct uip_ip_addr));
451 for(k=0;k<netif->hwaddr_len;k++) {
452 hdr->ethhdr.dest.addr[k] = 0xff;
453 hdr->ethhdr.src.addr[k] = srcaddr->addr[k];
455 hdr->ethhdr.type = htons(UIP_ETHTYPE_ARP);
457 err = netif->linkoutput(netif,p);
458 uip_pbuf_free(p);
460 return err;
463 /** @} */
464 /** @} */