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