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