root/net/tcp/arp.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. send_arp_q
  2. print_arp
  3. arp_sourceh
  4. arp_targeth
  5. arp_sourcep
  6. arp_targetp
  7. arp_free
  8. arp_malloc
  9. arp_response
  10. arp_lookup
  11. arp_destroy
  12. create_arp
  13. arp_rcv
  14. arp_snd
  15. arp_find
  16. arp_add
  17. arp_add_broad
  18. arp_queue

   1 /* arp.c */
   2 /*
   3     Copyright (C) 1992  Ross Biro
   4 
   5     This program is free software; you can redistribute it and/or modify
   6     it under the terms of the GNU General Public License as published by
   7     the Free Software Foundation; either version 2, or (at your option)
   8     any later version.
   9 
  10     This program is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13     GNU General Public License for more details.
  14 
  15     You should have received a copy of the GNU General Public License
  16     along with this program; if not, write to the Free Software
  17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  18 
  19     The Author may be reached as bir7@leland.stanford.edu or
  20     C/O Department of Mathematics; Stanford University; Stanford, CA 94305
  21 */
  22 /* $Id: arp.c,v 0.8.4.2 1992/11/10 10:38:48 bir7 Exp $ */
  23 /* $Log: arp.c,v $
  24  * Revision 0.8.4.2  1992/11/10  10:38:48  bir7
  25  * Change free_s to kfree_s and accidently changed free_skb to kfree_skb.
  26  *
  27  * Revision 0.8.4.1  1992/11/10  00:17:18  bir7
  28  * version change only.
  29  *
  30  * Revision 0.8.3.3  1992/11/10  00:14:47  bir7
  31  * Changed malloc to kmalloc and added $iId$
  32  *
  33  */
  34 
  35 #include <linux/types.h>
  36 #include <linux/string.h>
  37 #include <linux/kernel.h>
  38 #include <linux/sched.h>
  39 
  40 #include <linux/socket.h>
  41 #include <netinet/in.h>
  42 #include <asm/system.h>
  43 
  44 #include "timer.h"
  45 #include "ip.h"
  46 #include "tcp.h"
  47 #include "sock.h"
  48 #include "arp.h"
  49 
  50 #undef ARP_DEBUG
  51 #ifdef  ARP_DEBUG
  52 #define PRINTK printk
  53 #else
  54 #define PRINTK dummy_routine
  55 #endif
  56 
  57 static struct arp_table *arp_table[ARP_TABLE_SIZE] ={NULL, };
  58 static struct sk_buff *arp_q=NULL;
  59 
  60 /* this will try to retransmit everything on the queue. */
  61 static void
  62 send_arp_q(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64    struct sk_buff *skb;
  65    if (arp_q == NULL) return;
  66 
  67    skb = arp_q;
  68    do {
  69       if (!skb->dev->rebuild_header (skb+1, skb->dev))
  70         {
  71            if (skb->next == skb)
  72              {
  73                 arp_q = NULL;
  74              }
  75            else
  76              {
  77                 skb->next->prev = skb->prev;
  78                 skb->prev->next = skb->next;
  79                 arp_q = skb->next;
  80              }
  81            skb->next = NULL;
  82            skb->prev = NULL;
  83            skb->arp  = 1;
  84            skb->dev->queue_xmit (skb, skb->dev, 0);
  85            if (arp_q == NULL) break;
  86            skb = arp_q;
  87            continue;
  88         }
  89       skb=skb->next;
  90    } while (skb != arp_q);
  91 
  92 }
  93 
  94 static  void
  95 print_arp(struct arp *arp)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97   int i;
  98   unsigned long *lptr;
  99   unsigned char *ptr;
 100   PRINTK ("arp: \n");
 101   PRINTK ("   hrd = %d\n",net16(arp->hrd));
 102   PRINTK ("   pro = %d\n",net16(arp->pro));
 103   PRINTK ("   hlen = %d plen = %d\n",arp->hlen, arp->plen);
 104   PRINTK ("   op = %d\n", net16(arp->op));
 105   ptr = (unsigned char *)(arp+1);
 106   PRINTK ("   sender haddr = ");
 107   for (i = 0; i < arp->hlen; i++)
 108     {
 109       PRINTK ("0x%02X ",*ptr++);
 110     }
 111   lptr = (void *)ptr;
 112   PRINTK (" send paddr = %X\n",*lptr);
 113   lptr ++;
 114   ptr = (void *)lptr;
 115   PRINTK ("   destination haddr = ");
 116   for (i = 0; i < arp->hlen; i++)
 117     {
 118       PRINTK ("0x%02X ",*ptr++);
 119     }
 120   lptr = (void *)ptr;
 121   PRINTK (" destination paddr = %X\n",*lptr);
 122 }
 123 
 124 static  unsigned char *
 125 arp_sourceh(struct arp *arp)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127   unsigned char *ptr;
 128   ptr = (unsigned char *)(arp + 1);
 129   return (ptr);
 130 }
 131 
 132 static  unsigned char *
 133 arp_targeth(struct arp *arp)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135   unsigned char *ptr;
 136   ptr = (unsigned char *)(arp + 1);
 137   ptr += arp->hlen+4;
 138   return (ptr);
 139 }
 140 
 141 static  unsigned long *
 142 arp_sourcep(struct arp *arp)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144   unsigned long *lptr;
 145   unsigned char *ptr;
 146   ptr = (unsigned char *)(arp + 1);
 147   ptr += arp->hlen;
 148   lptr = (unsigned long *)ptr;
 149   return (lptr);
 150 }
 151 
 152 
 153 static  unsigned long *
 154 arp_targetp(struct arp *arp)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156   unsigned long *lptr;
 157   unsigned char *ptr;
 158   ptr = (unsigned char *)(arp + 1);
 159   ptr += 2*arp->hlen+4;
 160   lptr = (unsigned long *)ptr;
 161   return (lptr);
 162 }
 163 
 164 static  void
 165 arp_free (void *ptr, unsigned long len)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167   kfree_s(ptr, len);
 168 }
 169 
 170 static  void *
 171 arp_malloc (unsigned long amount, int priority)
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173   return (kmalloc (amount, priority));
 174 }
 175 
 176 static  int
 177 arp_response (struct arp *arp1, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179   struct arp *arp2;
 180   struct sk_buff *skb;
 181   int tmp;
 182 
 183   /* get some mem and initialize it for the return trip. */
 184   skb = arp_malloc (sizeof (*skb) + sizeof (*arp2) +
 185                     2*arp1->hlen + 2*arp1->plen + dev->hard_header_len,
 186                     GFP_ATOMIC);
 187   if (skb == NULL) return (1);
 188 
 189   skb->mem_addr = skb;
 190   skb->mem_len = sizeof (*skb) + sizeof (*arp2) + 2*arp1->hlen + 
 191     2*arp1->plen + dev->hard_header_len;
 192   skb->len = sizeof (*arp2) + 2*arp1->hlen + 
 193     2*arp1->plen + dev->hard_header_len;
 194 
 195   tmp = dev->hard_header((unsigned char *)(skb+1), dev,
 196                          ETHERTYPE_ARP, *arp_sourcep(arp1),
 197                          *arp_targetp(arp1),skb->len);
 198 
 199   if (tmp < 0) return (1);
 200 
 201   arp2 =(struct arp *) ((unsigned char *)skb+sizeof (*skb) + tmp );
 202   memcpy (arp2, arp1, sizeof (*arp2));
 203 
 204   /* now swap the addresses. */
 205   *arp_sourcep(arp2) = *arp_targetp(arp1);
 206   memcpy(arp_sourceh(arp2), dev->dev_addr, arp1->hlen);
 207 
 208   *arp_targetp(arp2) = *arp_sourcep(arp1);
 209   memcpy(arp_targeth(arp2), arp_sourceh(arp1), arp1->hlen);
 210 
 211   arp2->op = NET16(ARP_REPLY);
 212   skb->free = 1;
 213   skb->arp = 1; /* so the code will know it's not waiting on an arp. */
 214   skb->sk = NULL;
 215   skb->next = NULL;
 216   PRINTK (">>");
 217   print_arp(arp2);
 218   /* send it. */
 219   dev->queue_xmit (skb, dev, 0);
 220   return (0);
 221 }
 222 
 223 /* This will find an entry in the arp table by looking at the ip
 224    address. */
 225 static  struct arp_table *
 226 arp_lookup (unsigned long paddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228   unsigned long hash;
 229   struct arp_table *apt;
 230   PRINTK ("arp_lookup(paddr=%X)\n", paddr);
 231   /* we don't want to arp ourselves. */
 232   if (my_ip_addr(paddr)) return (NULL);
 233   hash = net32(paddr) & (ARP_TABLE_SIZE - 1);
 234   cli();
 235   for (apt = arp_table[hash]; apt != NULL; apt = apt->next)
 236     {
 237       if (apt->ip == paddr)
 238         {
 239            sti();
 240            return (apt);
 241         }
 242     }
 243   sti();
 244   return (NULL);
 245 }
 246 
 247 void
 248 arp_destroy(unsigned long paddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250   unsigned long hash;
 251   struct arp_table *apt;
 252   struct arp_table *lapt;
 253   PRINTK ("arp_destroy (paddr=%X)\n",paddr);
 254   /* we don't want to destroy are own arp */
 255   if (my_ip_addr(paddr)) return;
 256   hash = net32(paddr) & (ARP_TABLE_SIZE - 1);
 257 
 258   cli(); /* can't be interrupted. */
 259   /* make sure there is something there. */
 260   if (arp_table[hash] == NULL) return;
 261 
 262   /* check the first one. */
 263   if (arp_table[hash]->ip == paddr)
 264     {
 265       apt = arp_table[hash];
 266       arp_table[hash] = arp_table[hash]->next;
 267       arp_free (apt, sizeof (*apt));
 268       sti();
 269       return;
 270     }
 271 
 272   /* now deal with it any where else in the chain. */
 273   lapt = arp_table[hash];
 274   for (apt = arp_table[hash]->next; apt != NULL; apt = apt->next)
 275     {
 276       if (apt->ip == paddr) 
 277         {
 278           lapt->next = apt->next;
 279           arp_free (apt, sizeof (*apt));
 280           sti();
 281           return;
 282         }
 283     }
 284   sti();
 285 }
 286 
 287 /* this routine does not check for duplicates.  It assumes the caller
 288    does. */
 289 static  struct arp_table *
 290 create_arp (unsigned long paddr, unsigned char *addr, int hlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292   struct arp_table *apt;
 293   unsigned long hash;
 294   apt = arp_malloc (sizeof (*apt), GFP_ATOMIC);
 295   if (apt == NULL) return (NULL);
 296 
 297   hash = net32(paddr) & (ARP_TABLE_SIZE - 1);
 298   apt->ip = paddr;
 299   apt->hlen =hlen;
 300   memcpy (apt->hard, addr, hlen);
 301   apt->last_used=timer_seq;
 302   cli();
 303   apt->next = arp_table[hash];
 304   arp_table[hash] = apt;
 305   sti();
 306   return (apt);
 307 }
 308 
 309 int
 310 arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
     /* [previous][next][first][last][top][bottom][index][help] */
 311 {
 312    struct arp *arp;
 313    struct arp_table *tbl;
 314    int ret;
 315 
 316    PRINTK ("<<\n");
 317    arp = skb->h.arp;
 318    print_arp(arp);
 319 
 320   /* if this test doesn't pass, something fishy is going on. */
 321   if (arp->hlen != dev->addr_len || dev->type !=NET16( arp->hrd))
 322     {
 323        kfree_skb(skb, FREE_READ);
 324        return (0);
 325     }
 326 
 327   /* for now we will only deal with ip addresses. */
 328   if (arp->pro != NET16(ARP_IP_PROT) || arp->plen != 4)
 329     {
 330        kfree_skb (skb, FREE_READ);
 331        return (0);
 332     }
 333 
 334   /* now look up the ip address in the table. */
 335   tbl = arp_lookup (*arp_sourcep(arp));
 336   if (tbl != NULL)
 337     {
 338        memcpy (tbl->hard, arp+1, arp->hlen);
 339        tbl->hlen = arp->hlen;
 340        tbl->last_used = timer_seq;
 341     }
 342 
 343   if (!my_ip_addr(*arp_targetp(arp)))
 344     {
 345        kfree_skb (skb, FREE_READ);
 346        return (0);
 347     }
 348 
 349   if (tbl == NULL)
 350     create_arp (*arp_sourcep(arp), arp_sourceh(arp), arp->hlen);
 351 
 352    /* now see if we can send anything. */
 353    send_arp_q();
 354      
 355   if (arp->op != NET16(ARP_REQUEST))
 356     {
 357        kfree_skb (skb, FREE_READ);
 358        return (0);
 359     }
 360 
 361   /* now we need to create a new packet. */
 362    ret = arp_response(arp, dev);
 363    kfree_skb (skb, FREE_READ);
 364    return (ret);
 365 }
 366 
 367 void
 368 arp_snd (unsigned long paddr, struct device *dev, unsigned long saddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 369 {
 370   struct sk_buff *skb;
 371   struct arp *arp;
 372   struct arp_table *apt;
 373   int tmp;
 374   PRINTK ("arp_snd (paddr=%X, dev=%X, saddr=%X)\n",paddr, dev, saddr);
 375 
 376   /* first we build a dummy arp table entry. */
 377   apt = create_arp (paddr, NULL, 0);
 378   if (apt == NULL) return;
 379 
 380   skb = arp_malloc (sizeof (*arp) + sizeof (*skb) + dev->hard_header_len +
 381                     2*dev->addr_len+8, GFP_ATOMIC);
 382   if (skb == NULL) return;
 383   
 384   skb->sk = NULL;
 385   skb->mem_addr = skb;
 386   skb->mem_len = sizeof (*arp) + sizeof (*skb) + dev->hard_header_len +
 387                     2*dev->addr_len+8;
 388   skb->arp = 1;
 389   skb->dev = dev;
 390   skb->len = sizeof (*arp) + dev->hard_header_len + 2*dev->addr_len+8;
 391   skb->next = NULL;
 392 
 393   tmp = dev->hard_header ((unsigned char *)(skb+1), dev,
 394                           ETHERTYPE_ARP, 0, saddr, skb->len);
 395   if (tmp < 0)
 396     {
 397        arp_free (skb->mem_addr, skb->mem_len);
 398        return;
 399     }
 400 
 401   arp =(struct arp *) ((unsigned char *)skb+sizeof (*skb) + tmp );
 402   arp->hrd = net16(dev->type);
 403   arp->pro = NET16(ARP_IP_PROT);
 404   arp->hlen = dev->addr_len;
 405   arp->plen = 4;
 406   arp->op = NET16(ARP_REQUEST);
 407   *arp_sourcep(arp) = saddr;
 408   *arp_targetp(arp) = paddr;
 409   memcpy (arp_sourceh(arp), dev->dev_addr, dev->addr_len);
 410   memcpy (arp_targeth(arp), dev->broadcast, dev->addr_len);
 411   PRINTK(">>\n");
 412   print_arp(arp);
 413   dev->queue_xmit (skb, dev, 0);
 414 }
 415 
 416 int
 417 arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 418            unsigned long saddr)
 419 {
 420   struct arp_table *apt;
 421   PRINTK ("arp_find(haddr=%X, paddr=%X, dev=%X, saddr=%X)\n",
 422           haddr, paddr, dev, saddr);
 423   if (my_ip_addr (paddr))
 424     {
 425       memcpy (haddr, dev->dev_addr, dev->addr_len);
 426       return (0);
 427     }
 428   apt = arp_lookup (paddr);
 429   if (apt != NULL)
 430     {
 431        /* make sure it's not too old. If it is too old, we will
 432           just pretend we did not find it, and then arp_snd
 433           will verify the address for us. */
 434        if (!before (apt->last_used, timer_seq+ARP_TIMEOUT) &&
 435            apt->hlen != 0)
 436          {
 437             apt->last_used=timer_seq;
 438             memcpy (haddr, apt->hard, dev->addr_len);
 439             return (0);
 440          }
 441     }
 442 
 443   /* if we didn't find an entry, we will try to 
 444      send an arp packet. */
 445   if (apt == NULL || after (timer_seq, apt->last_used+ARP_RES_TIME))
 446     arp_snd(paddr,dev,saddr);
 447 
 448   /* this assume haddr are atleast 4 bytes.
 449      If this isn't true we can use a lookup
 450      table, one for every dev. */
 451   *(unsigned long *)haddr = paddr;
 452   return (1);
 453 }
 454 
 455 void
 456 arp_add (unsigned long addr, unsigned char *haddr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 457 {
 458    struct arp_table *apt;
 459    /* first see if the address is already in the table. */
 460    apt = arp_lookup (addr);
 461    if (apt != NULL)
 462      {
 463         apt->last_used = timer_seq;
 464         memcpy (apt->hard, haddr , dev->addr_len);
 465         return;
 466      }
 467    create_arp (addr, haddr, dev->addr_len);
 468 }
 469 
 470 void
 471 arp_add_broad (unsigned long addr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 472 {
 473   arp_add (addr,  dev->broadcast , dev);
 474 }
 475 
 476 void
 477 arp_queue(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 478 {
 479    cli();
 480    if (arp_q == NULL)
 481      {
 482         arp_q = skb;
 483         skb->next = skb;
 484         skb->prev = skb;
 485      }
 486    else
 487      {
 488         skb->next = arp_q;
 489         skb->prev = arp_q->prev;
 490         skb->next->prev = skb;
 491         skb->prev->next = skb;
 492      }
 493    sti();
 494 }

/* [previous][next][first][last][top][bottom][index][help] */