home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / packet / n17jsrc / arp.c < prev    next >
C/C++ Source or Header  |  1991-10-18  |  9KB  |  322 lines

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