bootpdip.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:29k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  * BOOTP is documented in RFC 951 and RFC 1048
  9.  *
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12. /* Dynamic Ip Assignment for a Bootp Server
  13.  * Called when a client request is received and the bootp server doesnt' have a
  14.  * record for it.
  15.  *
  16.  * Design goals:
  17.  *   Assign an IP address
  18.  *   Separation/Identification of IP addresses assigned and not assigned
  19.  *   Time out mechanism to reclaim IP address
  20.  * Timer, and arp on address with little activity
  21.  *   Reassignment to same machine if possible.
  22.  */     
  23. #include <stdio.h>
  24. #include <time.h>
  25. #include "global.h"
  26. #include "arp.h"
  27. #include "iface.h"
  28. #include "mbuf.h"
  29. #include "netuser.h"
  30. #include "pktdrvr.h"
  31. #include "timer.h"
  32. #include "bootpd.h"
  33. #define E_NOMEM 3101
  34. #define ERR_NOIPADDRESS 3103 /* No IP address available. */
  35. #define THRESH_ON            20    /* (%) When to turn on reclaimation of IP addresses. */
  36. #define THRESH_CRITICAL       2    /* (#) */
  37. #define THRESH_OFF           50    /* (%) */
  38. #define R_OFF                   0x01    /* Reclaimation is off. */
  39. #define R_RECLAIM               0x02    /* Reclaimation is on. */
  40. #define R_CRITICAL              0x04    /* Reclaimation is operating in critical state. */
  41. #define R_DONE                  0x08    /* Reclaimation is finishing up. */
  42. #define V_SWAIT                 0x10    /* Reclaimation is wait to start verif cycle. */
  43. #define V_VERIFY                0x20    /* Reclaimation is in verification cycle. */
  44. #define TIME_RWAIT (5)  /* Time between running reclm da_task */
  45. #define TIME_SWAIT              (30)    /* Time between cycles of starting address rec */
  46. #define TIME_VWAIT              (10)    /* Time to wait between sending ARPs to verify add
  47. resses. */
  48. #define TIME_ADDRRETRY          (4 * 600)       /* Time to wait before trying to reclaim a
  49. n address. */
  50. #define TIME_ADDRRECLAIM        (900)   /* Time for which an address must be in the reclai
  51. mation */
  52.                                         /* queue before being moved to the free list. */
  53. #define RECLAIM_QUEUE_MAX       15      /* Maximum number of addresses in reclaimation queue. */
  54. /*      dynamic_ip.c
  55.  *
  56.  * This file contains code to manage a range of dynamic IP addresses on a network.
  57.  */
  58. /* Queue structures  */
  59. struct  q_elt {
  60.         struct  q_elt *next;
  61. };
  62. struct  q {
  63.         char *head;
  64.         char *tail;
  65. };
  66. /* Dynamic IP structures */
  67. struct daddr {
  68.         struct daddr *da_next;       /* Queue link. */
  69.         int32 da_addr;        /* IP address. */
  70.         time_t da_time;        /* last time this address was answered for. */
  71. uint8 da_hwaddr[1];   /* Hardware address, variable length. */
  72. };
  73. struct drange_desc {
  74.         struct drange_desc *dr_next;    /* Queue link. */
  75.         struct iface    *dr_iface;      /* Pointer to network information. */
  76. struct timer timer; /* Timer for reclaiming */
  77.         int32     dr_start;       /* First IP address in range. */
  78.         int32     dr_end;         /* Last IP address in range. */
  79.         uint16           dr_acount;      /* Number of IP addresses in range. */
  80.         uint16           dr_fcount;      /* Number of IP addresses in free. */
  81.         uint16           dr_rcount;      /* Number of IP addresses on reclmation queue  */
  82.         uint16           dr_thon;        /* Threshold for turning on reclaimation. */
  83.         uint16           dr_thcritical;  /* Threshold for critical reclaimation. */
  84.         uint16           dr_thoff;       /* Threshold for turning off reclaimation. */
  85.         int32           dr_time_addrretry;      /* Time to wait before retrying addresses.
  86.    Varies with state. */
  87.         uint16           dr_hwaddrlen;   /* Length of hardware address. */
  88. uint8   dr_rstate;      /* Reclaimation state. */
  89. uint8   dr_vstate;      /* Verification state. */
  90.         time_t          dr_rtime;       /* Time stamp for reclaimation. */
  91.         struct daddr    *dr_raddr;      /* Address being verified. */
  92.         struct daddr    *dr_table;      /* Pointer to table of addresses. */
  93.         struct q        dr_usedq;       /* Pointer to list of used addresses. */
  94.         struct q        dr_reclaimq;    /* Pointer to list of addrs being reclaimed.  */
  95.         struct q        dr_freeq;       /* Pointer to list of free addresses. */
  96. };
  97. #define da_structlen(dr)        (sizeof (struct daddr) + dr->dr_hwaddrlen)
  98. #define da_getnext(dr,da)       ((struct daddr *) ((unsigned char *)da + da_structlen(dr)))
  99. /*
  100.  * Globals.
  101.  */
  102. int ifaceToArpMap[] = {
  103.         0,                          /* CL_NONE */
  104.         ARP_ETHER,                          /* CL_ETHERNET */
  105.         ARP_PRONET,                          /* CL_PRONET_10 */
  106.         ARP_IEEE802,                         /* CL_IEEE8025 */
  107.         0,                          /* CL_OMNINET */
  108.         ARP_APPLETALK,                          /* CL_APPLETALK */
  109.         0,                             /* CL_SERIAL_LINE */
  110.         0,                          /* CL_STARLAN */
  111.         ARP_ARCNET,                          /* CL_ARCNET */
  112.         ARP_AX25,                               /* CL_AX25 */
  113.         0,                                      /* CL_KISS */
  114.         0,                                      /* CL_IEEE8023 */
  115.         0,                                      /* CL_FDDI */
  116.         0,                                      /* CL_INTERNET_X25 */
  117.         0,                                      /* CL_LANSTAR */
  118.         0,                                      /* CL_SLFP */
  119.         ARP_NETROM,                             /* CL_NETROM */
  120.         0                                       /* NCLASS */
  121. };
  122. static struct q                 rtabq;
  123. struct timer da_timer;
  124. char bp_ascii[128];
  125. static void da_runtask(void *arg);
  126. struct q_elt *q_dequeue(struct q *queue);
  127. static void da_closeup(struct drange_desc *dr);
  128. static void dprint_addresses(struct drange_desc *dr);
  129. static int q_remove(struct q *source_queue,struct q_elt *qel);
  130. static void iptoa(int32 ipaddr,char ipstr[16]);
  131. static void da_task(void);
  132. static int da_fill_reclaim(struct drange_desc *dr);
  133. static void da_do_verify(struct drange_desc *dr,int pendtime);
  134. static void da_enter_reclaim(struct drange_desc *dr);
  135. static void da_enter_done(struct drange_desc *dr);
  136. static void da_enter_off(struct drange_desc *dr);
  137. static void q_enqueue(struct q  *queue,struct q_elt *elem);
  138. static int da_get_old_addr(struct drange_desc *dr,uint8 *hwaddr,struct daddr **dap);
  139. static int da_get_free_addr(struct drange_desc *dr,struct daddr **dap);
  140. static void da_enter_critical(struct drange_desc *dr);
  141. static void q_init(struct q *queue);
  142. extern int bp_ReadingCMDFile;
  143. /*
  144.  * Shutdown routines.
  145.  */
  146. /*
  147.  * Done serving a network.
  148.  */
  149. da_done_net(iface)
  150. struct iface *iface;
  151. {
  152.         struct drange_desc *dr;
  153.         /* Find the network table */
  154.         for(dr = (struct drange_desc *) rtabq.head; dr != NULL; dr = dr->dr_next){
  155.                 if(iface == dr->dr_iface)
  156.                         break;
  157.         }
  158.         if(dr == NULL){
  159. bp_log("Range for interface '%s' not found.n", iface->name);
  160. return -1;
  161. }
  162.         da_closeup(dr);
  163. bp_log("Range removed for iface %sn", iface->name);
  164.         return 0;
  165. }
  166. /*
  167.  * Print the status of the da structures.
  168.  */
  169. void
  170. da_status(iface)
  171. struct iface *iface;
  172. {
  173.         struct drange_desc *dr;
  174. /* If no interface was specified, print all the range information */
  175. if(iface == NULL){
  176.          for(dr = (struct drange_desc *) rtabq.head; dr != NULL; 
  177.  dr = dr->dr_next) 
  178. dprint_addresses(dr);
  179. } else {
  180. /* Print the specified range's information */
  181. /* Find the specified interface */
  182.          for(dr = (struct drange_desc *) rtabq.head; 
  183.  (dr != NULL) && (dr->dr_iface != iface); 
  184.  dr = dr->dr_next)
  185. /* If network not found, return */
  186. if(dr == NULL){
  187. printf("Range for interface '%s' not found.n", iface->name);
  188. return;
  189. }
  190. /* The range has been found.  Print it. */
  191. dprint_addresses(dr);
  192. }
  193. }
  194. /*
  195.  * Finish up service.  Close up on each of the address ranges.
  196.  */
  197. void
  198. da_shut()
  199. {
  200.         struct drange_desc *dr;
  201. stop_timer(&da_timer);
  202.         while((dr = (struct drange_desc *)q_dequeue (&rtabq)) != NULL)
  203.                 da_closeup(dr);
  204. }
  205. /*
  206.  * Release resource for a network.
  207.  */
  208. static void
  209. da_closeup(dr)
  210. struct drange_desc *dr;
  211. {
  212.         free(dr->dr_table); /* Free the address table. */
  213.         q_remove(&rtabq, (struct q_elt *)dr); /* Dequeue the range descriptor. */
  214.         free(dr); /* Free the range descriptor. */
  215. }
  216. /* This is only called from a command */
  217. static void
  218. dprint_addresses(dr)
  219. struct drange_desc *dr;
  220. {
  221.         struct daddr *da;
  222.         char ipa[16];
  223. char ipb[16];
  224. struct arp_type *at;
  225. at = &Arp_type[dr->dr_iface->iftype->type];
  226. iptoa(dr->dr_start, ipa);
  227. iptoa(dr->dr_end, ipb);
  228. printf("Interface %s range: %s - %sn", dr->dr_iface->name, ipa, ipb);
  229.         da = (struct daddr *) dr->dr_freeq.head;
  230. printf("Free address queuen");
  231.         while(da){
  232.                 iptoa(da->da_addr, ipa);
  233.                 printf("    %s  last used by %sn", ipa,(*at->format)(bp_ascii, da->da_hwaddr));
  234.                 da = da->da_next;
  235.         }
  236.         da = (struct daddr *) dr->dr_usedq.head;
  237.         printf("nUsed address queuen");
  238.         while(da){
  239.                 iptoa(da->da_addr, ipa);
  240.                 printf("    %s  in use by %sn", ipa, (*at->format)(bp_ascii, da->da_hwaddr));
  241.                 da = da->da_next;
  242.         }
  243.         da =(struct daddr *) dr->dr_reclaimq.head;
  244.         printf("nReclaimation address queuen");
  245.         while(da){
  246.                 iptoa(da->da_addr, ipa);
  247.                 printf("    %s  in use by %s?n", ipa, (*at->format)(bp_ascii, da->da_hwaddr));
  248.                 da = da->da_next;
  249.         }
  250.         printf("n");
  251. }
  252. /*
  253.  * Reclaimation routines.
  254.  */
  255. static void
  256. da_runtask(p)
  257. void *p;
  258. {
  259. stop_timer(&da_timer);
  260. da_task();
  261. set_timer(&da_timer,TIME_RWAIT*1000L);
  262. start_timer(&da_timer);
  263. }
  264. /*
  265.  * Called periodically to run reclaimation.
  266.  */
  267. static void
  268. da_task()
  269. {
  270. struct drange_desc *dr;
  271. time_t now;
  272. int arpHardware, arpPendtime;
  273. now = time(NULL);
  274. for(dr = (struct drange_desc *)rtabq.head; dr != NULL; dr = dr->dr_next){
  275. arpHardware = ifaceToArpMap [dr->dr_iface->iftype->type];
  276. arpPendtime = Arp_type[arpHardware].pendtime;
  277. if(!(dr->dr_rstate & R_OFF)){ /* If doing reclaimation on this range. */
  278. if(dr->dr_vstate == V_SWAIT){ /* If in wait sub-state. */
  279. /* Doing reclaimation on this range and am waiting to 
  280.  * start a cycle of address
  281.  * verification.  Check if it is time to start the 
  282.  * cycle. */
  283. if(now - dr->dr_rtime > TIME_SWAIT){
  284. /* Start the cycle.  */
  285. if(!(dr->dr_rstate & R_DONE))
  286. da_fill_reclaim(dr);
  287. dr->dr_vstate = V_VERIFY; /* verify sub-state. */
  288. dr->dr_raddr = NULL; /* start at beginning */
  289. }
  290. }
  291. /* If in the verify state (may have just been changed above), and 
  292.  * enough time has passed since last lookup, check it and start
  293.  * the next lookup. */
  294. if(dr->dr_vstate == V_VERIFY){
  295. if(now - dr->dr_rtime > arpPendtime){
  296. da_do_verify(dr, arpPendtime); /* Verify address. */
  297. dr->dr_rtime = time(NULL); /* Set time stamp. */
  298. if(dr->dr_raddr == NULL){ /* If at end... */
  299. dr->dr_vstate = V_SWAIT; /* Q empty; enter wait sub-state. */
  300. }
  301. }
  302. }
  303. /* 
  304.  * State transitions.  May have moved some addresses to free list.
  305.  * If so, I may be able to move to a "lower" state.
  306.  */
  307. switch(dr->dr_rstate){
  308. /* case R_OFF: Not handled. */
  309. case R_CRITICAL:
  310. /* Have conditions droped below critical threshhold? */
  311. if(dr->dr_fcount > dr->dr_thcritical)
  312. da_enter_reclaim(dr);
  313. /* Fall through. */
  314. case R_RECLAIM:
  315. /* Have I reclaimed enough addresses? */
  316. if(dr->dr_fcount > dr->dr_thoff)
  317. da_enter_done(dr);
  318. /* Fall through. */
  319. case R_DONE:
  320. /* Am I in the done state and have exausted the reclaimation queue? */
  321. if((dr->dr_rstate & R_DONE) && dr->dr_reclaimq.head == NULL) 
  322. da_enter_off(dr);
  323. break;
  324. }
  325. }
  326. }
  327. }
  328. /* 
  329.  * Enter the DONE state.  Can't get to the done state from the off state.
  330.  */
  331. static void
  332. da_enter_done(dr)
  333. struct drange_desc *dr;
  334. {
  335. char ipa[16], ipb[16];
  336. iptoa(dr->dr_start, ipa);
  337. iptoa(dr->dr_end, ipb);
  338. if((dr->dr_rstate & R_OFF) == 0){ 
  339. dr->dr_rstate = R_DONE;
  340. dr->dr_time_addrretry = TIME_ADDRRETRY; /* Wait a while before retrying addresses. */
  341. }
  342. }
  343. /* 
  344.  * Enter the OFF state.
  345.  */
  346. static void
  347. da_enter_off(dr)
  348. struct drange_desc *dr;
  349. {
  350. char ipa[16], ipb[16];
  351. iptoa(dr->dr_start, ipa);
  352. iptoa(dr->dr_end, ipb);
  353. dr->dr_rstate = R_OFF;
  354. }
  355. /*
  356.  * Verify addresses.
  357.  * To avoid flodding the network and our address resolution queue I only send
  358.  * out one ARP at a time.  This routine is called periodically to step through
  359.  * the reclaimation queue.  The first step is to check for a responce to the
  360.  * ARP that was sent out previously.  If there is a responce I move the address
  361.  * to the used queue. The next step is to send out an ARP for the next address
  362.  * on the recliamation queue. After a suitable intervel (TIME_VTIME) I'll be
  363.  * called again.
  364.  */
  365. static void
  366. da_do_verify(dr, pendtime)
  367. struct drange_desc *dr;
  368. int pendtime;
  369. {
  370. struct daddr *da, *dn;
  371. struct iface *iface;
  372. long now;
  373. struct arp_tab *ap;
  374. uint16 arpType;
  375.   now = time(NULL);
  376.   iface = dr->dr_iface;
  377. arpType = ifaceToArpMap[iface->iftype->type];
  378. /*
  379.    * If I sent an ARP for an address, check if that ARP has been responded to.
  380.  * If dr_raddr points to an address record, I have previously sent an
  381.  * ARP for that address.  Check the ARP cache for a responce.
  382.  * If dr_raddr is NULL then I am to start at the head of the reclaim queue.
  383.    */
  384. if(dr->dr_raddr != NULL){
  385. /* ARP has been sent for dr_raddr.  Check the ARP cache for a responce. */
  386. da = dr->dr_raddr;
  387. dn = da->da_next;
  388. ap = arp_lookup(arpType, da->da_addr);
  389. if((ap != NULL) && (ap->state == ARP_VALID)){
  390. /* Host responded to arp.  Place address on used queue.
  391.  * Copy in physical address of host using address to
  392.  * make sure our info is up to date.  
  393.  * I could verify that physical address of host
  394.  * responding to  ARP matches the physical address of
  395.  * the host I think owns the address.  If don't match
  396.  * someone is probably using an incorrect address.
  397.  */
  398. q_remove(&dr->dr_reclaimq, (struct q_elt *)da);
  399. --dr->dr_rcount;
  400. da->da_time = now; /* Time tested. */
  401. memcpy(da->da_hwaddr, ap->hw_addr, Arp_type[ap->hardware].hwalen);
  402. q_enqueue(&dr->dr_usedq, (struct q_elt *)da);
  403. } else {
  404. /* Host did not respond to ARP.  If addr on reclaim
  405.  * queue long enough, move it to the free queue.
  406.  */
  407. if(now - da->da_time >= pendtime){
  408. q_remove(&dr->dr_reclaimq, (struct q_elt *)da);
  409. --dr->dr_rcount;
  410. q_enqueue(&dr->dr_freeq,(struct q_elt *)da);
  411. ++dr->dr_fcount;
  412. bp_log("Reclaimed address %s on net %s.n", 
  413. inet_ntoa(da->da_addr), dr->dr_iface->name);
  414. }
  415. }
  416. } else {
  417. /* Use first addr in reclaimq. */
  418. dn = (struct daddr *) dr->dr_reclaimq.head;
  419. }
  420. /*
  421.    * Now move to the next entry in the queue and ARP for it.
  422.    */
  423.   da = dn;
  424. if(da != NULL){
  425. ap = arp_lookup(arpType, da->da_addr);
  426. if(ap != NULL) arp_drop(ap);
  427. res_arp(iface, arpType, da->da_addr, NULL);
  428. }
  429. dr->dr_raddr = da; /* Verify this address next time around. */
  430. dr->dr_rtime = time(NULL);
  431. }
  432. /*
  433.  * Fill the reclaimation list from the used list.  Take addresses off the head
  434.  * of the used queue until the reclaim queue is full, the used queue is empty,
  435.  * or the address at the head of the used queue has been verified (responded
  436.  * to an ARP) within dr_time_addrretry tocks.
  437.  */
  438. static int
  439. da_fill_reclaim(dr)
  440. struct drange_desc *dr;
  441. {
  442.         struct daddr *da;
  443.         long now;
  444.         now = time(NULL);
  445.         while(dr->dr_rcount < RECLAIM_QUEUE_MAX){
  446. /* Look at first address on used queue. */
  447.                 da = (struct daddr *) dr->dr_usedq.head;
  448.                 if(da == NULL)
  449. return 0;    /* If used queue is empty, done filling. */
  450.                 if(now - da->da_time < dr->dr_time_addrretry)
  451.                         return 0;
  452. /* If the first element has responded to in ARP recently.
  453.  * I am done filling.
  454.  */
  455. /* Get first address on used queue. */
  456.                 da = (struct daddr *) q_dequeue(&dr->dr_usedq);
  457. /* Mark time addr put in reclaim queue. */
  458.                 da->da_time = now;
  459. /* Put it at end of reclaim queue. */
  460.                 q_enqueue(&dr->dr_reclaimq,(struct q_elt *)da);
  461.                 ++dr->dr_rcount;
  462.         }
  463.         return 0;
  464. }
  465. /*
  466.  * Address assignment routines.
  467.  */
  468. /*
  469.  * Assign an address.
  470.  */
  471. int
  472. da_assign(iface, hwaddr, ipaddr)
  473. struct iface *iface; /* -> Pointer to lnet struct of net on which to assign addr. */
  474. uint8 *hwaddr; /* -> Pointer to hardware address of hosts. */
  475. int32 *ipaddr; /* <- Address assigned to host. */
  476. {
  477. struct drange_desc *dr;
  478. struct daddr *da;
  479. int status;
  480. struct arp_type *at;
  481. /* Find the network table */
  482. for(dr = (struct drange_desc *) rtabq.head; dr != NULL; dr = dr->dr_next){
  483. if(iface == dr->dr_iface)
  484. break;
  485. }
  486. if(dr == NULL){
  487. *ipaddr = 0;
  488. return ERR_NOIPADDRESS;
  489. }
  490. /* If this host had an address assigned previously, try to reassign
  491.  * that. If no previous address, assign a new one.
  492.  */
  493. status = da_get_old_addr(dr, hwaddr, &da);
  494. if(status != 0) 
  495. status = da_get_free_addr(dr, &da);
  496. /* If I got an address, assign it and link it in to the use list. */
  497. if(status == 0){
  498. memcpy(da->da_hwaddr, hwaddr, dr->dr_hwaddrlen);
  499. *ipaddr = da->da_addr;
  500. da->da_time = time(NULL); /* Time assigned */
  501. q_enqueue(&dr->dr_usedq,(struct q_elt *)da);
  502. at = &Arp_type[dr->dr_iface->iftype->type];
  503. bp_log("IP addr %s assigned to %s on network %sn",
  504.  inet_ntoa(*ipaddr),
  505.  (*at->format)(bp_ascii, hwaddr), dr->dr_iface->name);
  506. }
  507.         switch(dr->dr_rstate){
  508.         case R_OFF:
  509.         case R_DONE:
  510.                 if(dr->dr_fcount <= dr->dr_thon) 
  511. da_enter_reclaim(dr);
  512.                 /* Fall through. */
  513.         case R_RECLAIM:
  514.                 if(dr->dr_fcount <= dr->dr_thcritical) 
  515. da_enter_critical(dr);
  516.                 break;
  517.         /* case R_CRITICAL: is not handled. */
  518.         }
  519.         return status;
  520. }
  521. /*
  522.  * Enter the reclaimation state.
  523.  */
  524. static void
  525. da_enter_reclaim(dr)
  526. struct drange_desc *dr;
  527. {
  528.         char ipa[16], ipb[16];
  529.         iptoa(dr->dr_start, ipa);
  530.         iptoa(dr->dr_end, ipb);
  531.         if(dr->dr_rstate & R_OFF){
  532.                 dr->dr_vstate = V_SWAIT;  /* da_enter_reclaim: R_OFF */
  533.                 dr->dr_rtime = 0;
  534.         }
  535.         dr->dr_rstate = R_RECLAIM;
  536.         dr->dr_time_addrretry = TIME_ADDRRETRY;         /* Wait a while before retrying addresses. */
  537. }
  538. /*
  539.  * Search for hwaddr on the used list, the reclaimation list, and the free list.
  540.  */
  541. static int
  542. da_get_free_addr(dr, dap)
  543. struct drange_desc *dr;
  544. struct daddr **dap;
  545. {
  546.         *dap = (struct daddr *) q_dequeue(&(dr->dr_freeq));
  547.         if(*dap == NULL) 
  548. return ERR_NOIPADDRESS;
  549.         --dr->dr_fcount;
  550.         return 0;
  551. }
  552. /*
  553.  * Search for hwaddr on the used list, the reclaimation list, and the free list.
  554.  */
  555. static int
  556. da_get_old_addr(dr, hwaddr, dap)
  557. struct drange_desc *dr;
  558. uint8   *hwaddr;
  559. struct daddr **dap;
  560. {
  561.         struct daddr *da;
  562. /* Search the used queue */
  563.         for(da = (struct daddr *) dr->dr_usedq.head; da != NULL; da = da->da_next){
  564.                 if(memcmp(da->da_hwaddr, hwaddr, dr->dr_hwaddrlen) == 0){
  565.                         q_remove(&dr->dr_usedq,(struct q_elt *)da);
  566.                         *dap = da;
  567.                         return 0;
  568.                 }
  569.         }
  570. /* Search the relaimq queue */
  571.         for(da = (struct daddr *) dr->dr_reclaimq.head; da != NULL; 
  572. da = da->da_next){
  573.                 if(memcmp(da->da_hwaddr, hwaddr, dr->dr_hwaddrlen) == 0){
  574.                         /* Here is the address.  I have to be carefull in removing it from
  575.  * reclaim queue, I may be verifying this address.
  576.                          * If I am, I have to fix up the pointers before removing this
  577.                          * element.
  578.                          */
  579.                         if((dr->dr_rstate & R_OFF) == 0 && dr->dr_vstate == V_VERIFY 
  580. && dr->dr_raddr == da){ 
  581. /* I am verifying this very address.  */
  582.                                 /* Start over.  
  583.  * This should happen very infrequently at most. */
  584.                                 dr->dr_vstate = V_SWAIT;  /* get_old_addr */
  585.                         }
  586.                         q_remove(&dr->dr_reclaimq,(struct q_elt *)da);
  587.                         *dap = da;
  588.                         return 0;
  589.                 }
  590.         }
  591. /* Search the free queue */
  592.         for(da = (struct daddr *) dr->dr_freeq.head; da != NULL; da = da->da_next){
  593.                 if(memcmp(da->da_hwaddr, hwaddr, dr->dr_hwaddrlen) == 0){
  594.                         q_remove(&dr->dr_freeq,(struct q_elt *)da);
  595.                         --dr->dr_fcount;
  596.                         *dap = da;
  597.                         return 0;
  598.                 }
  599.         }
  600.         return ERR_NOIPADDRESS;
  601. }
  602. #ifdef notdef
  603. static void
  604. dprint_dr_record(dr)
  605. struct drange_desc *dr;
  606. {
  607.         bp_log("Queue link   x%lxn", dr->dr_next);
  608.         bp_log("Pointer to network information         x%lxn", dr->dr_iface);
  609.         bp_log("First IP address in range              x%lxn", dr->dr_start);
  610.         bp_log("Last IP address in range               x%lxn", dr->dr_end);
  611.         bp_log("Number of IP addresses in range        %dn", dr->dr_acount);
  612.         bp_log("Number of IP addresses in free         %dn", dr->dr_fcount);
  613.         bp_log("Number of IP addresses on reclaimation queue %dn", 
  614. dr->dr_rcount);
  615.         bp_log("Threshold for turning on reclaimation  %dn", dr->dr_thon);
  616.         bp_log("Threshold for critical reclaimation    %dn", dr->dr_thcritical);
  617.         bp_log("Threshold for turning off reclaimation %dn", dr->dr_thoff);
  618.         bp_log("Time to wait before retrying addresses %ldn", 
  619. dr->dr_time_addrretry);
  620.         bp_log("Length of hardware address             %dn", dr->dr_hwaddrlen);
  621.         bp_log("Reclaimation state                     %dn",(int)dr->dr_rstate);
  622.         bp_log("Verification state                     %dn",(int)dr->dr_vstate);
  623.         bp_log("Time stamp for reclaimation            %ldn", dr->dr_rtime);
  624.         bp_log("Address being verified                 x%lxn", dr->dr_raddr);
  625.         bp_log("Pointer to table of addresses          x%lxn", dr->dr_table);
  626.         bp_log("uesdq x%lx  reclaimq                   x%lx  freeq x%lxn", dr->dr_usedq, 
  627. dr->dr_reclaimq, dr->dr_freeq);
  628. }
  629. #endif
  630. /*
  631.  * Enter the critical reclaimation state.
  632.  */
  633. static void
  634. da_enter_critical(dr)
  635. struct drange_desc *dr;
  636. {
  637.         char ipa[16], ipb[16];
  638. char *ipc;
  639. ipc = inet_ntoa(dr->dr_start);
  640. strcpy(ipa, ipc);
  641. ipc = inet_ntoa(dr->dr_end);
  642. strcpy(ipb, ipc);
  643.         if((dr->dr_rstate & R_OFF) == 0){
  644.                 dr->dr_vstate = V_SWAIT; /* Enter critical, & R_OFF */
  645.                 dr->dr_rtime = 0;
  646.         }
  647.         dr->dr_rstate = R_CRITICAL;
  648.         dr->dr_time_addrretry = 0;      /* Retry addresses as fast as possible. */
  649. }
  650. /*
  651.  * Initialization
  652.  */
  653. /*
  654.  * Initialize the Dynamic address assignment module.
  655.  */
  656. int
  657. da_init()
  658. {
  659.         q_init(&rtabq);
  660.         return 0;
  661. }
  662. /*
  663.  * Begin dynamic address service for a network.
  664.  */
  665. int
  666. da_serve_net(iface, rstart, rend)
  667. struct iface *iface; /* Pointer to lnet record. */
  668. int32 rstart; /* First address in range. */
  669. int32 rend; /* Last address in range. */
  670. {
  671. struct drange_desc *dr; /* Pointer to the range descriptor. */
  672. struct daddr *da; /* Pointer to an address structure. */
  673. int32 rcount; /* Number of addresses range. */
  674. time_t now; /* Current time. */
  675. uint16 i;
  676. char ipc[16], ipd[16];
  677.         /* Find the network table */
  678.         for(dr = (struct drange_desc *) rtabq.head; dr != NULL;
  679.  dr = dr->dr_next){
  680.                 if(iface == dr->dr_iface)
  681.                         break;
  682.         }
  683. if(dr == NULL){
  684. /* If there is no network table, allocate a new one
  685.  *
  686.    * Allocate the memory I need.
  687.    */
  688. dr = (struct drange_desc *) calloc(1, sizeof(*dr));
  689. if(dr == NULL) 
  690. return E_NOMEM;
  691. } else if((dr->dr_start != rstart) || (dr->dr_end != rend)) 
  692. /* If the range is different, create a new range */
  693. free(dr->dr_table);
  694. else
  695. return 0; /* There is no change, return */
  696. rcount = (rend - rstart) + 1;
  697. da = (struct daddr *) calloc(1,(sizeof (*da) + iface->iftype->hwalen) * rcount);
  698. if(da == NULL) 
  699. return E_NOMEM;
  700. /* 
  701.  * Got the memory, fill in the structures.
  702.  */
  703. dr->dr_iface = iface;
  704. dr->dr_start = rstart;
  705. dr->dr_end = rend;
  706. dr->dr_acount = rcount;
  707. dr->dr_fcount = 0;
  708. dr->dr_rcount = 0;
  709. dr->dr_thon = (rcount * THRESH_ON) / 100;
  710. dr->dr_thcritical = THRESH_CRITICAL;
  711. dr->dr_thoff = (rcount * THRESH_OFF) / 100;
  712. dr->dr_time_addrretry = 0;
  713.         dr->dr_hwaddrlen = iface->iftype->hwalen;
  714. dr->dr_rstate = R_OFF;
  715. dr->dr_vstate = V_SWAIT; /* Initialize */
  716. dr->dr_rtime = 0;
  717. dr->dr_raddr = NULL;
  718. dr->dr_table = da;
  719. /* 
  720.  * Fill in the table and link them all onto the used list.
  721.  */
  722. time(&now);
  723. for(i = 0, da = dr->dr_table; i < dr->dr_acount; ++i, da = da_getnext(dr, da)){
  724. da->da_addr = rstart++;
  725. da->da_time = 0; /* Initiallize at 0, only here */
  726. q_enqueue(&dr->dr_usedq,(struct q_elt *)da);
  727. }
  728. /* and set up the timer stuff */
  729. if(rtabq.head == NULL){
  730. set_timer(&da_timer,TIME_RWAIT*1000L);
  731.         da_timer.func = da_runtask;
  732.         da_timer.arg = (void *) 0;
  733. start_timer(&da_timer);
  734. }
  735. q_enqueue(&rtabq,(struct q_elt *)dr);
  736. da_enter_critical(dr); /* Start reclaiming some of these addresses. */
  737. iptoa(dr->dr_start, ipc);
  738. iptoa(dr->dr_end, ipd);
  739. bp_log("DynamicIP range: %s - %sn", ipc, ipd);
  740. return 0;
  741. }
  742. /*
  743.  * Routines to implement a simple forward linked queue.
  744.  */
  745. /*
  746.  *      q_init()
  747.  *      Initialize simple Q descriptor
  748.  */
  749. static void
  750. q_init(queue)
  751. struct q *queue;
  752. {
  753.         queue->head = 0;
  754.         queue->tail = 0;
  755. }
  756. /*
  757.  *      q_enqueue()
  758.  *              Enqueue an element in a simple Q.
  759.  */
  760. void
  761. q_enqueue(queue, elem)
  762. struct q *queue;
  763. struct q_elt *elem;
  764. {
  765.         struct q_elt *last;
  766.         if(queue->tail != NULL){  /* If not empty Q... */
  767.                 last = (struct q_elt *) queue->tail;
  768.                 last->next = elem;
  769.         }
  770.         else
  771. queue->head = (char *) elem;
  772.         queue->tail = (char *) elem;
  773.         elem->next = NULL;
  774. }
  775. /*
  776.  *      q_dequeue       ()
  777.  *      Pull an element off of the head of a Q.
  778.  */
  779. struct q_elt *
  780. q_dequeue(queue)
  781. struct q *queue;
  782. {
  783.         struct q_elt *elem;
  784.         if(queue->head == NULL)
  785. return NULL; /* return NULL when empty Q */
  786.         elem = (struct q_elt *) queue->head;
  787.         queue->head = (char *) elem->next;
  788.         elem->next = NULL;
  789.         if(queue->head == NULL)
  790. queue->tail = NULL;
  791.         return elem;
  792. }
  793. /*
  794.  *      Remove an element from the middle of a queue.  Note that
  795.  *      there is no mutex here, so this shouldn't be used on
  796.  *      critical Qs
  797.  */
  798. static int
  799. q_remove(source_queue, qel)
  800. struct q *source_queue;
  801. struct q_elt *qel;
  802. {
  803.         struct q_elt *prev, *e;
  804.         /*   Case : removing first in Q */
  805.         if(qel == (struct q_elt *) source_queue->head){
  806.                 source_queue->head = (char *)qel->next;  /* trying to remove first in queue... */
  807.                 if(source_queue->head == NULL)   /* nothing left... */
  808.                         source_queue->tail = NULL;  /* blank out the Q */
  809.                 else if(source_queue->head == source_queue->tail){ /* One thing left */
  810.                         e = (struct q_elt *) source_queue->head; /* As insurance, set it's next to NULL. */
  811.                         e->next = NULL;
  812.                 }
  813.                 return 0;
  814.         }
  815.         /* find Q element before qel, so that we can link around qel */
  816.         for(prev = (struct q_elt *) source_queue->head; prev->next != qel; prev = prev->next)
  817.                 if(prev == NULL)
  818.                         return 1;
  819.         /* Case : Removing last in Q */
  820.         if(qel == (struct q_elt *) source_queue->tail){     /* trying to remove last one in queue... */
  821.                 prev->next = NULL;   /* there is a prev elt, since we return on first */
  822.                 source_queue->tail = (char *) prev;
  823.                 return 0;
  824.         }
  825.         /*  else, removing a queue element in the middle...  */
  826.         prev->next = qel->next;
  827.         return 0;
  828. }
  829. /*
  830.  * Support Routines
  831.  */
  832. static void
  833. iptoa(ipaddr, ipstr)
  834. int32 ipaddr;
  835. char ipstr[16];
  836. {
  837. char *tmpStr;
  838. tmpStr = inet_ntoa(ipaddr);
  839. strcpy(ipstr, tmpStr);
  840. }
  841. #ifdef notdef
  842. static  void
  843. build_hex_string(fromstr, len, tostr)
  844. char *fromstr; int  len;
  845. char *tostr;
  846. {
  847. int i;
  848. for(i=0; i < len; i++){
  849. sprintf(tostr, "%02x", fromstr[i]);
  850. tostr++;
  851. tostr++;
  852. }
  853. fromstr[len] = 0;
  854. }
  855. #endif