home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
msvp98b1.lzh
/
MSNARP.C
< prev
next >
Wrap
Text File
|
1993-05-14
|
13KB
|
477 lines
/* File MSNARP.C
* ARP and RARP packet processor
*
* Copyright (C) 1991, University of Waterloo.
* Copyright (C) 1985, 1992, 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
* 2 June 1992
*
* 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. */
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;
#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 = 0x0100; /* ARP, hardware kind ident */
/*
* 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 */
void
arp_init() /* init to zero ARP and arp_gateway tables */
{
static first_time = 0;
if (first_time == 0)
{
memset((byte *)arp_data, 0, sizeof(arp_tables) * MAX_ARP_DATA);
memset((byte *)arp_gate_data, 0,
sizeof(gate_tables) * MAX_GATE_DATA);
}
arp_last_gateway = 0; /* reset the gateway table */
first_time = 1; /* to keep arp_tables on hot start */
}
/*
* arp_add_gateway - if data is NULL, don't use string
*/
void
arp_add_gateway(byte *data, longword ip)
{
int 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 (i = (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;
op = (arp_header *)eth_formatpacket(ð_brdcast[0], 0x0608);
op->hwType = arp_hardware; /* hardware frame */
op->protType = 0x0008; /* IP protocol */
op->hlen = MAC_len; /* 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 */
if (ip == my_ip_addr)
return;
eth_send(8+2*MAC_len+2*PLEN); /* 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;
int i;
if (in == NULL) return (0); /* failure */
if (in->protType != 0x0008) /* 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, 0x0608);
op->hwType = arp_hardware;
op->protType = 0x0008; /* IP protocol */
op->hlen = MAC_len; /* 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(8+2*MAC_len+2*PLEN)); /* 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 int i;
int j;
longword timeout, resend;
static int recurse = 0;
if (pktdevclass == PD_SLIP)
/* we are running slip or something which does not use addresses */
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 int i;
longword his_ip;
register arp_tables *arp_ptr;
if (in == NULL) return (0); /* failure */
/* require Ethernet hardware and Internet software */
if ((in->protType != 0x0008))
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 Ethernet address */
static void
arp_rev_request(void)
{
register arp_header *op;
op = (arp_header *)eth_formatpacket(ð_brdcast[0], 0x3580); /*RARP */
op->hwType = arp_hardware;
op->protType = 0x0008; /* IP protocol */
op->hlen = MAC_len; /* 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(8+2*MAC_len+2*PLEN); /* 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 */
}