⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bootpdip.c

📁 在51单片机上实现TCPIP协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:

#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 + -