# 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