uip_arp.c

Go to the documentation of this file.
00001 
00027 /*
00028  * Copyright (c) 2001-2003, Adam Dunkels.
00029  * All rights reserved.
00030  *
00031  * Redistribution and use in source and binary forms, with or without
00032  * modification, are permitted provided that the following conditions
00033  * are met:
00034  * 1. Redistributions of source code must retain the above copyright
00035  *    notice, this list of conditions and the following disclaimer.
00036  * 2. Redistributions in binary form must reproduce the above copyright
00037  *    notice, this list of conditions and the following disclaimer in the
00038  *    documentation and/or other materials provided with the distribution.
00039  * 3. The name of the author may not be used to endorse or promote
00040  *    products derived from this software without specific prior
00041  *    written permission.
00042  *
00043  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
00044  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00045  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00046  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00047  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00048  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00049  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00050  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00051  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00052  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00053  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00054  *
00055  * This file is part of the uIP TCP/IP stack.
00056  *
00057  * $Id: uip_arp.c,v 1.8 2006/06/02 23:36:21 adam Exp $
00058  *
00059  */
00060 
00061 
00062 #include "uip_arp.h"
00063 
00064 #include <string.h>
00065 
00066 #ifdef __ICCARM__
00067         #pragma pack(1)
00068 #endif
00069 
00070 struct arp_hdr {
00071   struct uip_eth_hdr ethhdr;
00072   u16_t hwtype;
00073   u16_t protocol;
00074   u8_t hwlen;
00075   u8_t protolen;
00076   u16_t opcode;
00077   struct uip_eth_addr shwaddr;
00078   u16_t sipaddr[2];
00079   struct uip_eth_addr dhwaddr;
00080   u16_t dipaddr[2];
00081 } PACK_STRUCT_END;
00082 
00083 #ifdef __ICCARM__
00084         #pragma pack()
00085 #endif
00086 
00087 #ifdef __ICCARM__
00088         #pragma pack(1)
00089 #endif
00090 
00091 struct ethip_hdr {
00092   struct uip_eth_hdr ethhdr;
00093   /* IP header. */
00094   u8_t vhl,
00095     tos,
00096     len[2],
00097     ipid[2],
00098     ipoffset[2],
00099     ttl,
00100     proto;
00101   u16_t ipchksum;
00102   u16_t srcipaddr[2],
00103     destipaddr[2];
00104 } PACK_STRUCT_END;
00105 
00106 #ifdef __ICCARM__
00107         #pragma pack()
00108 #endif
00109 
00110 #define ARP_REQUEST 1
00111 #define ARP_REPLY   2
00112 
00113 #define ARP_HWTYPE_ETH 1
00114 
00115 struct arp_entry {
00116   u16_t ipaddr[2];
00117   struct uip_eth_addr ethaddr;
00118   u8_t time;
00119 };
00120 
00121 static const struct uip_eth_addr broadcast_ethaddr =
00122   {{0xff,0xff,0xff,0xff,0xff,0xff}};
00123 static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff};
00124 
00125 static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
00126 static u16_t ipaddr[2];
00127 static u8_t i, c;
00128 
00129 static u8_t arptime;
00130 static u8_t tmpage;
00131 
00132 #define BUF   ((struct arp_hdr *)&uip_buf[0])
00133 #define IPBUF ((struct ethip_hdr *)&uip_buf[0])
00134 /*-----------------------------------------------------------------------------------*/
00139 /*-----------------------------------------------------------------------------------*/
00140 void
00141 uip_arp_init(void)
00142 {
00143   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00144     memset(arp_table[i].ipaddr, 0, 4);
00145   }
00146 }
00147 /*-----------------------------------------------------------------------------------*/
00156 /*-----------------------------------------------------------------------------------*/
00157 void
00158 uip_arp_timer(void)
00159 {
00160   struct arp_entry *tabptr;
00161 
00162   ++arptime;
00163   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00164     tabptr = &arp_table[i];
00165     if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 &&
00166        arptime - tabptr->time >= UIP_ARP_MAXAGE) {
00167       memset(tabptr->ipaddr, 0, 4);
00168     }
00169   }
00170 
00171 }
00172 /*-----------------------------------------------------------------------------------*/
00173 static void
00174 uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
00175 {
00176   register struct arp_entry *tabptr;
00177   /* Walk through the ARP mapping table and try to find an entry to
00178      update. If none is found, the IP -> MAC address mapping is
00179      inserted in the ARP table. */
00180   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00181 
00182     tabptr = &arp_table[i];
00183     /* Only check those entries that are actually in use. */
00184     if(tabptr->ipaddr[0] != 0 &&
00185        tabptr->ipaddr[1] != 0) {
00186 
00187       /* Check if the source IP address of the incoming packet matches
00188          the IP address in this ARP table entry. */
00189       if(ipaddr[0] == tabptr->ipaddr[0] &&
00190          ipaddr[1] == tabptr->ipaddr[1]) {
00191         
00192         /* An old entry found, update this and return. */
00193         memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
00194         tabptr->time = arptime;
00195 
00196         return;
00197       }
00198     }
00199   }
00200 
00201   /* If we get here, no existing ARP table entry was found, so we
00202      create one. */
00203 
00204   /* First, we try to find an unused entry in the ARP table. */
00205   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00206     tabptr = &arp_table[i];
00207     if(tabptr->ipaddr[0] == 0 &&
00208        tabptr->ipaddr[1] == 0) {
00209       break;
00210     }
00211   }
00212 
00213   /* If no unused entry is found, we try to find the oldest entry and
00214      throw it away. */
00215   if(i == UIP_ARPTAB_SIZE) {
00216     tmpage = 0;
00217     c = 0;
00218     for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00219       tabptr = &arp_table[i];
00220       if(arptime - tabptr->time > tmpage) {
00221         tmpage = arptime - tabptr->time;
00222         c = i;
00223       }
00224     }
00225     i = c;
00226     tabptr = &arp_table[i];
00227   }
00228 
00229   /* Now, i is the ARP table entry which we will fill with the new
00230      information. */
00231   memcpy(tabptr->ipaddr, ipaddr, 4);
00232   memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
00233   tabptr->time = arptime;
00234 }
00235 /*-----------------------------------------------------------------------------------*/
00248 /*-----------------------------------------------------------------------------------*/
00249 #if 1
00250 void
00251 uip_arp_ipin(void)
00252 {
00253   uip_len -= sizeof(struct uip_eth_hdr);
00254         
00255   /* Only insert/update an entry if the source IP address of the
00256      incoming IP packet comes from a host on the local network. */
00257   if((IPBUF->srcipaddr[0] & uip_netmask[0]) !=
00258      (uip_hostaddr[0] & uip_netmask[0])) {
00259     return;
00260   }
00261   if((IPBUF->srcipaddr[1] & uip_netmask[1]) !=
00262      (uip_hostaddr[1] & uip_netmask[1])) {
00263     return;
00264   }
00265   uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
00266 
00267   return;
00268 }
00269 #endif /* 0 */
00270 /*-----------------------------------------------------------------------------------*/
00292 /*-----------------------------------------------------------------------------------*/
00293 void
00294 uip_arp_arpin(void)
00295 {
00296 
00297   if(uip_len < sizeof(struct arp_hdr)) {
00298     uip_len = 0;
00299     return;
00300   }
00301   uip_len = 0;
00302 
00303   switch(BUF->opcode) {
00304   case HTONS(ARP_REQUEST):
00305     /* ARP request. If it asked for our address, we send out a
00306        reply. */
00307     if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
00308       /* First, we register the one who made the request in our ARP
00309          table, since it is likely that we will do more communication
00310          with this host in the future. */
00311       uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
00312 
00313       /* The reply opcode is 2. */
00314       BUF->opcode = HTONS(2);
00315 
00316       memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
00317       memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
00318       memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
00319       memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
00320 
00321       BUF->dipaddr[0] = BUF->sipaddr[0];
00322       BUF->dipaddr[1] = BUF->sipaddr[1];
00323       BUF->sipaddr[0] = uip_hostaddr[0];
00324       BUF->sipaddr[1] = uip_hostaddr[1];
00325 
00326       BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
00327       uip_len = sizeof(struct arp_hdr);
00328     }
00329     break;
00330   case HTONS(ARP_REPLY):
00331     /* ARP reply. We insert or update the ARP table if it was meant
00332        for us. */
00333     if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
00334       uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
00335     }
00336     break;
00337   }
00338 
00339   return;
00340 }
00341 /*-----------------------------------------------------------------------------------*/
00368 /*-----------------------------------------------------------------------------------*/
00369 void
00370 uip_arp_out(void)
00371 {
00372   struct arp_entry *tabptr;
00373 
00374   /* Find the destination IP address in the ARP table and construct
00375      the Ethernet header. If the destination IP addres isn't on the
00376      local network, we use the default router's IP address instead.
00377 
00378      If not ARP table entry is found, we overwrite the original IP
00379      packet with an ARP request for the IP address. */
00380 
00381   /* First check if destination is a local broadcast. */
00382   if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) {
00383     memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
00384   } else {
00385     /* Check if the destination address is on the local network. */
00386     if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) {
00387       /* Destination address was not on the local network, so we need to
00388          use the default router's IP address instead of the destination
00389          address when determining the MAC address. */
00390       uip_ipaddr_copy(ipaddr, uip_draddr);
00391     } else {
00392       /* Else, we use the destination IP address. */
00393       uip_ipaddr_copy(ipaddr, IPBUF->destipaddr);
00394     }
00395 
00396     for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00397       tabptr = &arp_table[i];
00398       if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) {
00399         break;
00400       }
00401     }
00402 
00403     if(i == UIP_ARPTAB_SIZE) {
00404       /* The destination address was not in our ARP table, so we
00405          overwrite the IP packet with an ARP request. */
00406 
00407       memset(BUF->ethhdr.dest.addr, 0xff, 6);
00408       memset(BUF->dhwaddr.addr, 0x00, 6);
00409       memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
00410       memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
00411 
00412       uip_ipaddr_copy(BUF->dipaddr, ipaddr);
00413       uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);
00414       BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */
00415       BUF->hwtype = HTONS(ARP_HWTYPE_ETH);
00416       BUF->protocol = HTONS(UIP_ETHTYPE_IP);
00417       BUF->hwlen = 6;
00418       BUF->protolen = 4;
00419       BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
00420 
00421       uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];
00422 
00423       uip_len = sizeof(struct arp_hdr);
00424       return;
00425     }
00426 
00427     /* Build an ethernet header. */
00428     memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
00429   }
00430   memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
00431 
00432   IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);
00433 
00434   uip_len += sizeof(struct uip_eth_hdr);
00435 }
00436 /*-----------------------------------------------------------------------------------*/
00437