home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / src0131 / arp.c < prev    next >
C/C++ Source or Header  |  1991-01-26  |  9KB  |  319 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  * Copyright 1991 Phil Karn, KA9Q
  4.  */
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "timer.h"
  8. #include "iface.h"
  9. #include "enet.h"
  10. #include "ax25.h"
  11. #include "icmp.h"
  12. #include "ip.h"
  13. #include "arp.h"
  14. #include "icmp.h"
  15.  
  16. static unsigned arp_hash __ARGS((int16 hardware,int32 ipaddr));
  17. static void arp_output __ARGS((struct iface *iface,int16 hardware,int32 target));
  18.  
  19. /* Hash table headers */
  20. struct arp_tab *Arp_tab[ARPSIZE];
  21.  
  22. struct arp_stat Arp_stat;
  23.  
  24. /* Resolve an IP address to a hardware address; if not found,
  25.  * initiate query and return NULLCHAR.  If an address is returned, the
  26.  * interface driver may send the packet; if NULLCHAR is returned,
  27.  * res_arp() will have saved the packet on its pending queue,
  28.  * so no further action (like freeing the packet) is necessary.
  29.  */
  30. char *
  31. res_arp(iface,hardware,target,bp)
  32. struct iface *iface;    /* Pointer to interface block */
  33. int16 hardware;        /* Hardware type */
  34. int32 target;        /* Target IP address */
  35. struct mbuf *bp;    /* IP datagram to be queued if unresolved */
  36. {
  37.     register struct arp_tab *arp;
  38.     struct ip ip;
  39.  
  40.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  41.         return arp->hw_addr;
  42.     if(arp != NULLARP){
  43.         /* Earlier packets are already pending, kick this one back
  44.          * as a source quench
  45.          */
  46.         ntohip(&ip,&bp);
  47.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULL);
  48.         free_p(bp);
  49.     } else {
  50.         /* Create an entry and put the datagram on the
  51.          * queue pending an answer
  52.          */
  53.         arp = arp_add(target,hardware,NULLCHAR,0);
  54.         enqueue(&arp->pending,bp);
  55.         arp_output(iface,hardware,target);
  56.     }
  57.     return NULLCHAR;
  58. }
  59. /* Handle incoming ARP packets. This is almost a direct implementation of
  60.  * the algorithm on page 5 of RFC 826, except for:
  61.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  62.  *    pending a reply to our ARP request.
  63.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  64.  * 3. Requests for IP addresses listed in our table as "published" are
  65.  *    responded to, even if the address is not our own.
  66.  */
  67. void
  68. arp_input(iface,bp)
  69. struct iface *iface;
  70. struct mbuf *bp;
  71. {
  72.     struct arp arp;
  73.     struct arp_tab *ap;
  74.     struct arp_type *at;
  75.     int i;
  76.     
  77.     Arp_stat.recv++;
  78.     if(ntoharp(&arp,&bp) == -1)    /* Convert into host format */
  79.         return;
  80.     if(arp.hardware >= NHWTYPES){
  81.         /* Unknown hardware type, ignore */
  82.         Arp_stat.badtype++;
  83.         return;
  84.     }
  85.     at = &Arp_type[arp.hardware];
  86.     if(arp.protocol != at->iptype){
  87.         /* Unsupported protocol type, ignore */
  88.         Arp_stat.badtype++;
  89.         return;
  90.     }
  91.     if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  92.         /* Incorrect protocol addr length (different hw addr lengths
  93.          * are OK since AX.25 addresses can be of variable length)
  94.          */
  95.         Arp_stat.badlen++;
  96.         return;
  97.     }
  98.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  99.         /* This guy is trying to say he's got the broadcast address! */
  100.         Arp_stat.badaddr++;
  101.         return;
  102.     }
  103.     /* If this guy is already in the table, update its entry
  104.      * unless it's a manual entry (noted by the lack of a timer)
  105.      */
  106.     ap = NULLARP;    /* ap plays the role of merge_flag in the spec */
  107.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  108.      && dur_timer(&ap->timer) != 0){
  109.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0);
  110.     }
  111.     /* See if we're the address they're looking for */
  112.     if(ismyaddr(arp.tprotaddr) != NULLIF){
  113.         if(ap == NULLARP)    /* Only if not already in the table */
  114.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0);
  115.  
  116.         if(arp.opcode == ARP_REQUEST){
  117.             /* Swap sender's and target's (us) hardware and protocol
  118.              * fields, and send the packet back as a reply
  119.              */
  120.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  121.             /* Mark the end of the sender's AX.25 address
  122.              * in case he didn't
  123.              */
  124.             if(arp.hardware == ARP_AX25)
  125.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  126.  
  127.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  128.             arp.tprotaddr = arp.sprotaddr;
  129.             arp.sprotaddr = iface->addr;
  130.             arp.opcode = ARP_REPLY;
  131.             if((bp = htonarp(&arp)) == NULLBUF)
  132.                 return;
  133.  
  134.             if(iface->forw != NULLIF)
  135.                 (*iface->forw->output)(iface->forw,
  136.                  arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  137.             else 
  138.                 (*iface->output)(iface,arp.thwaddr,
  139.                  iface->hwaddr,at->arptype,bp);
  140.             Arp_stat.inreq++;
  141.         } else {
  142.             Arp_stat.replies++;
  143.         }
  144.     } else if(arp.opcode == ARP_REQUEST
  145.      && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  146.      && ap->pub){
  147.         /* Otherwise, respond if the guy he's looking for is
  148.          * published in our table.
  149.          */
  150.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  151.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  152.         arp.tprotaddr = arp.sprotaddr;
  153.         arp.sprotaddr = ap->ip_addr;
  154.         arp.opcode = ARP_REPLY;
  155.         if((bp = htonarp(&arp)) == NULLBUF)
  156.             return;
  157.         if(iface->forw != NULLIF)
  158.             (*iface->forw->output)(iface->forw,
  159.              arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  160.         else 
  161.             (*iface->output)(iface,arp.thwaddr,
  162.              iface->hwaddr,at->arptype,bp);
  163.         Arp_stat.inreq++;
  164.     } else if(arp.opcode == REVARP_REQUEST){
  165.         for(i=0;i<ARPSIZE;i++)
  166.             for(ap = Arp_tab[i];ap != NULLARP;ap = ap->next)
  167.                 if(memcmp(ap->hw_addr,&arp.thwaddr,at->hwalen) == 0)
  168.                     goto found;
  169.     found:    if(ap != NULLARP && ap->pub){
  170.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  171.             arp.tprotaddr = ap->ip_addr;
  172.             arp.sprotaddr = iface->addr;
  173.             arp.opcode = REVARP_REPLY;
  174.             if((bp = htonarp(&arp)) == NULLBUF)
  175.                 return;
  176.             if(iface->forw != NULLIF)
  177.                 (*iface->forw->output)(iface->forw,
  178.                  arp.thwaddr,iface->forw->hwaddr,REVARP_TYPE,bp);
  179.             else 
  180.                 (*iface->output)(iface,arp.thwaddr,
  181.                  iface->hwaddr,REVARP_TYPE,bp);
  182.             Arp_stat.inreq++;
  183.         }
  184.     }
  185. }
  186. /* Add an IP-addr / hardware-addr pair to the ARP table */
  187. struct arp_tab *
  188. arp_add(ipaddr,hardware,hw_addr,pub)
  189. int32 ipaddr;        /* IP address, host order */
  190. int16 hardware;        /* Hardware type */
  191. char *hw_addr;        /* Hardware address, if known; NULLCHAR otherwise */
  192. int pub;        /* Publish this entry? */
  193. {
  194.     struct mbuf *bp;
  195.     register struct arp_tab *ap;
  196.     struct arp_type *at;
  197.     unsigned hashval;
  198.  
  199.     if(hardware >=NHWTYPES)
  200.         return NULLARP;    /* Invalid hardware type */
  201.     at = &Arp_type[hardware];
  202.  
  203.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  204.         /* New entry */
  205.         ap = (struct arp_tab *)callocw(1,sizeof(struct arp_tab));
  206.         ap->hw_addr = mallocw(at->hwalen);
  207.         ap->timer.func = arp_drop;
  208.         ap->timer.arg = ap;
  209.         ap->hardware = hardware;
  210.         ap->ip_addr = ipaddr;
  211.  
  212.         /* Put on head of hash chain */
  213.         hashval = arp_hash(hardware,ipaddr);
  214.         ap->prev = NULLARP;
  215.         ap->next = Arp_tab[hashval];
  216.         Arp_tab[hashval] = ap;
  217.         if(ap->next != NULLARP){
  218.             ap->next->prev = ap;
  219.         }
  220.     }
  221.     if(hw_addr == NULLCHAR){
  222.         /* Await response */
  223.         ap->state = ARP_PENDING;
  224.         set_timer(&ap->timer,Arp_type[hardware].pendtime * 1000L);
  225.     } else {
  226.         /* Response has come in, update entry and run through queue */
  227.         ap->state = ARP_VALID;
  228.         set_timer(&ap->timer,ARPLIFE*1000L);
  229.         memcpy(ap->hw_addr,hw_addr,at->hwalen);
  230.         ap->pub = pub;
  231.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  232.             ip_route(NULLIF,bp,0);
  233.     }
  234.     start_timer(&ap->timer);
  235.     return ap;
  236. }
  237.  
  238. /* Remove an entry from the ARP table */
  239. void
  240. arp_drop(p)
  241. void *p;
  242. {
  243.     register struct arp_tab *ap;
  244.  
  245.     ap = (struct arp_tab *)p;
  246.     if(ap == NULLARP)
  247.         return;
  248.     stop_timer(&ap->timer);    /* Shouldn't be necessary */
  249.     if(ap->next != NULLARP)
  250.         ap->next->prev = ap->prev;
  251.     if(ap->prev != NULLARP)
  252.         ap->prev->next = ap->next;
  253.     else
  254.         Arp_tab[arp_hash(ap->hardware,ap->ip_addr)] = ap->next;
  255.     free_q(&ap->pending);
  256.     free(ap->hw_addr);
  257.     free((char *)ap);
  258. }
  259.  
  260. /* Look up the given IP address in the ARP table */
  261. struct arp_tab *
  262. arp_lookup(hardware,ipaddr)
  263. int16 hardware;
  264. int32 ipaddr;
  265. {
  266.     register struct arp_tab *ap;
  267.  
  268.     for(ap = Arp_tab[arp_hash(hardware,ipaddr)]; ap != NULLARP; ap = ap->next){
  269.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  270.             break;
  271.     }
  272.     return ap;
  273. }
  274. /* Send an ARP request to resolve IP address target_ip */
  275. static void
  276. arp_output(iface,hardware,target)
  277. struct iface *iface;
  278. int16 hardware;
  279. int32 target;
  280. {
  281.     struct arp arp;
  282.     struct mbuf *bp;
  283.     struct arp_type *at;
  284.  
  285.     at = &Arp_type[hardware];
  286.     if(iface->output == NULLFP)
  287.         return;
  288.     
  289.     arp.hardware = hardware;
  290.     arp.protocol = at->iptype;
  291.     arp.hwalen = at->hwalen;
  292.     arp.pralen = sizeof(int32);
  293.     arp.opcode = ARP_REQUEST;
  294.     memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  295.     arp.sprotaddr = iface->addr;
  296.     memset(arp.thwaddr,0,at->hwalen);
  297.     arp.tprotaddr = target;
  298.     if((bp = htonarp(&arp)) == NULLBUF)
  299.         return;
  300.     (*iface->output)(iface,at->bdcst,
  301.         iface->hwaddr,at->arptype,bp);
  302.     Arp_stat.outreq++;
  303. }
  304.  
  305. /* Hash a {hardware type, IP address} pair */
  306. static
  307. unsigned
  308. arp_hash(hardware,ipaddr)
  309. int16 hardware;
  310. int32 ipaddr;
  311. {
  312.     register unsigned hashval;
  313.  
  314.     hashval = hardware;
  315.     hashval ^= hiword(ipaddr);
  316.     hashval ^= loword(ipaddr);
  317.     return hashval % ARPSIZE;
  318. }        
  319.