📄 bootpdip.c
字号:
#include <stdio.h>
#include <time.h>
#include "global.h"
#include "arp.h"
#include "iface.h"
#include "mbuf.h"
#include "netuser.h"
#include "pktdrvr.h"
#include "timer.h"
#include "bootpd.h"
#define E_NOMEM 3101
#define ERR_NOIPADDRESS 3103 /* No IP address available. */
#define THRESH_ON 20 /* (%) When to turn on reclaimation of IP addresses. */
#define THRESH_CRITICAL 2 /* (#) */
#define THRESH_OFF 50 /* (%) */
#define R_OFF 0x01 /* Reclaimation is off. */
#define R_RECLAIM 0x02 /* Reclaimation is on. */
#define R_CRITICAL 0x04 /* Reclaimation is operating in critical state. */
#define R_DONE 0x08 /* Reclaimation is finishing up. */
#define V_SWAIT 0x10 /* Reclaimation is wait to start verif cycle. */
#define V_VERIFY 0x20 /* Reclaimation is in verification cycle. */
#define TIME_RWAIT (5) /* Time between running reclm da_task */
#define TIME_SWAIT (30) /* Time between cycles of starting address rec */
#define TIME_VWAIT (10) /* Time to wait between sending ARPs to verify add
resses. */
#define TIME_ADDRRETRY (4 * 600) /* Time to wait before trying to reclaim a
n address. */
#define TIME_ADDRRECLAIM (900) /* Time for which an address must be in the reclai
mation */
/* queue before being moved to the free list. */
#define RECLAIM_QUEUE_MAX 15 /* Maximum number of addresses in reclaimation queue. */
/* dynamic_ip.c
*
* This file contains code to manage a range of dynamic IP addresses on a network.
*/
/* Queue structures */
struct q_elt {
struct q_elt *next;
};
struct q {
char *head;
char *tail;
};
/* Dynamic IP structures */
struct daddr {
struct daddr *da_next; /* Queue link. */
int32 da_addr; /* IP address. */
time_t da_time; /* last time this address was answered for. */
uint8 da_hwaddr[1]; /* Hardware address, variable length. */
};
struct drange_desc {
struct drange_desc *dr_next; /* Queue link. */
struct iface *dr_iface; /* Pointer to network information. */
struct timer timer; /* Timer for reclaiming */
int32 dr_start; /* First IP address in range. */
int32 dr_end; /* Last IP address in range. */
uint16 dr_acount; /* Number of IP addresses in range. */
uint16 dr_fcount; /* Number of IP addresses in free. */
uint16 dr_rcount; /* Number of IP addresses on reclmation queue */
uint16 dr_thon; /* Threshold for turning on reclaimation. */
uint16 dr_thcritical; /* Threshold for critical reclaimation. */
uint16 dr_thoff; /* Threshold for turning off reclaimation. */
int32 dr_time_addrretry; /* Time to wait before retrying addresses.
Varies with state. */
uint16 dr_hwaddrlen; /* Length of hardware address. */
uint8 dr_rstate; /* Reclaimation state. */
uint8 dr_vstate; /* Verification state. */
time_t dr_rtime; /* Time stamp for reclaimation. */
struct daddr *dr_raddr; /* Address being verified. */
struct daddr *dr_table; /* Pointer to table of addresses. */
struct q dr_usedq; /* Pointer to list of used addresses. */
struct q dr_reclaimq; /* Pointer to list of addrs being reclaimed. */
struct q dr_freeq; /* Pointer to list of free addresses. */
};
#define da_structlen(dr) (sizeof (struct daddr) + dr->dr_hwaddrlen)
#define da_getnext(dr,da) ((struct daddr *) ((unsigned char *)da + da_structlen(dr)))
/*
* Globals.
*/
int ifaceToArpMap[] = {
0, /* CL_NONE */
ARP_ETHER, /* CL_ETHERNET */
ARP_PRONET, /* CL_PRONET_10 */
ARP_IEEE802, /* CL_IEEE8025 */
0, /* CL_OMNINET */
ARP_APPLETALK, /* CL_APPLETALK */
0, /* CL_SERIAL_LINE */
0, /* CL_STARLAN */
ARP_ARCNET, /* CL_ARCNET */
ARP_AX25, /* CL_AX25 */
0, /* CL_KISS */
0, /* CL_IEEE8023 */
0, /* CL_FDDI */
0, /* CL_INTERNET_X25 */
0, /* CL_LANSTAR */
0, /* CL_SLFP */
ARP_NETROM, /* CL_NETROM */
0 /* NCLASS */
};
static struct q rtabq;
struct timer da_timer;
char bp_ascii[128];
static void da_runtask(void *arg);
struct q_elt *q_dequeue(struct q *queue);
static void da_closeup(struct drange_desc *dr);
static void dprint_addresses(struct drange_desc *dr);
static int q_remove(struct q *source_queue,struct q_elt *qel);
static void iptoa(int32 ipaddr,char ipstr[16]);
static void da_task(void);
static int da_fill_reclaim(struct drange_desc *dr);
static void da_do_verify(struct drange_desc *dr,int pendtime);
static void da_enter_reclaim(struct drange_desc *dr);
static void da_enter_done(struct drange_desc *dr);
static void da_enter_off(struct drange_desc *dr);
static void q_enqueue(struct q *queue,struct q_elt *elem);
static int da_get_old_addr(struct drange_desc *dr,uint8 *hwaddr,struct daddr **dap);
static int da_get_free_addr(struct drange_desc *dr,struct daddr **dap);
static void da_enter_critical(struct drange_desc *dr);
static void q_init(struct q *queue);
extern int bp_ReadingCMDFile;
/*
* Shutdown routines.
*/
/*
* Done serving a network.
*/
da_done_net(iface)
struct iface *iface;
{
struct drange_desc *dr;
/* Find the network table */
for(dr = (struct drange_desc *) rtabq.head; dr != NULL; dr = dr->dr_next){
if(iface == dr->dr_iface)
break;
}
if(dr == NULL){
bp_log("Range for interface '%s' not found.\n", iface->name);
return -1;
}
da_closeup(dr);
bp_log("Range removed for iface %s\n", iface->name);
return 0;
}
/*
* Print the status of the da structures.
*/
void
da_status(iface)
struct iface *iface;
{
struct drange_desc *dr;
/* If no interface was specified, print all the range information */
if(iface == NULL){
for(dr = (struct drange_desc *) rtabq.head; dr != NULL;
dr = dr->dr_next)
dprint_addresses(dr);
} else {
/* Print the specified range's information */
/* Find the specified interface */
for(dr = (struct drange_desc *) rtabq.head;
(dr != NULL) && (dr->dr_iface != iface);
dr = dr->dr_next)
;
/* If network not found, return */
if(dr == NULL){
printf("Range for interface '%s' not found.\n", iface->name);
return;
}
/* The range has been found. Print it. */
dprint_addresses(dr);
}
}
/*
* Finish up service. Close up on each of the address ranges.
*/
void
da_shut()
{
struct drange_desc *dr;
stop_timer(&da_timer);
while((dr = (struct drange_desc *)q_dequeue (&rtabq)) != NULL)
da_closeup(dr);
}
/*
* Release resource for a network.
*/
static void
da_closeup(dr)
struct drange_desc *dr;
{
free(dr->dr_table); /* Free the address table. */
q_remove(&rtabq, (struct q_elt *)dr); /* Dequeue the range descriptor. */
free(dr); /* Free the range descriptor. */
}
/* This is only called from a command */
static void
dprint_addresses(dr)
struct drange_desc *dr;
{
struct daddr *da;
char ipa[16];
char ipb[16];
struct arp_type *at;
at = &Arp_type[dr->dr_iface->iftype->type];
iptoa(dr->dr_start, ipa);
iptoa(dr->dr_end, ipb);
printf("Interface %s range: %s - %s\n", dr->dr_iface->name, ipa, ipb);
da = (struct daddr *) dr->dr_freeq.head;
printf("Free address queue\n");
while(da){
iptoa(da->da_addr, ipa);
printf(" %s last used by %s\n", ipa,(*at->format)(bp_ascii, da->da_hwaddr));
da = da->da_next;
}
da = (struct daddr *) dr->dr_usedq.head;
printf("\nUsed address queue\n");
while(da){
iptoa(da->da_addr, ipa);
printf(" %s in use by %s\n", ipa, (*at->format)(bp_ascii, da->da_hwaddr));
da = da->da_next;
}
da =(struct daddr *) dr->dr_reclaimq.head;
printf("\nReclaimation address queue\n");
while(da){
iptoa(da->da_addr, ipa);
printf(" %s in use by %s?\n", ipa, (*at->format)(bp_ascii, da->da_hwaddr));
da = da->da_next;
}
printf("\n");
}
/*
* Reclaimation routines.
*/
static void
da_runtask(p)
void *p;
{
stop_timer(&da_timer);
da_task();
set_timer(&da_timer,TIME_RWAIT*1000L);
start_timer(&da_timer);
}
/*
* Called periodically to run reclaimation.
*/
static void
da_task()
{
struct drange_desc *dr;
time_t now;
int arpHardware, arpPendtime;
now = time(NULL);
for(dr = (struct drange_desc *)rtabq.head; dr != NULL; dr = dr->dr_next){
arpHardware = ifaceToArpMap [dr->dr_iface->iftype->type];
arpPendtime = Arp_type[arpHardware].pendtime;
if(!(dr->dr_rstate & R_OFF)){ /* If doing reclaimation on this range. */
if(dr->dr_vstate == V_SWAIT){ /* If in wait sub-state. */
/* Doing reclaimation on this range and am waiting to
* start a cycle of address
* verification. Check if it is time to start the
* cycle. */
if(now - dr->dr_rtime > TIME_SWAIT){
/* Start the cycle. */
if(!(dr->dr_rstate & R_DONE))
da_fill_reclaim(dr);
dr->dr_vstate = V_VERIFY; /* verify sub-state. */
dr->dr_raddr = NULL; /* start at beginning */
}
}
/* If in the verify state (may have just been changed above), and
* enough time has passed since last lookup, check it and start
* the next lookup. */
if(dr->dr_vstate == V_VERIFY){
if(now - dr->dr_rtime > arpPendtime){
da_do_verify(dr, arpPendtime); /* Verify address. */
dr->dr_rtime = time(NULL); /* Set time stamp. */
if(dr->dr_raddr == NULL){ /* If at end... */
dr->dr_vstate = V_SWAIT; /* Q empty; enter wait sub-state. */
}
}
}
/*
* State transitions. May have moved some addresses to free list.
* If so, I may be able to move to a "lower" state.
*/
switch(dr->dr_rstate){
/* case R_OFF: Not handled. */
case R_CRITICAL:
/* Have conditions droped below critical threshhold? */
if(dr->dr_fcount > dr->dr_thcritical)
da_enter_reclaim(dr);
/* Fall through. */
case R_RECLAIM:
/* Have I reclaimed enough addresses? */
if(dr->dr_fcount > dr->dr_thoff)
da_enter_done(dr);
/* Fall through. */
case R_DONE:
/* Am I in the done state and have exausted the reclaimation queue? */
if((dr->dr_rstate & R_DONE) && dr->dr_reclaimq.head == NULL)
da_enter_off(dr);
break;
}
}
}
}
/*
* Enter the DONE state. Can't get to the done state from the off state.
*/
static void
da_enter_done(dr)
struct drange_desc *dr;
{
char ipa[16], ipb[16];
iptoa(dr->dr_start, ipa);
iptoa(dr->dr_end, ipb);
if((dr->dr_rstate & R_OFF) == 0){
dr->dr_rstate = R_DONE;
dr->dr_time_addrretry = TIME_ADDRRETRY; /* Wait a while before retrying addresses. */
}
}
/*
* Enter the OFF state.
*/
static void
da_enter_off(dr)
struct drange_desc *dr;
{
char ipa[16], ipb[16];
iptoa(dr->dr_start, ipa);
iptoa(dr->dr_end, ipb);
dr->dr_rstate = R_OFF;
}
/*
* Verify addresses.
* To avoid flodding the network and our address resolution queue I only send
* out one ARP at a time. This routine is called periodically to step through
* the reclaimation queue. The first step is to check for a responce to the
* ARP that was sent out previously. If there is a responce I move the address
* to the used queue. The next step is to send out an ARP for the next address
* on the recliamation queue. After a suitable intervel (TIME_VTIME) I'll be
* called again.
*/
static void
da_do_verify(dr, pendtime)
struct drange_desc *dr;
int pendtime;
{
struct daddr *da, *dn;
struct iface *iface;
long now;
struct arp_tab *ap;
uint16 arpType;
now = time(NULL);
iface = dr->dr_iface;
arpType = ifaceToArpMap[iface->iftype->type];
/*
* If I sent an ARP for an address, check if that ARP has been responded to.
* If dr_raddr points to an address record, I have previously sent an
* ARP for that address. Check the ARP cache for a responce.
* If dr_raddr is NULL then I am to start at the head of the reclaim queue.
*/
if(dr->dr_raddr != NULL){
/* ARP has been sent for dr_raddr. Check the ARP cache for a responce. */
da = dr->dr_raddr;
dn = da->da_next;
ap = arp_lookup(arpType, da->da_addr);
if((ap != NULL) && (ap->state == ARP_VALID)){
/* Host responded to arp. Place address on used queue.
* Copy in physical address of host using address to
* make sure our info is up to date.
* I could verify that physical address of host
* responding to ARP matches the physical address of
* the host I think owns the address. If don't match
* someone is probably using an incorrect address.
*/
q_remove(&dr->dr_reclaimq, (struct q_elt *)da);
--dr->dr_rcount;
da->da_time = now; /* Time tested. */
memcpy(da->da_hwaddr, ap->hw_addr, Arp_type[ap->hardware].hwalen);
q_enqueue(&dr->dr_usedq, (struct q_elt *)da);
} else {
/* Host did not respond to ARP. If addr on reclaim
* queue long enough, move it to the free queue.
*/
if(now - da->da_time >= pendtime){
q_remove(&dr->dr_reclaimq, (struct q_elt *)da);
--dr->dr_rcount;
q_enqueue(&dr->dr_freeq,(struct q_elt *)da);
++dr->dr_fcount;
bp_log("Reclaimed address %s on net %s.\n",
inet_ntoa(da->da_addr), dr->dr_iface->name);
}
}
} else {
/* Use first addr in reclaimq. */
dn = (struct daddr *) dr->dr_reclaimq.head;
}
/*
* Now move to the next entry in the queue and ARP for it.
*/
da = dn;
if(da != NULL){
ap = arp_lookup(arpType, da->da_addr);
if(ap != NULL) arp_drop(ap);
res_arp(iface, arpType, da->da_addr, NULL);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -