Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

arp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001, Swedish Institute of Computer Science.
00003  * All rights reserved. 
00004  *
00005  * Redistribution and use in source and binary forms, with or without 
00006  * modification, are permitted provided that the following conditions 
00007  * are met: 
00008  * 1. Redistributions of source code must retain the above copyright 
00009  *    notice, this list of conditions and the following disclaimer. 
00010  * 2. Redistributions in binary form must reproduce the above copyright 
00011  *    notice, this list of conditions and the following disclaimer in the 
00012  *    documentation and/or other materials provided with the distribution. 
00013  * 3. Neither the name of the Institute nor the names of its contributors 
00014  *    may be used to endorse or promote products derived from this software 
00015  *    without specific prior written permission. 
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00027  * SUCH DAMAGE. 
00028  * 
00029  * arp.c
00030  *                     
00031  * Author : Adam Dunkels <adam@sics.se>                               
00032  *
00033  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00034  *            Departamento de Informática de Sistemas y Computadores          
00035  *            Universidad Politécnica de Valencia                             
00036  *            Valencia (Spain)    
00037  *            Date: April 2003                                          
00038  *  
00039  */
00040 
00041 #include "lwip/inet.h"
00042 #include "netif/arp.h"
00043 #include "lwip/ip.h"
00044 
00045 #if LWIP_DHCP
00046 #  include "lwip/dhcp.h"
00047 #endif
00048 
00049 
00050 #define ARP_MAXAGE 2  /* 120 * 10 seconds = 20 minutes. */
00051 
00052 #define HWTYPE_ETHERNET 1
00053 
00054 #define ARP_REQUEST 1
00055 #define ARP_REPLY 2
00056 #define htons HTONS
00057 #define htonl HTONL
00058 
00059 /* MUST be compiled with "pack structs" or equivalent! */
00060 PACK_STRUCT_BEGIN
00061 struct arp_hdr {
00062   PACK_STRUCT_FIELD(struct eth_hdr ethhdr);
00063   PACK_STRUCT_FIELD(u16_t hwtype);
00064   PACK_STRUCT_FIELD(u16_t proto);
00065   PACK_STRUCT_FIELD(u16_t _hwlen_protolen);
00066   PACK_STRUCT_FIELD(u16_t opcode);
00067   PACK_STRUCT_FIELD(struct eth_addr shwaddr);
00068   PACK_STRUCT_FIELD(struct ip_addr sipaddr);
00069   PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
00070   PACK_STRUCT_FIELD(struct ip_addr dipaddr);
00071 } PACK_STRUCT_STRUCT;
00072 PACK_STRUCT_END
00073 
00074 #define ARPH_HWLEN(hdr) (NTOHS((hdr)->_hwlen_protolen) >> 8)
00075 #define ARPH_PROTOLEN(hdr) (NTOHS((hdr)->_hwlen_protolen) & 0xff)
00076 
00077 
00078 #define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = HTONS(ARPH_PROTOLEN(hdr) | ((len) << 8))
00079 #define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = HTONS((len) | (ARPH_HWLEN(hdr) << 8))
00080 
00081 PACK_STRUCT_BEGIN
00082 struct ethip_hdr {
00083   PACK_STRUCT_FIELD(struct eth_hdr eth);
00084   PACK_STRUCT_FIELD(struct ip_hdr ip);
00085 };
00086 PACK_STRUCT_END
00087 
00088 struct arp_entry {
00089   struct ip_addr ipaddr;
00090   struct eth_addr ethaddr;
00091   u8_t ctime;
00092 };
00093 
00094 static struct arp_entry arp_table[ARP_TABLE_SIZE];
00095 static u8_t ctime;
00096 
00097 /*-----------------------------------------------------------------------------------*/
00098 u8_t get_u8_t_from_char(char c,int low){
00099 
00100   if(low){
00101     /* a-z */
00102     if((c >= 97) && (c <= 122)) return (c-87);
00103     /* A-Z */
00104     else if((c >= 65) && (c <= 90)) return (c-55);
00105     /* 0-9 */
00106     else if((c >= 48) && (c <= 57)) return (c-48);
00107   }else{ /* !low */
00108     /* a-z */
00109     if((c >= 97) && (c <= 122)) return ((c-87)<<4);
00110     /* A-Z */
00111     else if((c >= 65) && (c <= 90)) return ((c-55)<<4);
00112     /* 0-9 */
00113     else if((c >= 48) && (c <= 57)) return ((c-48)<<4);
00114   }
00115   return -1;
00116 }
00117 
00118 /*-----------------------------------------------------------------------------------*/
00119 unsigned char get_char_from_u8_t(u8_t value){
00120   if(value < 10){
00121     return (unsigned char)(value + 48); //48 is the ascii code for '0'
00122   }else{
00123     return (unsigned char)(value + 55); //65 would be the ascii code for 'A'
00124   }
00125 }
00126 
00127 /*-----------------------------------------------------------------------------------*/
00128 void string2mac(struct eth_addr *mac, char *name){
00129   int i,hop=0;
00130 
00131   for(i=0; i<6; i++){
00132     mac->addr[i] = get_u8_t_from_char(name[hop],0) + get_u8_t_from_char(name[hop+1],1);
00133     hop+=3;
00134   }
00135 }
00136 
00137 /*-----------------------------------------------------------------------------------*/
00138 void mac2string(struct eth_addr *mac, char *name){
00139   int i,hop=0;
00140   u8_t aux;
00141 
00142   for(i=0; i<5; i++){
00143     aux = mac->addr[i];
00144     name[hop] = get_char_from_u8_t((aux & 0xf0)>>4);
00145     name[hop+1] = get_char_from_u8_t((aux & 0x0f));
00146     name[hop+2] = 0x3a; //0x3a is the code ascii (in hex) for ':'
00147     hop+=3;
00148   }
00149   name[hop] = get_char_from_u8_t((mac->addr[5] & 0xf0)>>4);
00150   name[hop+1] = get_char_from_u8_t((mac->addr[5] & 0x0f));
00151 }
00152 
00153 /*-----------------------------------------------------------------------------------*/
00154 void
00155 arp_init(void)
00156 {
00157   u8_t i;
00158   
00159   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00160     ip_addr_set(&(arp_table[i].ipaddr),
00161                 IP_ADDR_ANY);
00162   }
00163 }
00164 /*-----------------------------------------------------------------------------------*/
00165 void
00166 arp_tmr(void)
00167 {
00168   u8_t i;
00169   
00170   ++ctime;
00171   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00172     if(!ip_addr_isany(&arp_table[i].ipaddr) &&       
00173        ctime - arp_table[i].ctime >= ARP_MAXAGE) {
00174       ip_addr_set(&(arp_table[i].ipaddr),
00175                   IP_ADDR_ANY);
00176     }
00177   }  
00178 }
00179 /*-----------------------------------------------------------------------------------*/
00180 static void
00181 add_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr)
00182 {
00183   u8_t i, j, k;
00184   u8_t maxtime;
00185   
00186   /* Walk through the ARP mapping table and try to find an entry to
00187      update. If none is found, the IP -> MAC address mapping is
00188      inserted in the ARP table. */
00189   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00190     
00191     /* Only check those entries that are actually in use. */
00192     if(!ip_addr_isany(&arp_table[i].ipaddr)) {
00193       /* Check if the source IP address of the incoming packet matches
00194          the IP address in this ARP table entry. */
00195       if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
00196         /* An old entry found, update this and return. */
00197         for(k = 0; k < 6; ++k) {
00198           arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
00199         }
00200         arp_table[i].ctime = ctime;
00201         return;
00202       }
00203     }
00204   }
00205 
00206   /* If we get here, no existing ARP table entry was found, so we
00207      create one. */
00208 
00209   /* First, we try to find an unused entry in the ARP table. */
00210   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00211     if(ip_addr_isany(&arp_table[i].ipaddr)) {
00212       break;
00213     }
00214   }
00215 
00216   /* If no unused entry is found, we try to find the oldest entry and
00217      throw it away. */
00218   if(i == ARP_TABLE_SIZE) {
00219     maxtime = 0;
00220     j = 0;
00221     for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00222       if(ctime - arp_table[i].ctime > maxtime) {
00223         maxtime = ctime - arp_table[i].ctime;
00224         j = i;
00225       }
00226     }
00227     i = j;
00228   }
00229 
00230   /* Now, i is the ARP table entry which we will fill with the new
00231      information. */
00232   ip_addr_set(&arp_table[i].ipaddr, ipaddr);
00233   for(k = 0; k < 6; ++k) {
00234     arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
00235   }
00236   arp_table[i].ctime = ctime;
00237   return;
00238 
00239 }
00240 /*-----------------------------------------------------------------------------------*/
00241 void
00242 arp_ip_input(struct netif *netif, struct pbuf *p)
00243 {
00244   struct ethip_hdr *hdr;
00245   
00246   hdr = p->payload;
00247   
00248   /* Only insert/update an entry if the source IP address of the
00249      incoming IP packet comes from a host on the local network. */
00250   if(!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
00251     return;
00252   }
00253   add_arp_entry(&(hdr->ip.src), &(hdr->eth.src));
00254 }
00255 /*-----------------------------------------------------------------------------------*/
00256 struct pbuf *
00257 arp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
00258 {
00259   struct arp_hdr *hdr;
00260   u8_t i;
00261   
00262   if(p->tot_len < sizeof(struct arp_hdr)) {
00263 
00264     pbuf_free(p);
00265     return NULL;
00266   }
00267 
00268   hdr = p->payload;
00269   
00270   switch(htons(hdr->opcode)) {
00271   case ARP_REQUEST:
00272     /* ARP request. If it asked for our address, we send out a
00273        reply. */
00274 
00275     if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) {
00276       hdr->opcode = htons(ARP_REPLY);
00277 
00278       ip_addr_set(&(hdr->dipaddr), &(hdr->sipaddr));
00279       ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));
00280 
00281       for(i = 0; i < 6; ++i) {
00282         hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
00283         hdr->shwaddr.addr[i] = ethaddr->addr[i];
00284         hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];
00285         hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
00286       }
00287 
00288       hdr->hwtype = htons(HWTYPE_ETHERNET);
00289       ARPH_HWLEN_SET(hdr, 6);
00290       
00291       hdr->proto = htons(ETHTYPE_IP);
00292       ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));      
00293       
00294       hdr->ethhdr.type = htons(ETHTYPE_ARP);      
00295       return p;
00296     }
00297     break;
00298   case ARP_REPLY:    
00299     /* ARP reply. We insert or update the ARP table. */
00300 
00301     if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) {
00302       add_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr));
00303 #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
00304       dhcp_arp_reply(&hdr->sipaddr);
00305 #endif      
00306     }
00307     break;
00308   default:
00309 
00310     break;
00311   }
00312 
00313   pbuf_free(p);
00314   return NULL;
00315 }
00316 /*-----------------------------------------------------------------------------------*/
00317 struct eth_addr *
00318 arp_lookup(struct ip_addr *ipaddr)
00319 {
00320   u8_t i;
00321   
00322   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00323     if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
00324       return &arp_table[i].ethaddr;
00325     }
00326   }
00327   return NULL;  
00328 }
00329 /*-----------------------------------------------------------------------------------*/
00330 struct pbuf *
00331 arp_query(struct netif *netif, struct eth_addr *ethaddr, struct ip_addr *ipaddr)
00332 {
00333   struct arp_hdr *hdr;
00334   struct pbuf *p;
00335   u8_t i;
00336 
00337   p = pbuf_alloc(PBUF_LINK, sizeof(struct arp_hdr), PBUF_RAM);
00338   if(p == NULL) {
00339     return NULL;
00340   }
00341 
00342   hdr = p->payload;
00343   
00344   hdr->opcode = htons(ARP_REQUEST);
00345 
00346   for(i = 0; i < 6; ++i) {
00347     hdr->dhwaddr.addr[i] = 0x00;
00348     hdr->shwaddr.addr[i] = ethaddr->addr[i];
00349   }
00350   
00351   ip_addr_set(&(hdr->dipaddr), ipaddr);
00352   ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));
00353 
00354   hdr->hwtype = htons(HWTYPE_ETHERNET);
00355   ARPH_HWLEN_SET(hdr, 6);
00356 
00357   hdr->proto = htons(ETHTYPE_IP);
00358   ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
00359 
00360   for(i = 0; i < 6; ++i) {
00361     hdr->ethhdr.dest.addr[i] = 0xff;
00362     hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
00363   }
00364   
00365   hdr->ethhdr.type = htons(ETHTYPE_ARP);      
00366   return p;
00367 }
00368 /*-----------------------------------------------------------------------------------*/
00369 
00370 
00371 
00372 

Generated on Wed Jan 14 12:58:56 2004 for RTL-lwIP-0.4 by doxygen 1.3.4