home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
msr313src.tar.gz
/
msr313src.tar
/
msnarp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-12
|
13KB
|
466 lines
/* File MSNARP.C
* ARP and RARP packet processor
*
* Copyright (C) 1991, University of Waterloo.
* Copyright (C) 1985, 1993, Trustees of Columbia University in the
* City of New York. Permission is granted to any individual or institution
* to use this software as long as it is not sold for profit. This copyright
* notice must be retained. This software may not be included in commercial
* products without written permission of Columbia University.
*
* Original version created by Erick Engelke of the University of
* Waterloo, Waterloo, Ontario, Canada.
* Adapted and modified for MS-DOS Kermit by Joe R. Doupnik,
* Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
*
* Last edit
* 18 Dec 1992 v3.13
*
* Address Resolution Protocol
*
* Externals:
* ap_handler(pb) - returns 1 on handled correctly, 0 on problems
* arp_resolve - rets 1 on success, 0 on fail
* - does not return hardware address if passed NULL for buffer
*
*/
#include "msntcp.h"
#include "msnlib.h"
#ifdef KERMIT
#define MAX_ARP_DATA 10
#else
#define MAX_ARP_DATA 40
#endif /* KERMIT */
#define NEW_EXPIRY
#define MAX_ARP_ALIVE 300 /* five minutes */
#define MAX_ARP_GRACE 100 /* additional grace upon expiration */
#define PLEN 4 /* bytes in an IP address longword */
eth_address eth_none = { 0,0,0 };
/* ARP and RARP header. Note that address lengths and hardware type ident
vary depending on frame type at the hardware level. The frame handler
(Packet Driver or ODI driver) will set these values. jrd */
typedef struct {
word hwType; /* hardware type ident */
word protType; /* protocol ident */
byte hlen; /* length of MAC hardware address */
byte plen; /* plen, length of protocol address */
word opcode;
byte addr[6+6+2*PLEN]; /* address fields, frame dependent */
} arp_header;
typedef struct
{
longword ip;
eth_address hardware;
byte flags;
byte bits; /* bits in network */
longword expiry;
} arp_tables;
typedef struct
{
longword gate_ip;
longword subnet;
longword mask;
} gate_tables;
/* ARP style op codes */
#define ARP_REQUEST 0x0100
#define ARP_REPLY 0x0200
#define RARP_REQUEST 0x0300 /* RARP request */
#define RARP_REPLY 0x0400 /* RARP reply */
#define ARP_FLAG_NEED 0
#define ARP_FLAG_FOUND 1
#define ARP_FLAG_FIXED 255 /* cannot be removed */
extern longword ipbcast; /* IP broadcast address */
/* MAC_len and arp_hardware can be set by the packet frame routines */
word MAC_len = 6; /* bytes in MAC level hardware addr */
word arp_hardware = 0x0001; /* ARP, hardware ident, little end */
/*
* arp resolution cache - we zero fill it to save an initialization routine
*/
static arp_tables arp_data[MAX_ARP_DATA];
gate_tables arp_gate_data[MAX_GATE_DATA];
word arp_last_gateway = 0;
static word arp_index = 0; /* rotates round-robin */
/*
* arp_add_gateway - if data is NULL, don't use string
*/
void
arp_add_gateway(byte *data, longword ip)
{
word i;
register byte *subnetp, *maskp;
longword subnet, mask;
if ((data == NULL) && (ip == 0L)) return; /* nothing to do */
subnet = mask = 0;
if (data != NULL)
{
maskp = NULL;
if ((subnetp = strchr(data, ',')) != NULL)
{
*subnetp++ = 0;
if (maskp = strchr(subnetp, ','))
{
*maskp++ = 0;
mask = aton(maskp);
subnet = aton(subnetp);
}
else
{
subnet = aton(subnetp);
switch ((word)(subnet >> 30) & 0x000f)
{
case 0:
case 1: mask = 0xff000000L; break;
case 2: mask = 0xfffffe00L; break;
case 3: mask = 0xffffff00L; break;
}
}
}
}
if (arp_last_gateway >= MAX_GATE_DATA) return;
for (i = 0; i < arp_last_gateway; i++)
if (arp_gate_data[i].mask < mask)
{
bcopy(&arp_gate_data[i], &arp_gate_data[i+1],
(arp_last_gateway - i) * sizeof(gate_tables));
break;
}
if ((data != NULL) && (ip == 0L)) /* if text form given */
ip = aton(data); /* convert to 32 bit long */
arp_gate_data[i].gate_ip = ip;
arp_gate_data[i].subnet = subnet;
arp_gate_data[i].mask = mask;
arp_last_gateway++; /* used up another one */
}
longword
arp_rpt_gateway(int i) /* report IP of gateway i */
{
if (i >= 0 && i < MAX_GATE_DATA)
return (arp_gate_data[i].gate_ip);
else return (0L);
}
static void
arp_request(longword ip)
{
register arp_header *op;
longword temp;
if (ip == my_ip_addr)
return;
op = (arp_header *)eth_formatpacket(ð_brdcast[0], TYPE_ARP);
op->hwType = htons(arp_hardware); /* hardware frame */
op->protType = TYPE_IP; /* IP protocol */
op->hlen = (byte)(MAC_len & 0xff); /* MAC address len */
op->plen = PLEN; /* IP address len */
op->opcode = ARP_REQUEST;
bcopy(eth_addr, op->addr, MAC_len); /* our MAC address */
temp = htonl(my_ip_addr);
bcopy(&temp, &op->addr[MAC_len], PLEN); /* our IP */
temp = htonl(ip);
bcopy(&temp, &op->addr[2*MAC_len+PLEN], PLEN); /* host IP */
eth_send(sizeof(arp_header)); /* send the packet */
}
static arp_tables *
arp_search(longword ip, int create)
{
register int i;
register arp_tables *arp_ptr;
for (i = 0; i < MAX_ARP_DATA; i++)
if (ip == arp_data[i].ip)
return(&arp_data[i]);
/* didn't find any */
if (create != 0)
{ /* pick an old or empty one */
for (i = 0; i < MAX_ARP_DATA; i++)
{
arp_ptr = &arp_data[i];
if ((arp_ptr->ip == 0L) ||
chk_timeout(arp_ptr->expiry + MAX_ARP_GRACE))
return(arp_ptr);
}
/* pick one at pseudo-random */
return (&arp_data[arp_index =
(arp_index + 1) % MAX_ARP_DATA]);
}
return (NULL);
}
void
arp_register(longword use, longword instead_of)
{ /* new IP to use instead of this IP */
register arp_tables *arp_ptr;
if (arp_ptr = arp_search(instead_of, 0)) /* if in ARP cache */
{ /* insert Ethernet address of new IP */
arp_resolve(use, arp_ptr->hardware);
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
return;
}
arp_ptr = arp_search(use, 1); /* create a new one */
arp_ptr->flags = ARP_FLAG_NEED;
arp_ptr->ip = instead_of;
arp_resolve(use, arp_ptr->hardware);
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
}
void
arp_tick(longword ip)
{
register arp_tables *arp_ptr;
if (arp_ptr = arp_search(ip, 0))
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
}
/*
* arp_handler - handle incomming ARP packets
*/
int
arp_handler(arp_header *in)
{
register arp_header *op;
longword his_ip, temp;
register arp_tables *arp_ptr;
if (in == NULL) return (0); /* failure */
if (in->protType != TYPE_IP) /* IP protocol */
return(0); /* 0 means no, fail */
/* continuously accept data - but only for people we talk to */
bcopy(&in->addr[MAC_len], &his_ip, PLEN);
his_ip = ntohl(his_ip);
if ((arp_ptr = arp_search(his_ip, 0)) != NULL)/* do not create entry */
{
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
bcopy(in->addr, arp_ptr->hardware, MAC_len);
arp_ptr->flags = ARP_FLAG_FOUND;
}
/* does someone else want our hardware address? */
bcopy(&in->addr[2*MAC_len+PLEN], &temp, PLEN);
if (in->opcode == ARP_REQUEST && /* and be a resolution req */
temp == htonl(my_ip_addr)) /* for my IP */
{
op = (arp_header *)eth_formatpacket(in->addr, TYPE_ARP);
op->hwType = htons(arp_hardware);
op->protType = TYPE_IP; /* IP protocol */
op->hlen = (byte) (MAC_len & 0xff); /* MAC address len */
op->plen = PLEN; /* IP address len */
op->opcode = ARP_REPLY;
/* host's MAC and IP address */
bcopy(in->addr, &op->addr[MAC_len+PLEN], MAC_len + PLEN);
bcopy(eth_addr, op->addr, MAC_len); /* our MAC addr */
temp = htonl(my_ip_addr); /* our IP in net order */
bcopy(&temp, &op->addr[MAC_len], PLEN);
return (eth_send(sizeof(arp_header))); /* send the packet */
}
return (1); /* for success */
}
/*
* arp_resolve - resolve IP address to hardware address
*/
int
arp_resolve(longword ina, eth_address *ethap)
{
register arp_tables *arp_ptr;
register word i;
int j;
longword timeout, resend;
static int recurse = 0;
/* If we are running SLIP or ODI's SLIP_PPP which do not use
MAC level addresses */
if (pktdevclass == PD_SLIP ||
(pktdevclass == PD_ETHER && MAC_len == 0 ))
return(1);
if (ina == my_ip_addr)
{
if (ethap != NULL)
bcopy(eth_addr, ethap, MAC_len);
recurse = 0;
return(1); /* success */
}
if (ina == 0L || ina == 0xffffffffL || ina == ipbcast)
return (0); /* cannot resolve IP of 0's or 0xff's*/
if (recurse > 6) return (0); /* fail */
recurse++;
tcp_tick(NULL);
/* attempt to solve with ARP cache */
if ((arp_ptr = arp_search(ina, 0)) != NULL)
if (strncmp(arp_ptr->hardware, eth_none, MAC_len))
{ /* have non-NULL Ethernet address */
/* has been resolved */
#ifdef NEW_EXPIRY
if (chk_timeout(arp_ptr->expiry))
{
if (! chk_timeout(arp_ptr->expiry +
MAX_ARP_GRACE))
/* we wish to refresh it asynchronously */
arp_request(ina);
}
#endif /* NEW_EXPIRY */
if ((arp_ptr->flags == ARP_FLAG_FOUND) ||
(arp_ptr->flags == ARP_FLAG_FIXED))
{
/* we found a valid hardware address */
if (ethap != NULL)
{
bcopy(arp_ptr->hardware, ethap,
MAC_len);
recurse = 0;
return(1); /* success */
}
} /* end of if ((arp_ptr... */
} /* end of if (strncmp... main */
/* make a new one if necessary */
if (arp_ptr == NULL)
{
arp_ptr = arp_search(ina, 1); /* 1 means create an entry */
arp_ptr->flags = ARP_FLAG_NEED; /* say need a real entry */
}
/* we must look elsewhere - but is it on our subnet? */
if ((ina ^ my_ip_addr) & sin_mask) /* not of this network */
{
j = 0; /* init status return */
for (i = 0; i < arp_last_gateway; i++)
{ /* compare the various subnet bits */
if ((arp_gate_data[i].mask & ina) ==
arp_gate_data[i].subnet)
/* watch out RECURSIVE CALL! */
if ((j = arp_resolve(arp_gate_data[i].gate_ip,
ethap)) != 0)
break; /* success */
}
recurse--;
return (j);
}
if (ina == 0L) /* return if no host, or no gateway */
{
recurse--;
outs("\r\n Cannot find a gateway");
return(0); /* fail */
}
/* is on our subnet, we must resolve */
timeout = set_timeout(2); /* two seconds is long for ARP */
while (!chk_timeout(timeout))
{ /* do the request */
arp_request(arp_ptr->ip = ina);
resend = set_timeout(1) - 14L; /* 250 ms */
while (!chk_timeout(resend))
{
tcp_tick(NULL); /* read packets */
if (arp_ptr->flags)
{
if (ethap != NULL)
bcopy(arp_ptr->hardware, ethap,
MAC_len);
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
arp_ptr->flags = ARP_FLAG_FOUND;
recurse = 0;
return(1); /* success */
}
}
}
recurse--;
return(0); /* fail */
}
int
rarp_handler(arp_header *in)
{
register word i;
longword his_ip;
register arp_tables *arp_ptr;
if (in == NULL) return (0); /* failure */
if ((in->protType != TYPE_IP)) /* Internet protocol*/
return (0); /* 0 means no, fail */
bcopy(&in->addr[MAC_len], &his_ip, PLEN);
his_ip = ntohl(his_ip);
if ((arp_ptr = arp_search(his_ip, 0)) != NULL)
{
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
bcopy(in->addr, arp_ptr->hardware, MAC_len);
arp_ptr->flags = ARP_FLAG_FOUND;
}
/* look for RARP Reply */
if ((my_ip_addr == 0) && (in->opcode == RARP_REPLY))
{ /* match our Ethernet address too */
for (i = 0; i < MAC_len; i++)
if (in->addr[i+MAC_len+PLEN] != (byte)eth_addr[i])
return (1); /* not for us */
bcopy(&in->addr[2*MAC_len+PLEN], &my_ip_addr, PLEN);
my_ip_addr = ntohl(my_ip_addr); /* our IP addr */
}
return (1); /* for success */
}
/* send a RARP packet to request an IP address for our MAC address */
static void
arp_rev_request(void)
{
register arp_header *op;
op = (arp_header *)eth_formatpacket(ð_brdcast[0], TYPE_RARP);
op->hwType = htons(arp_hardware);
op->protType = TYPE_IP; /* IP protocol */
op->hlen = (byte)(MAC_len & 0xff); /* MAC address len */
op->plen = PLEN; /* IP address len */
op->opcode = RARP_REQUEST;
bcopy(eth_addr, op->addr, MAC_len); /* our MAC address */
bcopy(eth_addr, &op->addr[MAC_len+PLEN], MAC_len); /* in target too */
eth_send(sizeof(arp_header)); /* send the packet */
}
/* Send a series of RARP requests until our IP address is non-zero or
we timeout.
*/
int
do_rarp(void)
{
longword timeout, resend;
timeout = set_timeout(10); /* 10 seconds total */
while (chk_timeout(timeout) == 0)
{
arp_rev_request(); /* ask for our IP */
resend = set_timeout(1); /* two second retry */
while (chk_timeout(resend) == 0)
{
tcp_tick(NULL); /* read packets */
if (my_ip_addr != 0L) return (1); /* got a reply */
}
}
return (0); /* got no reply */
}