home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / manage / snmp / kip / arp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-01-17  |  9.5 KB  |  397 lines

  1. /*
  2.  *  (c) 1986, Stanford Univ. CSLI.
  3.  *  May be used but not sold without permission.
  4.  *
  5.  *  (c) 1986, Kinetics, Inc.
  6.  *  May be used but not sold without permission.
  7.  *
  8.  *  $Header: arp.c,v 4.1 88/11/01 19:47:44 sw0l Exp $
  9.  */
  10.  
  11. /*
  12.  * Address resolution protocol.
  13.  */
  14.  
  15. #include "gw.h"
  16. #include "fp/pbuf.h"
  17. #include "ab.h"
  18. #include "inet.h"
  19. #include "fp/cmdmacro.h"
  20.  
  21. #include "glob.h"
  22.  
  23. /*
  24.  * See RFC 826 (see "arp.rfc") for protocol description.
  25.  * Field names used correspond to RFC 826.
  26.  */
  27.  
  28. #define    ARPHLNMAX    6    /* largest arp_hln value needed */
  29. #define    ARPPLN        4    /* length of protocol address (IP) */
  30.  
  31. struct    arp {
  32.     u_short    arp_hrd;    /* format of hardware address */
  33.     u_short    arp_pro;    /* format of proto. address  */
  34.     u_char    arp_hln;    /* length of hardware address  */
  35.     u_char    arp_pln;    /* length of protocol address  */
  36.     u_short    arp_op;
  37. #define    ARPOP_REQUEST    1    /* request to resolve address */
  38. #define    ARPOP_REPLY    2    /* response to previous request */
  39. #define ARPOP_PROBE     3    /* Apple 'Address PROBE' opcode */
  40.     u_char    arp_d[ARPHLNMAX*2+ARPPLN*2];
  41.                 /* contains 4 packed fields:
  42.                    sender hardware/proto addresses,
  43.                    target hardware/proto addresses */
  44. };
  45. #define    arp_sha(ea)    (&(ea)->arp_d[0])
  46. #define    arp_spa(ea)    (&(ea)->arp_d[hln])
  47. #define    arp_tha(ea)    (&(ea)->arp_d[hln+ARPPLN])
  48. #define    arp_tpa(ea)    (&(ea)->arp_d[hln+hln+ARPPLN])
  49. #define    sizeof_arp    (sizeof(struct arp) - ARPHLNMAX*2  + hln + hln)
  50.  
  51.  
  52. /*
  53.  * Internet to hardware address resolution table.
  54.  */
  55. struct    arptab {
  56.     iaddr_t at_iaddr;        /* internet address */
  57.     u_char    at_haddr[ARPHLNMAX];    /* hardware address */
  58.     u_char    at_timer;        /* minutes since last reference */
  59.     u_char    at_flags;        /* flags */
  60.     struct    pbuf *at_hold;        /* last packet until resolved/timeout */
  61. };
  62. /* at_flags field values */
  63. #define    ATF_INUSE    1        /* entry in use */
  64. #define ATF_COM        2        /* completed entry (haddr valid) */
  65.  
  66. #define    ARPTAB_BSIZ    3        /* bucket size */
  67. #define    ARPTAB_NB    8        /* number of buckets */
  68. #define    ARPTAB_SIZE    (ARPTAB_BSIZ * ARPTAB_NB)
  69.  
  70. struct    arptab *arptnew();
  71.  
  72. struct    arptab arptab[ARPTAB_SIZE];
  73.  
  74. #define    ARPTAB_HASH(a) \
  75.     ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB)
  76.  
  77. #define    ARPTAB_LOOK(at,addr) { \
  78.     register n; \
  79.     at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
  80.     for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
  81.         if (at->at_iaddr == addr) \
  82.             break; \
  83.     if (n >= ARPTAB_BSIZ) \
  84.         at = 0; }
  85.  
  86. int    arpt_age;        /* aging timer */
  87.  
  88. /* timer values */
  89. #define    ARPT_AGE    (60*1)    /* aging timer, 1 min. */
  90. #define    ARPT_KILLC    20    /* kill completed entry in 20 mins. */
  91. #define    ARPT_KILLI    3    /* kill incomplete entry in 3 minutes */
  92.  
  93.  
  94. u_char    broadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  95.  
  96. /*
  97.  * Timeout routine.  Age arptab entries once a minute.
  98.  * Entered once per second.
  99.  */
  100. arptimer()
  101. {
  102.     register struct arptab *at;
  103.     register i;
  104.  
  105.     if (++arpt_age > ARPT_AGE) {
  106.         arpt_age = 0;
  107.         at = &arptab[0];
  108.         for (i = 0; i < ARPTAB_SIZE; i++, at++) {
  109.             if (at->at_flags == 0)
  110.                 continue;
  111.             if (++at->at_timer < ((at->at_flags&ATF_COM) ?
  112.                 ARPT_KILLC : ARPT_KILLI))
  113.                 continue;
  114.             /* timer has expired, clear entry */
  115.             arptfree(at);
  116.         }
  117.     }
  118. }
  119.  
  120. /*
  121.  * Broadcast an ARP packet, asking who has addr on interface ifp.
  122.  */
  123. arpwhohas(ifp, addr)
  124.     register struct ifnet *ifp;
  125.     iaddr_t *addr;
  126. {
  127.     register struct pbuf *p;
  128.     register struct arp *ea;
  129.     register hln;
  130.     
  131.     if (ifp == &ifab) {
  132.         nbpwhohasip(*addr);
  133.         return;
  134.     }
  135.     hln = ifp->if_haddrlen;
  136.     K_PGET(PT_ARP,p); /* get a buffer from the free list */
  137.      if (p == 0)
  138.         return;
  139.     p->p_len = sizeof_arp;
  140.     ea = (struct arp *)p->p_off;
  141.     bzero((caddr_t)ea, sizeof_arp);
  142.     ea->arp_hrd = htons(ifp->if_haddrform);
  143.     ea->arp_pro = htons(ifp->if_addrform);
  144.     ea->arp_hln = hln;    /* hardware address length */
  145.     ea->arp_pln = ARPPLN;    /* protocol address length */
  146.  
  147.     /* Check whether this is the Ethertalk interface, and
  148.          * the address hasn't been set yet. If so we must still
  149.          * be sending PROBE's
  150.          */
  151.     if (ifp->if_dnode == 0) {
  152.       /* This is probably the ethertalk interface and */
  153.       /* we must still be probing for an address */
  154.       ea->arp_op = htons(ARPOP_PROBE);
  155.     } else       
  156.       ea->arp_op = htons(ARPOP_REQUEST);
  157.     bcopy(ifp->if_haddr, arp_sha(ea), hln);
  158.     bcopy((caddr_t)&ifp->if_addr, arp_spa(ea), ARPPLN);
  159.     bcopy((caddr_t)addr, arp_tpa(ea), ARPPLN);
  160.     (*ifp->if_output)(ifp, p,  AF_ARP, broadcastaddr);
  161. }
  162.  
  163. /*
  164.  * Resolve an IP address into a hardware address.  If success, 
  165.  * destha is filled in and 1 is returned.  If there is no entry
  166.  * in arptab, set one up and broadcast a request 
  167.  * for the IP address;  return 0.  Hold onto this pbuf and 
  168.  * resend it once the address is finally resolved.
  169.  */
  170. arpresolve(ifp, p, destip, destha)
  171.     register struct ifnet *ifp;
  172.     struct pbuf *p;
  173.     register iaddr_t *destip;
  174.     register u_char *destha;
  175. {
  176.     register struct arptab *at;
  177.     register hln = ifp->if_haddrlen;
  178.     int lna = ntohl(*(long *)destip) & 0xFF;
  179.  
  180.     if (lna == 0xFF || lna == 0x0) { /* broadcast address */
  181.         bcopy(broadcastaddr, destha, hln);
  182.         return (1);
  183.     }
  184.     /*
  185.      * We used to do some (conservative) locking here at splimp, since
  186.      * arpinput was called  from input interrupt service.
  187.      *    
  188.      *    s = splimp();
  189.      */
  190.     ARPTAB_LOOK(at, *destip);
  191.     if (at == 0) {            /* not found */
  192.         at = arptnew(destip);
  193.         at->at_hold = p;
  194.         arpwhohas(ifp, destip);
  195.         /* splx(s); */
  196.         return (0);
  197.     }
  198.     at->at_timer = 0;        /* restart the timer */
  199.     if (at->at_flags & ATF_COM) {    /* entry IS complete */
  200.         if (destha) bcopy(at->at_haddr, destha, hln);
  201.         /* splx(s); */
  202.         return (1);
  203.     }
  204.     /*
  205.      * There is an arptab entry, but no hardware address
  206.      * response yet.  Replace the held pbuf with this
  207.      * latest one.
  208.      */
  209.      if (at->at_hold) {
  210.          /* put buffer back on the free list */
  211.         K_PFREE(at->at_hold);
  212.      }
  213.     if (p) at->at_hold = p;
  214.     arpwhohas(ifp, destip);        /* ask again */
  215.     /* splx(s); */
  216.     return (0);
  217. }
  218.  
  219.  
  220. /*
  221.  * Called when packet containing ARP is received.
  222.  * Algorithm is that given in RFC 826.
  223.  * In addition, a sanity check is performed on the sender
  224.  * protocol address, to catch impersonators.
  225.  */
  226. arpinput(p)
  227.     struct pbuf *p;
  228. {
  229. #ifdef notdef
  230.     register struct ifnet *ifp = p_if(p);
  231. #else
  232.     register struct ifnet *ifp = source_if;
  233. #endif    
  234.     register struct arp *ea;
  235.     register struct arptab *at = 0;  /* same as "merge" flag */
  236.     register hln = ifp->if_haddrlen;
  237.     struct pbuf *phold;
  238.     iaddr_t isaddr,itaddr,myaddr;
  239.  
  240.     if (p->p_len < sizeof_arp)
  241.         goto out;
  242.     myaddr = ifp->if_addr;
  243.     ea = (struct arp *) p->p_off;
  244.     if (ntohs(ea->arp_pro) != ifp->if_addrform)
  245.         goto out;
  246.     bcopy(arp_spa(ea), (caddr_t)&isaddr, ARPPLN);
  247.     bcopy(arp_tpa(ea), (caddr_t)&itaddr, ARPPLN);
  248.     if (!bcmp(arp_sha(ea), ifp->if_haddr, hln))
  249.         goto out;    /* it's from me, ignore it. */
  250.  
  251.     /* Check for Ethertalk PROBE - Someone doing address aquisition */
  252.     if (ntohs(ea->arp_op) == ARPOP_PROBE) {
  253.       if (itaddr == myaddr)  goto reply;
  254.       else goto out;    /* ignore probes not meant for me */
  255.     }
  256.  
  257.     if (isaddr == myaddr) {
  258.       int i;
  259.       u_char *cp = arp_sha(ea);
  260.       sendf("duplicate IP address %x!! sent from hardware address: ");
  261.       for (i = 0 ; i < hln ; i++)
  262.         sendf("%x ", *cp++);
  263.       if (ntohs(ea->arp_op) == ARPOP_REQUEST) {
  264.         itaddr = myaddr;
  265.         goto reply;
  266.       }
  267.       goto out;
  268.     }
  269.  
  270.     ARPTAB_LOOK(at, isaddr);
  271.     if (at) {
  272.         bcopy(arp_sha(ea), at->at_haddr, hln);
  273.         at->at_flags |= ATF_COM;
  274.         if (at->at_hold) {
  275.             phold = at->at_hold;
  276.             at->at_hold = 0;
  277.             (*ifp->if_output)(ifp, phold, AF_IP, &isaddr);
  278.         }
  279.     }
  280.  
  281.     if (itaddr != myaddr && 
  282.         (ifp->if_matchus == 0 || (*ifp->if_matchus)(itaddr) == 0))
  283.         goto out;    /* if I am not the target */
  284.  
  285.     if (at == 0) {        /* ensure we have a table entry */
  286.         at = arptnew(&isaddr);
  287.         bcopy(arp_sha(ea), at->at_haddr, hln);
  288.         at->at_flags |= ATF_COM;
  289.     }
  290.  
  291.     if (ntohs(ea->arp_op) != ARPOP_REQUEST)
  292.         goto out;
  293.  
  294. reply:
  295.     bcopy(arp_sha(ea), arp_tha(ea), hln);
  296.     bcopy(arp_spa(ea), arp_tpa(ea), ARPPLN);
  297.     bcopy(ifp->if_haddr, arp_sha(ea), hln);
  298.     bcopy((caddr_t)&itaddr, arp_spa(ea), ARPPLN);
  299.     ea->arp_op = htons(ARPOP_REPLY);
  300.     (*ifp->if_output)(ifp, p, AF_ARP, arp_tha(ea));
  301.     return;
  302.  
  303. out:
  304.      /* put buffer back on the free list */
  305.     K_PFREE(p);
  306.     return;
  307. }
  308.  
  309. /*
  310.  * Got an arp reply (via nbpinput).  If it completes one of our arptab
  311.  * entries, send off the held buffer.  This subroutine is modeled after
  312.  * the inner section of arpinput.
  313.  */
  314. arpgotreply(ifp, iaddr, haddr)
  315.     register struct ifnet *ifp;
  316.     iaddr_t iaddr;
  317.     caddr_t haddr;
  318. {
  319.     register struct arptab *at;
  320.     struct pbuf *p;
  321.  
  322.     ARPTAB_LOOK(at, iaddr);
  323.     if (at == 0)    /* if no matching entry, nothing to do */
  324.         return;
  325.     bcopy(haddr, at->at_haddr, 4);
  326.     at->at_flags |= ATF_COM;
  327.     if (at->at_hold) {
  328.         p = at->at_hold;
  329.         at->at_hold = 0;
  330.         (*ifp->if_output)(ifp, p, AF_IP, &iaddr);
  331.     }
  332. }
  333.  
  334. /*
  335.  * Delete an arp cache entry.  Called from ipgassign when
  336.  * new assignment made.
  337.  */
  338. arpdelete(iaddr)
  339.     iaddr_t iaddr;
  340. {
  341.     register struct arptab *at;
  342.     ARPTAB_LOOK(at, iaddr);
  343.     if (at)
  344.         arptfree(at);
  345. }
  346.  
  347. /*
  348.  * Free an arptab entry.
  349.  */
  350. arptfree(at)
  351.     register struct arptab *at;
  352. {
  353.      short pri;
  354.      
  355.      K_SPLIMP(&pri);
  356.      if (at->at_hold) {
  357.          /* put buffer back on the free list */
  358.         K_PFREE(at->at_hold);
  359.      }
  360.  
  361.     at->at_hold = 0;
  362.     at->at_timer = at->at_flags = 0;
  363.     at->at_iaddr = 0;
  364.     K_SPLX(&pri);
  365. }
  366.  
  367. /*
  368.  * Enter a new address in arptab, pushing out the oldest entry 
  369.  * from the bucket if there is no room.
  370.  */
  371. struct arptab *
  372. arptnew(addr)
  373.     iaddr_t *addr;
  374. {
  375.     register n;
  376.     int oldest = 0;
  377.     register struct arptab *at, *ato;
  378.  
  379.     ato = at = &arptab[ARPTAB_HASH(*addr) * ARPTAB_BSIZ];
  380.     for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) {
  381.         if (at->at_flags == 0)
  382.             goto out;     /* found an empty entry */
  383.         if (at->at_timer > oldest) {
  384.             oldest = at->at_timer;
  385.             ato = at;
  386.         }
  387.     }
  388.     at = ato;
  389.     arptfree(at);
  390. out:
  391.     at->at_iaddr = *addr;
  392.     at->at_flags = ATF_INUSE;
  393.     return (at);
  394. }
  395.  
  396.  
  397.