home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff225.lzh / AmigaTCP / src / arp.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  14KB  |  609 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 "machdep.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "ether.h"
  9. #include "ax25.h"
  10. #include "arp.h"
  11. #include "cmdparse.h"
  12.  
  13. extern int32 ip_addr;        /* Our IP address */
  14.  
  15. int ec_output();
  16. int pether(),gether();
  17.  
  18. int setcall(),psax25();
  19.  
  20. /* Table of ARP hardware types */
  21. struct arp_type arp_type[] = {
  22.     0,
  23.     0,
  24.     0,
  25.     NULLCHAR,
  26.     NULLFP,
  27.     NULLFP,
  28.  
  29.     /* 10 megabit Ethernet */
  30.     6,            /* Ethernet address length */
  31.     0x800,            /* Ethernet type field for IP */
  32.     0x806,            /* Ethernet type field for ARP */
  33.     ether_bdcst,        /* Ethernet broadcast address */
  34.     pether,
  35.     gether,
  36.     
  37.     /* 3 megabit Ethernet */
  38.     0,
  39.     0,
  40.     0,
  41.     NULLCHAR,
  42.     NULLFP,
  43.     NULLFP,
  44.  
  45.     /* AX.25 */
  46.     7,            /* AX.25 address length */
  47.     0xCC,            /* AX.25 pid field for IP */
  48.     0xCD,            /* AX.25 pid field for ARP */
  49.     (char *)&ax25_bdcst,    /* AX.25 broadcast address */
  50.     psax25,
  51.     setcall,
  52. };
  53. #define    NTYPES    4
  54.  
  55. /* Hash table headers */
  56. struct arp_tab *arp_tab[ARPSIZE];
  57.  
  58. struct arp_stat arp_stat;
  59.  
  60. /* Resolve an IP address to a hardware address; if not found,
  61.  * initiate query and return NULLCHAR.  If an address is returned, the
  62.  * interface driver may send the packet; if NULLCHAR is returned,
  63.  * res_arp() will have saved the packet on its pending queue,
  64.  * so no further action (like freeing the packet) is necessary.
  65.  */
  66. char *
  67. res_arp(interface,hardware,target,bp)
  68. struct interface *interface;    /* Pointer to interface block */
  69. int16 hardware;        /* Hardware type */
  70. int32 target;        /* Target IP address */
  71. struct mbuf *bp;    /* IP datagram to be queued if unresolved */
  72. {
  73.     struct arp_tab *arp_lookup(),*arp_add();
  74.     void arp_output();
  75.     register struct arp_tab *arp;
  76.  
  77.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  78.         return arp->hw_addr;
  79.     /* Create an entry and put the datagram on the
  80.      * queue pending an answer
  81.      */
  82.     arp = arp_add(target,hardware,NULLCHAR,0);
  83.     enqueue(&arp->pending,bp);
  84.     arp_output(interface,hardware,target);
  85.     return NULLCHAR;
  86. }
  87. /* Handle incoming ARP packets. This is almost a direct implementation of
  88.  * the algorithm on page 5 of RFC 826, except for:
  89.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  90.  *    pending a reply to our ARP request.
  91.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  92.  */
  93. void
  94. arp_input(interface,bp)
  95. struct interface *interface;
  96. struct mbuf *bp;
  97. {
  98.     struct arp arp;
  99.     struct arp_tab *arp_lookup(),*ap;
  100.     struct arp_type *at;
  101.     struct mbuf *htonarp();
  102.     
  103.     arp_stat.recv++;
  104.     if(ntoharp(&arp,bp) == -1)    /* Convert into host format */
  105.         return;
  106.     if(arp.hardware >= NTYPES){
  107.         /* Unknown hardware type, ignore */
  108.         arp_stat.badtype++;
  109.         return;
  110.     }
  111.     at = &arp_type[arp.hardware];
  112.     if(arp.protocol != at->iptype){
  113.         /* Unsupported protocol type, ignore */
  114.         arp_stat.badtype++;
  115.         return;
  116.     }
  117.     if(arp.hwalen > MAXHWALEN || arp.pralen != sizeof(int32)){
  118.         /* Incorrect protocol addr length (different hw addr lengths
  119.          * are OK since AX.25 addresses can be of variable length)
  120.          */
  121.     arp_stat.badlen++;
  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,arp.hwalen & 0xff);
  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,arp.hwalen & 0xff);
  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.             bcopy(arp.shwaddr,arp.thwaddr,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[arp.hwalen-1] |= E;
  147.  
  148.             bcopy(interface->hwaddr,arp.shwaddr,at->hwalen);
  149.             arp.tprotaddr = arp.sprotaddr;
  150.             arp.sprotaddr = ip_addr;
  151.             arp.opcode = ARP_REPLY;
  152.             bp = htonarp(&arp);
  153.             (*interface->output)(interface,arp.thwaddr,
  154.                 interface->hwaddr,at->arptype,bp);
  155.             arp_stat.inreq++;
  156.         } else {
  157.             arp_stat.replies++;
  158.         }
  159.     }
  160. }
  161. /* Add an IP-addr / hardware-addr pair to the ARP table */
  162. static
  163. struct arp_tab *
  164. arp_add(ip_addr,hardware,hw_addr,hw_alen)
  165. int32 ip_addr;    /* IP address, host order */
  166. int16 hardware;    /* Hardware type */
  167. char *hw_addr;    /* Hardware address, if known; NULLCHAR otherwise */
  168. int16 hw_alen;    /* Length of hardware address */
  169. {
  170.     char *calloc(),*malloc();
  171.     struct arp_tab *arp_lookup();
  172.     void arp_drop();
  173.     struct mbuf *bp,*dequeue();
  174.     register struct arp_tab *ap;
  175.     register struct arp_type *at;
  176.     unsigned hashval,arp_hash();
  177.  
  178.     at = &arp_type[hardware];
  179.     if((ap = arp_lookup(hardware,ip_addr)) == NULLARP){
  180.         /* New entry */
  181.         if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  182.             return NULLARP;
  183.         ap->timer.func = arp_drop;
  184.         ap->timer.arg = (int *)ap;
  185.         ap->hardware = hardware;
  186.         ap->ip_addr = ip_addr;
  187.  
  188.         /* Put on head of hash chain */
  189.         hashval = arp_hash(hardware,ip_addr);
  190.         ap->prev = NULLARP;
  191.         ap->next = arp_tab[hashval];
  192.         arp_tab[hashval] = ap;
  193.         if(ap->next != NULLARP){
  194.             ap->next->prev = ap;
  195.         }
  196.     }
  197.     if(hw_addr == NULLCHAR){
  198.         /* Await response */
  199.         ap->state = ARP_PENDING;
  200.         ap->timer.start = PENDTIME;
  201.     } else {
  202.         /* Response has come in, update entry and run through queue */
  203.         ap->state = ARP_VALID;
  204.         ap->timer.start = ARPLIFE;
  205.         if(ap->hw_addr != NULLCHAR)
  206.             free(ap->hw_addr);
  207.         if((ap->hw_addr = malloc(hw_alen)) == NULLCHAR){
  208.             free((char *)ap);
  209.             return NULLARP;
  210.         }
  211.         bcopy(hw_addr,ap->hw_addr,hw_alen);
  212.         /* This kludge marks the end of an AX.25 address to allow
  213.          * for optional digipeaters (insert Joan Rivers salute here)
  214.          */
  215.         if(hardware == ARP_AX25)
  216.             ap->hw_addr[hw_alen-1] |= E;
  217.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  218.             ip_route(bp,0);
  219.     }
  220.     start_timer(&ap->timer);
  221.     return ap;
  222. }
  223.  
  224. /* Remove an entry from the ARP table */
  225. static
  226. void
  227. arp_drop(ap)
  228. register struct arp_tab *ap;
  229. {
  230.     unsigned arp_hash();
  231.  
  232.     if(ap == NULLARP)
  233.         return;
  234.     stop_timer(&ap->timer);    /* Shouldn't be necessary */
  235.     if(ap->next != NULLARP)
  236.         ap->next->prev = ap->prev;
  237.     if(ap->prev != NULLARP)
  238.         ap->prev->next = ap->next;
  239.     else
  240.         arp_tab[arp_hash(ap->hardware,ap->ip_addr)] = ap->next;
  241.     if(ap->hw_addr != NULLCHAR)
  242.         free(ap->hw_addr);
  243.     free_q(&ap->pending);
  244.     free((char *)ap);
  245. }
  246.  
  247. /* Look up the given IP address in the ARP table */
  248. static
  249. struct arp_tab *
  250. arp_lookup(hardware,ip_addr)
  251. int16 hardware;
  252. int32 ip_addr;
  253. {
  254.     unsigned arp_hash();
  255.     register struct arp_tab *ap;
  256.  
  257.     for(ap = arp_tab[arp_hash(hardware,ip_addr)]; ap != NULLARP; ap = ap->next){
  258.         if(ap->ip_addr == ip_addr && ap->hardware == hardware)
  259.             break;
  260.     }
  261.     return ap;
  262. }
  263. /* Send an ARP request to resolve IP address target_ip */
  264. static
  265. void
  266. arp_output(interface,hardware,target)
  267. struct interface *interface;
  268. int16 hardware;
  269. int32 target;
  270. {
  271.     struct arp arp;
  272.     struct mbuf *bp,*htonarp();
  273.     struct arp_type *at;
  274.  
  275.     at = &arp_type[hardware];
  276.     if(interface->output == NULLFP)
  277.         return;
  278.     
  279.     arp.hardware = hardware;
  280.     arp.protocol = at->iptype;
  281.     arp.hwalen = at->hwalen;
  282.     arp.pralen = sizeof(int32);
  283.     arp.opcode = ARP_REQUEST;
  284.     bcopy(interface->hwaddr,arp.shwaddr,at->hwalen);
  285.     arp.sprotaddr = ip_addr;
  286.     bzero(arp.thwaddr,at->hwalen);
  287.     arp.tprotaddr = target;
  288.     bp = htonarp(&arp);
  289.     (*interface->output)(interface,at->bdcst,
  290.         interface->hwaddr,at->arptype,bp);
  291.     arp_stat.outreq++;
  292. }
  293.  
  294. /* Hash a {hardware type, IP address} pair */
  295. static
  296. unsigned
  297. arp_hash(hardware,ip_addr)
  298. int16 hardware;
  299. int32 ip_addr;
  300. {
  301.     register unsigned hashval;
  302.  
  303.     hashval = hardware;
  304.     hashval ^= hiword(ip_addr);
  305.     hashval ^= loword(ip_addr);
  306.     hashval %= ARPSIZE;
  307.     return hashval;
  308. }        
  309. /* Copy a host format arp structure into mbuf for transmission */
  310. #ifdef    AMIGA
  311. /*
  312.  *  We play some dirty tricks here.  Since the AMIGA is a 68000 based
  313.  *  machine, it doesn't take kindly to doing word and long word stores 
  314.  *  on odd address boundaries.  We'll use bcopy() instead.  We can do
  315.  *  this simply because the 68000 is a big-endian machine, and we don't
  316.  *  need to convert to network byte order.  This is ugly.
  317.  */
  318. #endif
  319. static
  320. struct mbuf *
  321. htonarp(arp)
  322. register struct arp *arp;
  323. {
  324.     struct mbuf *bp;
  325.     register char *buf;
  326.  
  327.     if(arp == (struct arp *)NULL)
  328.         return NULLBUF;
  329.     if((bp = alloc_mbuf(sizeof(struct arp))) == NULLBUF)
  330.         return NULLBUF;
  331.  
  332.     buf = bp->data;
  333.  
  334.     *(int16 *)buf = htons(arp->hardware);
  335.     buf += sizeof(int16);
  336.  
  337.     *(int16 *)buf = htons(arp->protocol);
  338.     buf += sizeof(int16);
  339.  
  340.     *buf++ = arp->hwalen;
  341.  
  342.     *buf++ = arp->pralen;
  343.  
  344.     *(int16 *)buf = htons(arp->opcode);
  345.     buf += sizeof(int16);
  346.  
  347.     bcopy(arp->shwaddr,buf,arp->hwalen);
  348.     buf += arp->hwalen;
  349.  
  350. #ifndef    AMIGA
  351.     *(int32 *)buf = htonl(arp->sprotaddr);
  352. #else
  353.     /* we've been alright up to now, but arp->hwalen may have been
  354.        odd, so we don't know if buf is word aligned any more! */
  355.     bcopy(&arp->sprotaddr, buf, sizeof(int32));
  356. #endif
  357.     buf += sizeof(int32);
  358.  
  359.     bcopy(arp->thwaddr,buf,arp->hwalen);
  360.     buf += arp->hwalen;
  361.  
  362. #ifndef    AMIGA
  363.     *(int32 *)buf = htonl(arp->tprotaddr);
  364. #else
  365.     bcopy(&arp->tprotaddr, buf, sizeof(int32));
  366. #endif
  367.     buf += sizeof(int32);
  368.  
  369.     bp->cnt = buf - bp->data;
  370.     return bp;
  371. }
  372. /* Convert an incoming ARP packet into a host-format structure */
  373. static
  374. int
  375. ntoharp(arp,bp)
  376. register struct arp *arp;
  377. struct mbuf *bp;
  378. {
  379.     if(arp == (struct arp *)NULL || bp == NULLBUF)
  380.         return -1;
  381.  
  382.     pullup(&bp,(char *)&arp->hardware,sizeof(int16));
  383.     arp->hardware = ntohs(arp->hardware);
  384.  
  385.     pullup(&bp,(char *)&arp->protocol,sizeof(int16));
  386.     arp->protocol = ntohs(arp->protocol);
  387.  
  388.     pullup(&bp,(char *)&arp->hwalen,sizeof(char));
  389.  
  390.     pullup(&bp,(char *)&arp->pralen,sizeof(char));
  391.  
  392.     pullup(&bp,(char *)&arp->opcode,sizeof(int16));
  393.     arp->opcode = ntohs(arp->opcode);
  394.  
  395.     pullup(&bp,arp->shwaddr,arp->hwalen);
  396.  
  397.     pullup(&bp,(char *)&arp->sprotaddr,sizeof(int32));
  398.     arp->sprotaddr = ntohl(arp->sprotaddr);
  399.  
  400.     pullup(&bp,arp->thwaddr,arp->hwalen);
  401.  
  402.     pullup(&bp,(char *)&arp->tprotaddr,sizeof(int32));
  403.     arp->tprotaddr = ntohl(arp->tprotaddr);
  404.  
  405.     free_p(bp);
  406.     return 0;
  407. }
  408. #ifdef    TRACE
  409. char *arptypes[] = {
  410.     NULLCHAR,
  411.     "Ethernet",
  412.     "Exp Ethernet",
  413.     "AX.25",
  414.     "Pronet",
  415.     "Chaos"
  416. };
  417. int doarpadd(),doarpdrop();
  418. struct cmds arpcmds[] = {
  419.     "add", doarpadd, 4,
  420.     "usage: arp add <ip addr> ether|ax25 <callsign|ether addr>",
  421.     "arp add failed",
  422.  
  423.     "drop", doarpdrop, 3,
  424.     "usage: arp drop <ip addr> ether|ax25",
  425.     "not in table",
  426.  
  427.     NULLCHAR, NULLFP, 0,
  428.     "arp subcommands: add, drop",
  429.     NULLCHAR, 
  430. };
  431. int
  432. doarp(argc,argv)
  433. int argc;
  434. char *argv[];
  435. {
  436.     if(argc < 2){
  437.         dumparp();
  438.         return 0;
  439.     }
  440.     return subcmd(arpcmds,argc,argv);
  441. }
  442. static
  443. doarpadd(argc,argv)
  444. int argc;
  445. char *argv[];
  446. {
  447.     int hardware,hwalen,i;
  448.     int32 addr,aton();
  449.     char *malloc(),*hwaddr;
  450.     int naddr;
  451.     struct arp_tab *ap;
  452.     struct arp_type *at;
  453.     struct ax25_addr *axp;
  454.  
  455.     addr = aton(argv[1]);
  456.     /* This is a kludge. It really ought to be table driven */
  457.     switch(tolower(argv[2][0])){
  458.     case 'e':    /* "ether" */
  459.         hardware = ARP_ETHER;
  460.         naddr = 1;
  461.         break;        
  462.     case 'a':    /* "ax25" */
  463.         hardware = ARP_AX25;
  464.         naddr = argc - 3;
  465.         break;
  466.     default:
  467.         printf("unknown hardware type \"%s\"\r\n",argv[2]);
  468.         return -1;
  469.     }
  470.     /* If an entry already exists, clear it */
  471.     if((ap = arp_lookup(hardware,addr)) != NULLARP)
  472.         arp_drop(ap);
  473.  
  474.     at = &arp_type[hardware];
  475.  
  476.     /* Allocate buffer for hardware address and fill with remaining args */
  477.     hwalen = at->hwalen * naddr;
  478.     if((hwaddr = malloc(hwalen)) == NULLCHAR){
  479.         printf("No space\r\n");
  480.         return 0;
  481.     }
  482.     (*at->scan)(hwaddr,argv[3]);    /* Destination address */
  483.  
  484.     /* Special hackery to handle a series of AX.25 digipeaters */
  485.     if(hardware == ARP_AX25){
  486.         axp = (struct ax25_addr *)hwaddr;
  487.         for(i=1;i<naddr;i++){
  488.             /* Set E bit only on last AX.25 call */
  489.             axp->ssid &= ~E;
  490.             /* axp++; */
  491.             axp = (struct ax25_addr *) ((char *)axp + AXALEN);
  492.             (*at->scan)((char *)axp,argv[3+i]);
  493.         }
  494.     }
  495.     ap = arp_add(addr,hardware,hwaddr,hwalen);    /* Put in table */
  496.     free(hwaddr);                    /* Clean up */
  497.     stop_timer(&ap->timer);            /* Make entry permanent */
  498.     ap->timer.count = ap->timer.start = 0;
  499. }
  500. /* Remove an ARP entry */
  501. static
  502. doarpdrop(argc,argv)
  503. int argc;
  504. char *argv[];
  505. {
  506.     int hardware;
  507.     int32 addr,aton();
  508.     struct arp_tab *ap;
  509.  
  510.     addr = aton(argv[1]);
  511.     /* This is a kludge. It really ought to be table driven */
  512.     switch(tolower(argv[2][0])){
  513.     case 'e':    /* "ether" */
  514.         hardware = ARP_ETHER;
  515.         break;        
  516.     case 'a':    /* "ax25" */
  517.         hardware = ARP_AX25;
  518.         break;
  519.     default:
  520.         hardware = 0;
  521.         break;
  522.     }
  523.     if((ap = arp_lookup(hardware,addr)) == NULLARP)
  524.         return -1;
  525.     arp_drop(ap);
  526.     return 0;    
  527. }
  528. /* Dump ARP table */
  529. static
  530. dumparp()
  531. {
  532.     register int i;
  533.     extern struct arp_stat arp_stat;
  534.     register struct arp_tab *ap;
  535.     char e[128];
  536.     char *inet_ntoa();
  537.  
  538.     printf("received %u badtype %u reqst in %u replies %u reqst out %u\r\n",
  539.      arp_stat.recv,arp_stat.badtype,arp_stat.inreq,
  540.      arp_stat.replies,arp_stat.outreq);
  541.  
  542.     printf("IP addr         Type     Time Q Addr\r\n");
  543.     for(i=0;i<ARPSIZE;i++){
  544.         for(ap = arp_tab[i];ap != (struct arp_tab *)NULL;ap = ap->next){
  545.             printf("%-16s",inet_ntoa(ap->ip_addr));
  546.             printf("%-9s",arptypes[ap->hardware]);
  547.             printf("%-5ld",ap->timer.count*(long)MSPTICK/1000);
  548.             if(ap->state == ARP_PENDING)
  549.                 printf("%-2u",len_q(ap->pending));
  550.             else
  551.                 printf("  ");
  552.             if(ap->state == ARP_VALID){
  553.                 if(arp_type[ap->hardware].format != NULLFP){
  554.                     (*arp_type[ap->hardware].format)(e,ap->hw_addr);
  555.                 } else {
  556.                     e[0] = '\0';
  557.                 }
  558.                 printf("%s",e);
  559.             } else {
  560.                 printf("[unknown]");
  561.             }
  562.             printf("\r\n");
  563.         }
  564.     }
  565.     return 0;
  566. }
  567. /* Dump ARP packets (incomplete) */
  568. static char *hwtypes[] = {
  569.     "",
  570.     "10 Mb Ethernet",
  571.     "3 Mb Ethernet",
  572.     "AX.25",
  573.     NULLCHAR,
  574. };
  575. #define    NHWTYPES 4
  576. arp_dump(bp)
  577. struct mbuf *bp;
  578. {
  579.     struct arp arp;
  580.     struct mbuf *tbp;
  581.     char *inet_ntoa();
  582.  
  583.     if(bp == NULLBUF)
  584.         return;
  585.     /* Make temporary copy  */
  586.     dup_p(&tbp,bp,0,len_mbuf(bp));
  587.     ntoharp(&arp,tbp);
  588.  
  589.     if(arp.hardware < NHWTYPES)
  590.         printf("ARP: hwtype %s",hwtypes[arp.hardware]);
  591.     else
  592.         printf("ARP: hwtype %u",arp.hardware);
  593.     printf(" prot 0x%x hwlen %u prlen %u",
  594.         arp.protocol,arp.hwalen,arp.pralen);
  595.     switch(arp.opcode){
  596.     case ARP_REQUEST:
  597.         printf(" op REQUEST");
  598.         break;
  599.     case ARP_REPLY:
  600.         printf(" op REPLY");
  601.         break;
  602.     default:
  603.         printf(" op %u",arp.opcode);
  604.         break;
  605.     }
  606.     printf(" target %s\r\n",inet_ntoa(arp.tprotaddr));
  607. }
  608. #endif
  609.