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  * This file is part of the lwIP TCP/IP stack.
00030  * 
00031  * Author: Adam Dunkels <adam@sics.se>
00032  *
00033  * $Id: arp_8c-source.html 88 2016-01-12 00:11:29Z reddawg $
00034  *
00035  */
00036 
00037 #include <ubixos/types.h>
00038 #include <lib/kprintf.h>
00039 
00040 #include "net/debug.h"
00041 #include "net/ipv4/inet.h"
00042 #include "netif/arp.h"
00043 #include "net/ipv4/ip.h"
00044 
00045 
00046 #define ARP_MAXAGE 2  /* 120 * 10 seconds = 20 minutes. */
00047 
00048 #define HWTYPE_ETHERNET 1
00049 
00050 #define ARP_REQUEST 1
00051 #define ARP_REPLY 2
00052 
00053 /* MUST be compiled with "pack structs" or equivalent! */
00054 PACK_STRUCT_BEGIN
00055 struct arp_hdr {
00056   PACK_STRUCT_FIELD(struct eth_hdr ethhdr);
00057   PACK_STRUCT_FIELD(uInt16 hwtype);
00058   PACK_STRUCT_FIELD(uInt16 proto);
00059   PACK_STRUCT_FIELD(uInt16 _hwlen_protolen);
00060   PACK_STRUCT_FIELD(uInt16 opcode);
00061   PACK_STRUCT_FIELD(struct eth_addr shwaddr);
00062   PACK_STRUCT_FIELD(struct ip_addr sipaddr);
00063   PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
00064   PACK_STRUCT_FIELD(struct ip_addr dipaddr);
00065 } PACK_STRUCT_STRUCT;
00066 PACK_STRUCT_END
00067 
00068 #define ARPH_HWLEN(hdr) (NTOHS((hdr)->_hwlen_protolen) >> 8)
00069 #define ARPH_PROTOLEN(hdr) (NTOHS((hdr)->_hwlen_protolen) & 0xff)
00070 
00071 
00072 #define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = HTONS(ARPH_PROTOLEN(hdr) | ((len) << 8))
00073 #define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = HTONS((len) | (ARPH_HWLEN(hdr) << 8))
00074 
00075 PACK_STRUCT_BEGIN
00076 struct ethip_hdr {
00077   PACK_STRUCT_FIELD(struct eth_hdr eth);
00078   PACK_STRUCT_FIELD(struct ip_hdr ip);
00079 };
00080 PACK_STRUCT_END
00081 
00082 struct arp_entry {
00083   struct ip_addr ipaddr;
00084   struct eth_addr ethaddr;
00085   uInt8 ctime;
00086 };
00087 
00088 static struct arp_entry arp_table[ARP_TABLE_SIZE];
00089 static uInt8 ctime;
00090 
00091 /*-----------------------------------------------------------------------------------*/
00092 void
00093 arp_init(void)
00094 {
00095   uInt8 i;
00096   
00097   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00098     ip_addr_set(&(arp_table[i].ipaddr),
00099                 IP_ADDR_ANY);
00100   }
00101 }
00102 /*-----------------------------------------------------------------------------------*/
00103 void
00104 arp_tmr(void)
00105 {
00106   uInt8 i;
00107   
00108   ++ctime;
00109   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00110     if(!ip_addr_isany(&arp_table[i].ipaddr) &&       
00111        ctime - arp_table[i].ctime >= ARP_MAXAGE) {
00112       DEBUGF(ARP_DEBUG, ("arp_timer: expired entry %d.\n", i));
00113       ip_addr_set(&(arp_table[i].ipaddr),
00114                   IP_ADDR_ANY);
00115     }
00116   }  
00117 }
00118 /*-----------------------------------------------------------------------------------*/
00119 static void
00120 add_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr)
00121 {
00122   uInt8 i, j, k;
00123   uInt8 maxtime;
00124   
00125   /* Walk through the ARP mapping table and try to find an entry to
00126      update. If none is found, the IP -> MAC address mapping is
00127      inserted in the ARP table. */
00128   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00129     
00130     /* Only check those entries that are actually in use. */
00131     if(!ip_addr_isany(&arp_table[i].ipaddr)) {
00132       /* Check if the source IP address of the incoming packet matches
00133          the IP address in this ARP table entry. */
00134       if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
00135         /* An old entry found, update this and return. */
00136         for(k = 0; k < 6; ++k) {
00137           arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
00138         }
00139         arp_table[i].ctime = ctime;
00140         return;
00141       }
00142     }
00143   }
00144 
00145   /* If we get here, no existing ARP table entry was found, so we
00146      create one. */
00147 
00148   /* First, we try to find an unused entry in the ARP table. */
00149   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00150     if(ip_addr_isany(&arp_table[i].ipaddr)) {
00151       break;
00152     }
00153   }
00154 
00155   /* If no unused entry is found, we try to find the oldest entry and
00156      throw it away. */
00157   if(i == ARP_TABLE_SIZE) {
00158     maxtime = 0;
00159     j = 0;
00160     for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00161       if(ctime - arp_table[i].ctime > maxtime) {
00162         maxtime = ctime - arp_table[i].ctime;
00163         j = i;
00164       }
00165     }
00166     i = j;
00167   }
00168 
00169   /* Now, i is the ARP table entry which we will fill with the new
00170      information. */
00171   ip_addr_set(&arp_table[i].ipaddr, ipaddr);
00172   for(k = 0; k < 6; ++k) {
00173     arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
00174   }
00175   arp_table[i].ctime = ctime;
00176   return;
00177 
00178 }
00179 /*-----------------------------------------------------------------------------------*/
00180 void
00181 arp_ip_input(struct netif *netif, struct pbuf *p)
00182 {
00183   struct ethip_hdr *hdr;
00184   
00185   hdr = p->payload;
00186   
00187   /* Only insert/update an entry if the source IP address of the
00188      incoming IP packet comes from a host on the local network. */
00189   if(!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
00190     return;
00191   }
00192   DEBUGF(ARP_DEBUG, ("arp_ip_input: updating ARP table.\n"));
00193   add_arp_entry(&(hdr->ip.src), &(hdr->eth.src));
00194 }
00195 /*-----------------------------------------------------------------------------------*/
00196 struct pbuf *
00197 arp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
00198 {
00199   struct arp_hdr *hdr;
00200   uInt8 i;
00201   
00202   if(p->tot_len < sizeof(struct arp_hdr)) {
00203     kprintf("arp_arp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct arp_hdr));
00204     pbuf_free(p);
00205     return NULL;
00206   }
00207 
00208   hdr = p->payload;
00209   
00210   switch(htons(hdr->opcode)) {
00211   case ARP_REQUEST:
00212     /* ARP request. If it asked for our address, we send out a
00213        reply. */
00214     if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) {
00215       hdr->opcode = htons(ARP_REPLY);
00216 
00217       ip_addr_set(&(hdr->dipaddr), &(hdr->sipaddr));
00218       ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));
00219 
00220       for(i = 0; i < 6; ++i) {
00221         hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
00222         hdr->shwaddr.addr[i] = ethaddr->addr[i];
00223         hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];
00224         hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
00225       }
00226 
00227       hdr->hwtype = htons(HWTYPE_ETHERNET);
00228       ARPH_HWLEN_SET(hdr, 6);
00229       
00230       hdr->proto = htons(ETHTYPE_IP);
00231       ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));      
00232       
00233       hdr->ethhdr.type = htons(ETHTYPE_ARP);      
00234       return p;
00235     }
00236     break;
00237   case ARP_REPLY:    
00238     /* ARP reply. We insert or update the ARP table. */
00239     if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) {
00240       add_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr));
00241     }
00242     break;
00243   default:
00244     kprintf("arp_arp_input: unknown type %d\n", htons(hdr->opcode));
00245     break;
00246   }
00247 
00248   pbuf_free(p);
00249   return NULL;
00250 }
00251 /*-----------------------------------------------------------------------------------*/
00252 struct eth_addr *
00253 arp_lookup(struct ip_addr *ipaddr)
00254 {
00255   uInt8 i;
00256   
00257   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00258     if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
00259       return &arp_table[i].ethaddr;
00260     }
00261   }
00262   return NULL;  
00263 }
00264 /*-----------------------------------------------------------------------------------*/
00265 struct pbuf *
00266 arp_query(struct netif *netif, struct eth_addr *ethaddr, struct ip_addr *ipaddr)
00267 {
00268   struct arp_hdr *hdr;
00269   struct pbuf *p;
00270   uInt8 i;
00271 
00272   p = pbuf_alloc(PBUF_LINK, sizeof(struct arp_hdr), PBUF_RAM);
00273   if(p == NULL) {
00274     return NULL;
00275   }
00276 
00277   hdr = p->payload;
00278   
00279   hdr->opcode = htons(ARP_REQUEST);
00280 
00281   for(i = 0; i < 6; ++i) {
00282     hdr->dhwaddr.addr[i] = 0x00;
00283     hdr->shwaddr.addr[i] = ethaddr->addr[i];
00284   }
00285   
00286   ip_addr_set(&(hdr->dipaddr), ipaddr);
00287   ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));
00288 
00289   hdr->hwtype = htons(HWTYPE_ETHERNET);
00290   ARPH_HWLEN_SET(hdr, 6);
00291 
00292   hdr->proto = htons(ETHTYPE_IP);
00293   ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
00294 
00295   for(i = 0; i < 6; ++i) {
00296     hdr->ethhdr.dest.addr[i] = 0xff;
00297     hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
00298   }
00299   
00300   hdr->ethhdr.type = htons(ETHTYPE_ARP);      
00301   return p;
00302 }
00303 /*-----------------------------------------------------------------------------------*/
00304 
00305 
00306 
00307 

Generated on Tue Dec 12 08:52:07 2006 for UbixOS V2 by  doxygen 1.4.7