home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / tcpipsrc / ARP / c / ARP next >
Text File  |  1994-06-24  |  13KB  |  364 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.  */                
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "ip.h"
  11. #include "misc.h"
  12. #include "icmp.h"
  13. #include "iface.h"
  14. #include "ax25.h"
  15. #include "arp.h"
  16.  
  17. static void arp_output(struct interface *, int16, int32);
  18. static unsigned arp_hash(int16, int32);
  19.  
  20. extern int32 ip_addr;           /* Our IP address */
  21.  
  22. /* ARP entries for particular subnetwork types. The table values
  23.  * are filled in by calls to arp_init() at device attach time
  24.  */
  25. #define NTYPES  9
  26. struct arp_type arp_type[NTYPES];
  27.  
  28. /* Hash table headers */
  29. struct arp_tab *arp_tab[ARPSIZE];
  30.  
  31. struct arp_stat arp_stat;
  32.  
  33. /* Initialize an entry in the ARP table
  34.  * Called by the device driver at attach time
  35.  */
  36. int arp_init(unsigned int hwtype, int hwalen, int iptype, int arptype,
  37.              char *bdcst, int (*format)(), int (*scan)())
  38. {
  39.         register struct arp_type *at;
  40.  
  41.         if(hwtype >= NTYPES)
  42.                 return -1;      /* Table too small */
  43.  
  44.         at = &arp_type[hwtype];
  45.         at->hwalen = (int16)hwalen;
  46.         at->iptype = (int16)iptype;
  47.         at->arptype = (int16)arptype;
  48.         at->bdcst = bdcst;
  49.         at->format = format;
  50.         at->scan = scan;
  51.         return 0;
  52. }
  53.  
  54. /* Resolve an IP address to a hardware address; if not found,
  55.  * initiate query and return NULLCHAR.  If an address is returned, the
  56.  * interface driver may send the packet; if NULLCHAR is returned,
  57.  * res_arp() will have saved the packet on its pending queue,
  58.  * so no further action (like freeing the packet) is necessary.
  59.  */
  60. char *res_arp(struct interface *interface, int16 hardware, int32 target, struct mbuf *bp)
  61. {
  62.         register struct arp_tab *arp;
  63.         struct ip ip;
  64.  
  65.         if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  66.                 return arp->hw_addr;
  67.         if(arp != NULLARP){
  68.                 /* Earlier packets are already pending, kick this one back
  69.                  * as a source quench
  70.                  */
  71.                 ntohip(&ip,&bp);
  72.                 icmp_output(&ip,bp,QUENCH,0,NULLICMP);
  73.                 free_p(bp);
  74.         } else {
  75.                /* Create an entry and put the datagram on the
  76.                 * queue pending an answer
  77.                 */
  78.                arp = arp_add(target,hardware,NULLCHAR,0,0);
  79.                enqueue(&arp->pending,bp);
  80.                arp_output(interface,hardware,target);
  81.         }
  82.         return NULLCHAR;
  83. }
  84. /* Handle incoming ARP packets. This is almost a direct implementation of
  85.  * the algorithm on page 5 of RFC 826, except for:
  86.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  87.  *    pending a reply to our ARP request.
  88.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  89.  * 3. Requests for IP addresses listed in our table as "published" are
  90.  *    responded to, even if the address is not our own.
  91.  */
  92. void arp_input(struct interface *interface, struct mbuf *bp)
  93. {
  94.         struct arp arp;
  95.         struct arp_tab *ap;
  96.         struct arp_type *at;
  97.         
  98.         arp_stat.recv++;
  99.         if(ntoharp(&arp,&bp) == -1)     /* Convert into host format */
  100.                 return;
  101.         if(arp.hardware >= NTYPES){
  102.                 /* Unknown hardware type, ignore */
  103.                 arp_stat.badtype++;
  104.                 return;
  105.         }
  106.         at = &arp_type[arp.hardware];
  107.         if(arp.protocol != at->iptype){
  108.                 /* Unsupported protocol type, ignore */
  109.                 arp_stat.badtype++;
  110.                 return;
  111.         }
  112.         if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  113.                 /* Incorrect protocol addr length (different hw addr lengths
  114.                  * are OK since AX.25 addresses can be of variable length)
  115.                  */
  116.                 arp_stat.badlen++;
  117.                 return;
  118.         }
  119.         if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  120.                 /* This guy is trying to say he's got the broadcast address! */
  121.                 arp_stat.badaddr++;
  122.                 return;
  123.         }
  124.         /* If this guy is already in the table, update its entry
  125.          * unless it's a manual entry (noted by the lack of a timer)
  126.          */
  127.         ap = NULLARP;   /* ap plays the role of merge_flag in the spec */
  128.         if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  129.          && ap->timer.start != 0){
  130.                 ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  131.         }
  132.         /* See if we're the address they're looking for */
  133.         if(arp.tprotaddr == ip_addr){
  134.                 if(ap == NULLARP)       /* Only if not already in the table */
  135.                         arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  136.  
  137.                 if(arp.opcode == ARP_REQUEST){
  138.                         /* Swap sender's and target's (us) hardware and protocol
  139.                          * fields, and send the packet back as a reply
  140.                          */
  141.                         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  142.                         /* Mark the end of the sender's AX.25 address
  143.                          * in case he didn't
  144.                          */
  145.                         if(arp.hardware == ARP_AX25)
  146.                                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  147.  
  148.                         memcpy(arp.shwaddr,interface->hwaddr,at->hwalen);
  149.                         arp.tprotaddr = arp.sprotaddr;
  150.                         arp.sprotaddr = ip_addr;
  151.                         arp.opcode = ARP_REPLY;
  152.                         if((bp = htonarp(&arp)) == NULLBUF)
  153.                                 return;
  154.  
  155.                         if(interface->forw != NULLIF)
  156.                                 (*interface->forw->output)(interface->forw,
  157.                                  arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  158.                         else 
  159.                                 (*interface->output)(interface,arp.thwaddr,
  160.                                  interface->hwaddr,at->arptype,bp);
  161.                         arp_stat.inreq++;
  162.                 } else {
  163.                         arp_stat.replies++;
  164.                 }
  165.         } else if(arp.opcode == ARP_REQUEST
  166.                 && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  167.                 && ap->pub){
  168.                 /* Otherwise, respond if the guy he's looking for is
  169.                  * published in our table.
  170.                  */
  171.                 memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  172.                 /* Mark the end of the sender's AX.25 address
  173.                  * in case he didn't
  174.                  */
  175.                 if(arp.hardware == ARP_AX25)
  176.                         arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  177.                 memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  178.                 arp.tprotaddr = arp.sprotaddr;
  179.                 arp.sprotaddr = ap->ip_addr;
  180.                 arp.opcode = ARP_REPLY;
  181.                 if((bp = htonarp(&arp)) == NULLBUF)
  182.                         return;
  183.                 if(interface->forw != NULLIF)
  184.                         (*interface->forw->output)(interface->forw,
  185.                          arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  186.                 else 
  187.                         (*interface->output)(interface,arp.thwaddr,
  188.                          interface->hwaddr,at->arptype,bp);
  189.                 arp_stat.inreq++;
  190.         }
  191. }
  192. /* Add an IP-addr / hardware-addr pair to the ARP table */
  193. struct arp_tab *
  194. arp_add(int32 ipaddr, int16 hardware, char *hw_addr, int16 hw_alen, int pub)
  195. {
  196.         struct mbuf *bp;
  197.         register struct arp_tab *ap;
  198.         unsigned hashval;
  199.  
  200.         if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  201.                 /* New entry */
  202.                 if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  203.                         return NULLARP;
  204.                 ap->timer.func = arp_drop;
  205.                 ap->timer.arg = (char *)ap;
  206.                 ap->hardware = hardware;
  207.                 ap->ip_