home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msr313src.zip / msnarp.c < prev    next >
C/C++ Source or Header  |  1993-07-12  |  13KB  |  466 lines

  1. /* File MSNARP.C
  2.  * ARP and RARP packet processor
  3.  *
  4.  * Copyright (C) 1991, University of Waterloo.
  5.  * Copyright (C) 1985, 1993, Trustees of Columbia University in the 
  6.  * City of New York.  Permission is granted to any individual or institution
  7.  * to use this software as long as it is not sold for profit.  This copyright
  8.  * notice must be retained.  This software may not be included in commercial
  9.  * products without written permission of Columbia University.
  10.  *
  11.  * Original version created by Erick Engelke of the University of
  12.  *  Waterloo, Waterloo, Ontario, Canada.
  13.  * Adapted and modified for MS-DOS Kermit by Joe R. Doupnik, 
  14.  *  Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
  15.  *
  16.  * Last edit
  17.  * 18 Dec 1992 v3.13
  18.  *
  19.  * Address Resolution Protocol
  20.  *
  21.  *  Externals:
  22.  *  ap_handler(pb) - returns 1 on handled correctly, 0 on problems
  23.  *  arp_resolve - rets 1 on success, 0 on fail
  24.  *               - does not return hardware address if passed NULL for buffer
  25.  *
  26.  */
  27. #include "msntcp.h"
  28. #include "msnlib.h"
  29.  
  30. #ifdef KERMIT
  31. #define MAX_ARP_DATA 10
  32. #else
  33. #define MAX_ARP_DATA 40
  34. #endif    /* KERMIT */
  35.  
  36. #define NEW_EXPIRY
  37. #define MAX_ARP_ALIVE  300        /* five minutes */
  38. #define MAX_ARP_GRACE  100        /* additional grace upon expiration */
  39. #define PLEN    4            /* bytes in an IP address longword */
  40.  
  41. eth_address eth_none = { 0,0,0 };
  42.  
  43. /* ARP and RARP header. Note that address lengths and hardware type ident
  44.    vary depending on frame type at the hardware level. The frame handler
  45.    (Packet Driver or ODI driver) will set these values. jrd */
  46.  
  47. typedef    struct {
  48.     word    hwType;            /* hardware type ident */
  49.     word    protType;        /* protocol ident */
  50.     byte    hlen;            /* length of MAC hardware address */
  51.     byte    plen;            /* plen, length of protocol address */
  52.     word    opcode;
  53.     byte    addr[6+6+2*PLEN];    /* address fields, frame dependent */
  54. } arp_header;
  55.  
  56. typedef struct
  57.     {
  58.     longword    ip;
  59.     eth_address    hardware;
  60.     byte        flags;
  61.     byte        bits;        /* bits in network */
  62.     longword    expiry;
  63.     } arp_tables;
  64.  
  65. typedef struct
  66.     {
  67.     longword    gate_ip;
  68.     longword    subnet;
  69.     longword    mask;
  70.     } gate_tables;
  71.  
  72. /* ARP style op codes */
  73. #define ARP_REQUEST 0x0100
  74. #define ARP_REPLY   0x0200
  75. #define RARP_REQUEST 0x0300        /* RARP request */
  76. #define RARP_REPLY  0x0400        /* RARP reply */
  77.  
  78. #define ARP_FLAG_NEED    0
  79. #define ARP_FLAG_FOUND  1
  80. #define ARP_FLAG_FIXED  255        /* cannot be removed */
  81. extern longword ipbcast;        /* IP broadcast address */
  82. /* MAC_len and arp_hardware can be set by the packet frame routines */
  83. word MAC_len = 6;            /* bytes in MAC level hardware addr */
  84. word arp_hardware = 0x0001;        /* ARP, hardware ident, little end */
  85. /*
  86.  * arp resolution cache - we zero fill it to save an initialization routine
  87.  */
  88.  
  89. static arp_tables arp_data[MAX_ARP_DATA];
  90. gate_tables arp_gate_data[MAX_GATE_DATA];
  91. word arp_last_gateway = 0;
  92. static word arp_index = 0;        /* rotates round-robin */
  93.  
  94. /*
  95.  * arp_add_gateway - if data is NULL, don't use string
  96.  */
  97. void 
  98. arp_add_gateway(byte *data, longword ip)
  99. {
  100.     word i;
  101.     register byte *subnetp, *maskp;
  102.     longword subnet, mask;
  103.  
  104.     if ((data == NULL) && (ip == 0L)) return;     /* nothing to do */
  105.     subnet = mask = 0;
  106.     if (data != NULL)
  107.         {
  108.         maskp = NULL;
  109.         if ((subnetp = strchr(data, ',')) != NULL)
  110.             {
  111.             *subnetp++ = 0;
  112.             if (maskp = strchr(subnetp, ','))
  113.                 {
  114.                 *maskp++ = 0;
  115.                 mask = aton(maskp);
  116.                 subnet = aton(subnetp);
  117.                 }
  118.             else
  119.                 {
  120.                 subnet = aton(subnetp);
  121.                 switch ((word)(subnet >> 30) & 0x000f)
  122.                     {
  123.                     case 0:
  124.                         case 1: mask = 0xff000000L; break;
  125.                     case 2: mask = 0xfffffe00L; break;
  126.                     case 3: mask = 0xffffff00L; break;
  127.                     }
  128.                 }
  129.             }
  130.             }
  131.  
  132.     if (arp_last_gateway >= MAX_GATE_DATA) return;
  133.  
  134.     for (i = 0; i < arp_last_gateway; i++)
  135.         if (arp_gate_data[i].mask < mask)
  136.             {
  137.             bcopy(&arp_gate_data[i], &arp_gate_data[i+1],
  138.                 (arp_last_gateway - i) * sizeof(gate_tables));
  139.             break;
  140.             }
  141.  
  142.     if ((data != NULL) && (ip == 0L))    /* if text form given */
  143.         ip = aton(data);        /* convert to 32 bit long */
  144.  
  145.     arp_gate_data[i].gate_ip = ip;
  146.     arp_gate_data[i].subnet = subnet;
  147.     arp_gate_data[i].mask = mask;
  148.     arp_last_gateway++;            /* used up another one */
  149. }
  150.  
  151. longword
  152. arp_rpt_gateway(int i)            /* report IP of gateway i */
  153. {
  154.     if (i >= 0 && i < MAX_GATE_DATA)
  155.         return (arp_gate_data[i].gate_ip);
  156.     else    return (0L);
  157. }
  158.  
  159. static void 
  160. arp_request(longword ip)
  161. {
  162.     register arp_header *op;
  163.     longword temp;
  164.  
  165.     if (ip == my_ip_addr)
  166.         return;
  167.     op = (arp_header *)eth_formatpacket(ð_brdcast[0], TYPE_ARP);
  168.     op->hwType = htons(arp_hardware);        /* hardware frame */
  169.     op->protType = TYPE_IP;                /* IP protocol */
  170.     op->hlen = (byte)(MAC_len & 0xff);        /* MAC address len */
  171.     op->plen = PLEN;                /* IP address len */
  172.     op->opcode = ARP_REQUEST;
  173.     bcopy(eth_addr, op->addr, MAC_len);        /* our MAC address */
  174.     temp = htonl(my_ip_addr);
  175.     bcopy(&temp, &op->addr[MAC_len], PLEN);        /* our IP */
  176.     temp = htonl(ip);
  177.     bcopy(&temp, &op->addr[2*MAC_len+PLEN], PLEN);    /* host IP */
  178.     eth_send(sizeof(arp_header));            /* send the packet */
  179. }
  180.  
  181. static arp_tables *
  182. arp_search(longword ip, int create)
  183. {
  184.     register int i;
  185.     register arp_tables *arp_ptr;
  186.  
  187.     for (i = 0; i < MAX_ARP_DATA; i++)
  188.         if (ip == arp_data[i].ip)
  189.                 return(&arp_data[i]);
  190.                         /* didn't find any */
  191.     if (create != 0)
  192.         {            /* pick an old or empty one */
  193.         for (i = 0; i < MAX_ARP_DATA; i++)
  194.             {
  195.             arp_ptr = &arp_data[i];
  196.             if ((arp_ptr->ip == 0L) ||
  197.                     chk_timeout(arp_ptr->expiry + MAX_ARP_GRACE))
  198.             return(arp_ptr);
  199.             }
  200.                     /* pick one at pseudo-random */
  201.         return (&arp_data[arp_index =
  202.                 (arp_index + 1) % MAX_ARP_DATA]);
  203.         }
  204.     return (NULL);
  205. }
  206.  
  207. void 
  208. arp_register(longword use, longword instead_of)
  209. {    /* new IP to use   instead of this IP */
  210.     register arp_tables *arp_ptr;
  211.  
  212.     if (arp_ptr = arp_search(instead_of, 0)) /* if in ARP cache */
  213.         {        /* insert Ethernet address of new IP */
  214.         arp_resolve(use, arp_ptr->hardware);
  215.         arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
  216.         return;
  217.         }
  218.     arp_ptr = arp_search(use, 1);        /* create a new one */
  219.     arp_ptr->flags = ARP_FLAG_NEED;
  220.     arp_ptr->ip = instead_of;
  221.     arp_resolve(use, arp_ptr->hardware);
  222.     arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
  223. }
  224.  
  225. void
  226. arp_tick(longword ip)
  227. {
  228.     register arp_tables *arp_ptr;
  229.  
  230.     if (arp_ptr = arp_search(ip, 0))
  231.         arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
  232. }
  233.  
  234. /*
  235.  * arp_handler - handle incomming ARP packets
  236.  */
  237. int
  238. arp_handler(arp_header *in)
  239. {
  240.     register arp_header *op;
  241.     longword his_ip, temp;
  242.     register arp_tables *arp_ptr;
  243.  
  244.     if (in == NULL) return (0);            /* failure */
  245.  
  246.     if (in->protType != TYPE_IP)            /* IP protocol */
  247.         return(0);                /* 0 means no, fail */
  248.  
  249.     /* continuously accept data - but only for people we talk to */
  250.     bcopy(&in->addr[MAC_len], &his_ip, PLEN);
  251.     his_ip = ntohl(his_ip);
  252.  
  253.     if ((arp_ptr = arp_search(his_ip, 0)) != NULL)/* do not create entry */
  254.         {
  255.         arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
  256.         bcopy(in->addr, arp_ptr->hardware, MAC_len);
  257.         arp_ptr->flags = ARP_FLAG_FOUND;
  258.         }
  259.  
  260.             /* does someone else want our hardware address? */
  261.     bcopy(&in->addr[2*MAC_len+PLEN], &temp, PLEN);
  262.     if (in->opcode == ARP_REQUEST &&        /* and be a resolution req */
  263.             temp ==    htonl(my_ip_addr))    /* for my IP */
  264.         {
  265.         op = (arp_header *)eth_formatpacket(in->addr, TYPE_ARP);
  266.         op->hwType = htons(arp_hardware);
  267.         op->protType = TYPE_IP;            /* IP protocol */
  268.         op->hlen = (byte) (MAC_len & 0xff);    /* MAC address len */
  269.         op->plen = PLEN;            /* IP address len */
  270.         op->opcode = ARP_REPLY;
  271.                         /* host's MAC and IP address */
  272.         bcopy(in->addr, &op->addr[MAC_len+PLEN], MAC_len + PLEN);
  273.         bcopy(eth_addr, op->addr, MAC_len); /* our MAC addr */
  274.         temp = htonl(my_ip_addr);    /* our IP in net order */
  275.         bcopy(&temp, &op->addr[MAC_len], PLEN);
  276.         return (eth_send(sizeof(arp_header)));    /* send the packet */
  277.         }
  278.     return (1);                    /* for success */
  279. }
  280.  
  281. /*
  282.  * arp_resolve - resolve IP address to hardware address
  283.  */
  284. int
  285. arp_resolve(longword ina, eth_address *ethap)
  286. {
  287.     register arp_tables *arp_ptr;
  288.     register word i;
  289.     int j;
  290.     longword timeout, resend;
  291.     static int recurse = 0;
  292.  
  293.     /* If we are running SLIP or ODI's SLIP_PPP which do not use
  294.                         MAC level addresses */
  295.     if (pktdevclass == PD_SLIP || 
  296.         (pktdevclass == PD_ETHER && MAC_len == 0 ))
  297.             return(1);
  298.  
  299.     if (ina == my_ip_addr)
  300.             {
  301.         if (ethap != NULL)
  302.             bcopy(eth_addr, ethap, MAC_len);
  303.         recurse = 0;
  304.         return(1);                /* success */
  305.         }
  306.     if (ina == 0L || ina == 0xffffffffL || ina == ipbcast)
  307.         return (0);    /* cannot resolve IP of 0's or 0xff's*/
  308.  
  309.     if (recurse > 6) return (0);            /* fail */
  310.     recurse++;
  311.     tcp_tick(NULL);
  312.                 /* attempt to solve with ARP cache */
  313.     if ((arp_ptr = arp_search(ina, 0)) != NULL)
  314.         if (strncmp(arp_ptr->hardware, eth_none, MAC_len))
  315.             {    /* have non-NULL Ethernet address */
  316.                          /* has been resolved */
  317. #ifdef NEW_EXPIRY
  318.             if (chk_timeout(arp_ptr->expiry))
  319.                 {
  320.                 if (! chk_timeout(arp_ptr->expiry +
  321.                     MAX_ARP_GRACE))
  322.                     /* we wish to refresh it asynchronously */
  323.                     arp_request(ina);
  324.                 }
  325. #endif /* NEW_EXPIRY */
  326.             if ((arp_ptr->flags == ARP_FLAG_FOUND) ||
  327.                 (arp_ptr->flags == ARP_FLAG_FIXED))
  328.                 {
  329.                         /* we found a valid hardware address */
  330.                 if (ethap != NULL)
  331.                         {
  332.                     bcopy(arp_ptr->hardware, ethap, 
  333.                         MAC_len);
  334.                     recurse = 0;
  335.                     return(1);        /* success */
  336.                     }
  337.                 }    /* end of if ((arp_ptr... */
  338.             }        /* end of if (strncmp... main */
  339.  
  340.                         /* make a new one if necessary */
  341.     if (arp_ptr == NULL)
  342.             {
  343.         arp_ptr = arp_search(ina, 1);    /* 1 means create an entry */
  344.         arp_ptr->flags = ARP_FLAG_NEED;    /* say need a real entry */
  345.         }
  346.  
  347.         /* we must look elsewhere - but is it on our subnet? */
  348.     if ((ina ^ my_ip_addr) & sin_mask)    /* not of this network */
  349.         {
  350.         j = 0;                /* init status return */
  351.         for (i = 0; i < arp_last_gateway; i++)
  352.             {        /* compare the various subnet bits */
  353.                 if ((arp_gate_data[i].mask & ina) == 
  354.                 arp_gate_data[i].subnet)
  355.                     /* watch out RECURSIVE CALL! */
  356.                 if ((j = arp_resolve(arp_gate_data[i].gate_ip,
  357.                     ethap)) != 0)
  358.                         break;        /* success */
  359.             }
  360.         recurse--;
  361.         return (j);
  362.             }
  363.  
  364.     if (ina == 0L)        /* return if no host, or no gateway */
  365.             {
  366.         recurse--;
  367.         outs("\r\n Cannot find a gateway");
  368.         return(0);                    /* fail */
  369.         }
  370.  
  371.                     /* is on our subnet, we must resolve */
  372.     timeout = set_timeout(2);    /* two seconds is long for ARP */
  373.     while (!chk_timeout(timeout))
  374.         {    /* do the request */
  375.         arp_request(arp_ptr->ip = ina);
  376.         resend = set_timeout(1) - 14L;        /* 250 ms */
  377.         while (!chk_timeout(resend))
  378.             {
  379.             tcp_tick(NULL);            /* read packets */
  380.             if (arp_ptr->flags)
  381.                 {
  382.                 if (ethap != NULL)
  383.                     bcopy(arp_ptr->hardware, ethap, 
  384.                         MAC_len);
  385.                 arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
  386.                 arp_ptr->flags = ARP_FLAG_FOUND;
  387.                 recurse = 0;
  388.                 return(1);            /* success */
  389.                 }
  390.             }
  391.             }
  392.     recurse--;
  393.     return(0);            /* fail */
  394. }
  395.  
  396.  
  397. int
  398. rarp_handler(arp_header *in)
  399. {
  400.     register word i;
  401.     longword his_ip;
  402.     register arp_tables *arp_ptr;
  403.  
  404.     if (in == NULL) return (0);            /* failure */
  405.  
  406.     if ((in->protType != TYPE_IP))            /* Internet protocol*/
  407.         return (0);                /* 0 means no, fail */
  408.     bcopy(&in->addr[MAC_len], &his_ip, PLEN);
  409.     his_ip = ntohl(his_ip);
  410.     if ((arp_ptr = arp_search(his_ip, 0)) != NULL)
  411.         {
  412.         arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
  413.         bcopy(in->addr, arp_ptr->hardware, MAC_len);
  414.         arp_ptr->flags = ARP_FLAG_FOUND;
  415.         }
  416.                     /* look for RARP Reply */
  417.     if ((my_ip_addr == 0) && (in->opcode == RARP_REPLY))
  418.         {              /* match our Ethernet address too */
  419.         for (i = 0; i < MAC_len; i++)
  420.             if (in->addr[i+MAC_len+PLEN] != (byte)eth_addr[i])
  421.                 return (1);        /* not for us */
  422.         bcopy(&in->addr[2*MAC_len+PLEN], &my_ip_addr, PLEN);
  423.         my_ip_addr = ntohl(my_ip_addr);        /* our IP addr */
  424.         }
  425.     return (1);                    /* for success */
  426. }
  427.  
  428. /* send a RARP packet to request an IP address for our MAC address */
  429. static void 
  430. arp_rev_request(void)
  431. {
  432.     register arp_header *op;
  433.  
  434.     op = (arp_header *)eth_formatpacket(ð_brdcast[0], TYPE_RARP);
  435.     op->hwType = htons(arp_hardware);
  436.     op->protType = TYPE_IP;                /* IP protocol */
  437.     op->hlen = (byte)(MAC_len & 0xff);        /* MAC address len */
  438.     op->plen = PLEN;                /* IP address len */
  439.     op->opcode = RARP_REQUEST;
  440.     bcopy(eth_addr, op->addr, MAC_len);        /* our MAC address */
  441.     bcopy(eth_addr, &op->addr[MAC_len+PLEN], MAC_len); /* in target too */
  442.     eth_send(sizeof(arp_header));            /* send the packet */
  443. }
  444.  
  445. /* Send a series of RARP requests until our IP address is non-zero or
  446.    we timeout.
  447. */
  448. int
  449. do_rarp(void)
  450. {
  451.     longword timeout, resend;
  452.  
  453.     timeout = set_timeout(10);            /* 10 seconds total */
  454.     while (chk_timeout(timeout) == 0)
  455.             {
  456.         arp_rev_request();            /* ask for our IP */
  457.         resend = set_timeout(1);        /* two second retry */
  458.         while (chk_timeout(resend) == 0)
  459.             {
  460.             tcp_tick(NULL);            /* read packets */
  461.             if (my_ip_addr != 0L) return (1); /* got a reply */
  462.             }
  463.         }
  464.     return (0);                    /* got no reply */
  465. }
  466.