dhcpcState2.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:76k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* dhcpcState2.c - DHCP client runtime state machine (lease maintenance) */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01t,25apr02,wap  correct timeout calculations for RENEWING & REBINDING states
  8.                  (SPR #69069)
  9. 01s,23apr02,wap  use dhcpTime() instead of time() (SPR #68900)
  10. 01r,07mar02,wap  Remember to re-enable the BPF filter and set a watchdog
  11.                  timeout when we enter the REBINDING state in bound()
  12.                  (SPR #73243)
  13. 01q,06dec01,wap  Fix reboot_verify() so that it properly constructs retransmit
  14.                  request (make_request() called with wrong type) (SPR #70938)
  15. 01p,12oct01,rae  merge from truestack (SPRs 67822, 27426, 30344)
  16. 01o,24oct00,spm  fixed modification history after tor3_x merge
  17. 01n,23oct00,niq  merged from version 01r of tor3_x branch (base version 01m)
  18. 01m,04dec97,spm  added code review modifications
  19. 01l,06oct97,spm  removed reference to deleted endDriver global
  20. 01k,03sep97,spm  added specified minimum timeouts to lease reacquisition
  21. 01j,02sep97,spm  removed excess IMPORT statement and extra event hook parameter
  22. 01i,26aug97,spm  major overhaul: reorganized code and changed user interface
  23.                  to support multiple leases at runtime
  24. 01h,06aug97,spm  removed parameters linked list to reduce memory required
  25. 01g,15jul97,spm  replaced floating point to prevent ss5 exception (SPR #8738);
  26.                  removed unneeded checkpoint messages
  27. 01f,10jun97,spm  isolated incoming messages in state machine from input hooks
  28. 01e,02jun97,spm  changed DHCP option tags to prevent name conflicts (SPR #8667)
  29.                  and updated man pages
  30. 01d,06may97,spm  changed memory access to align IP header on four byte boundary
  31. 01c,18apr97,spm  added conditional include DHCPC_DEBUG for displayed output
  32. 01b,07apr97,spm  added code to use Host Requirements defaults and cleanup
  33.                  memory on exit, rewrote documentation
  34. 01a,29jan97,spm  extracted from dhcpc.c to reduce object size
  35. */
  36. /*
  37. DESCRIPTION
  38. This library contains a portion of the finite state machine for the WIDE 
  39. project DHCP client, modified for vxWorks compatibility.
  40. INTERNAL
  41. This module contains the functions used during and after the BOUND state. 
  42. It was created to reduce the size of the boot ROM image so that the DHCP client
  43. can be used with targets like the MV147 which have limited ROM capacity. When 
  44. executing at boot time, the DHCP client does not use any of the routines 
  45. defined in this module.
  46. INCLUDE_FILES: dhcpcLib.h
  47. */
  48. /*
  49.  * WIDE Project DHCP Implementation
  50.  * Copyright (c) 1995 Akihiro Tominaga
  51.  * Copyright (c) 1995 WIDE Project
  52.  * All rights reserved.
  53.  *
  54.  * Permission to use, copy, modify and distribute this software and its
  55.  * documentation is hereby granted, provided only with the following
  56.  * conditions are satisfied:
  57.  *
  58.  * 1. Both the copyright notice and this permission notice appear in
  59.  *    all copies of the software, derivative works or modified versions,
  60.  *    and any portions thereof, and that both notices appear in
  61.  *    supporting documentation.
  62.  * 2. All advertising materials mentioning features or use of this software
  63.  *    must display the following acknowledgement:
  64.  *      This product includes software developed by WIDE Project and
  65.  *      its contributors.
  66.  * 3. Neither the name of WIDE Project nor the names of its contributors
  67.  *    may be used to endorse or promote products derived from this software
  68.  *    without specific prior written permission.
  69.  *
  70.  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND WIDE
  71.  * PROJECT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  72.  * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ALSO, THERE
  73.  * IS NO WARRANTY IMPLIED OR OTHERWISE, NOR IS SUPPORT PROVIDED.
  74.  *
  75.  * Feedback of the results generated from any improvements or
  76.  * extensions made to this software would be much appreciated.
  77.  * Any such feedback should be sent to:
  78.  * 
  79.  *  Akihiro Tominaga
  80.  *  WIDE Project
  81.  *  Keio University, Endo 5322, Kanagawa, Japan
  82.  *  (E-mail: dhcp-dist@wide.ad.jp)
  83.  *
  84.  * WIDE project has the rights to redistribute these changes.
  85.  */
  86. /* includes */
  87. #include <stdio.h>
  88. #include <stdlib.h>
  89. #include <unistd.h>
  90. #include <string.h>
  91. #include <signal.h>
  92. #include <fcntl.h>
  93. #include <sys/types.h>
  94. #include <sys/socket.h>
  95. #include <sys/ioctl.h>
  96. #include <net/if.h>
  97. #include <netinet/in.h>
  98. #include <netinet/in_systm.h>
  99. #include <netinet/if_ether.h>
  100. #include <netinet/ip.h>
  101. #include <netinet/udp.h>
  102. #include <arpa/inet.h>
  103. #include "vxWorks.h"
  104. #include "ioLib.h"  /* ioctl declaration */
  105. #include "rngLib.h"
  106. #include "wdLib.h"
  107. #include "time.h"
  108. #include "inetLib.h"
  109. #include "logLib.h"
  110. #include "taskLib.h"
  111. #include "sysLib.h"
  112. #include "vxLib.h"
  113. #include "netLib.h"
  114. #include "sys/ioctl.h"
  115. #include "net/bpf.h"
  116. #include "dhcp/dhcpcCommonLib.h"
  117. #include "dhcp/dhcpcStateLib.h"
  118. #include "dhcp/dhcpcInternal.h"
  119. /* defines */
  120. /* Retransmission delay is timer value plus/minus one second (RFC 1541). */
  121. #define SLEEP_RANDOM(timer) ( (timer - 1) + (rand () % 2) )
  122. #define REQUEST_RETRANS   4  /* Max number of retransmissions. (RFC 1541). */
  123. /* globals */
  124. IMPORT SEM_ID dhcpcMutexSem; /* Protects status indicator */
  125. IMPORT struct dhcpLeaseData dhcpBootLease; /* Boot lease time / address */
  126. /*******************************************************************************
  127. *
  128. * use_parameter - reset the network according to the parameters provided
  129. *
  130. * If no event hook is present for the lease described by <pLeaseData>, this 
  131. * routine sets the network address, broadcast address and subnet mask for 
  132. * a network interface to the values chosen by the DHCP client and acknowledged 
  133. * by the offering DHCP server. The configuration of the network interface is
  134. * also changed automatically for any lease established during system startup,
  135. * whether or not an event hook is present. This routine calls any installed 
  136. * event notification hook to indicate that new lease parameters are available.
  137. *
  138. * RETURNS: 0 if setup completed, or 1 if error occurs.
  139. *
  140. * ERRNO: N/A
  141. * NOMANUAL
  142. */
  143. int use_parameter
  144.     (
  145.     struct dhcp_param * paramp,  /* Current DHCP parameters */
  146.     LEASE_DATA *  pLeaseData  /* lease-specific status information */
  147.     )
  148.     {
  149.     struct in_addr addr;
  150.     struct in_addr mask; 
  151.     struct in_addr brdaddr;
  152.     int status = 0;
  153.     int length;
  154.     char *  bufp;
  155.     void *  pCookie;
  156.     /*
  157.      * For now, use the address of the lease-specific data structure as the
  158.      * internal lease identifier. This could be replaced with a more 
  159.      * sophisticated mapping if necessary.
  160.      */
  161.     pCookie = (void *)pLeaseData;
  162.     if (pLeaseData->cacheHookRtn != NULL)
  163.         {
  164. #ifdef DHCPC_DEBUG
  165.         logMsg ("Saving lease data.n", 0, 0, 0, 0, 0, 0);
  166. #endif
  167. #if BSD<44
  168.         length = ntohs (dhcpcMsgIn.udp->uh_ulen) +
  169.                      (dhcpcMsgIn.ip->ip_v_hl & 0xff) * WORD;
  170. #else
  171.         length = ntohs (dhcpcMsgIn.udp->uh_ulen) +
  172.                      dhcpcMsgIn.ip->ip_hl * WORD;
  173. #endif
  174.         bufp = (char *)dhcpcMsgIn.ip;
  175.         (* pLeaseData->cacheHookRtn) (DHCP_CACHE_WRITE,
  176.                                       &pLeaseData->dhcpcParam->lease_origin, 
  177.                                       &length, bufp);
  178.         }
  179.     if (pLeaseData->autoConfig || pLeaseData->leaseType == DHCP_AUTOMATIC)
  180.         {
  181.         /* 
  182.          * If automatic configuration was requested or the lease was 
  183.          * established during system startup, the client library will 
  184.          * reconfigure the transmit/receive interface to use the retrieved 
  185.          * addressing information. Fetch the values for the interface address, 
  186.          * subnet mask, and broadcast address, if available.
  187.          */
  188.          bzero ( (char *)&addr, sizeof (struct in_addr));
  189.          bzero ( (char *)&mask, sizeof (struct in_addr));
  190.          bzero ( (char *)&brdaddr, sizeof (struct in_addr));
  191.          addr.s_addr = paramp->yiaddr.s_addr;
  192.          /* Set subnet mask, if available. */
  193.          if (paramp->subnet_mask != NULL) 
  194.              mask.s_addr = paramp->subnet_mask->s_addr;
  195.          else 
  196.              mask.s_addr = 0;
  197.          /* Set broadcast address, if available. */
  198.          if (paramp->brdcast_addr != NULL)
  199.              brdaddr.s_addr = paramp->brdcast_addr->s_addr;
  200.          else 
  201.              brdaddr.s_addr = 0;
  202.          }
  203.     /* 
  204.      * Set the transmit/receive interface to use the new parameters.
  205.      */
  206.     if (pLeaseData->autoConfig || pLeaseData->leaseType == DHCP_AUTOMATIC)
  207.         {
  208.         /* Set new address info. Returns 1 if address unchanged.  */
  209.         status = config_if (&pLeaseData->ifData, &addr, 
  210.                             ( (mask.s_addr != 0) ? &mask : NULL),
  211.                             ( (brdaddr.s_addr != 0) ? &brdaddr : NULL));
  212.         if (status == 0)   
  213.             set_route (paramp);
  214.         else if (status == -1)    /* Error. */
  215.             return (1);
  216.         /* Send an ARP reply to update the ARP cache on other hosts. */
  217.         arp_reply (&paramp->yiaddr, &pLeaseData->ifData);
  218.         }
  219.     /*
  220.      * If an event notification hook is present, send an
  221.      * indication that a new set of parameters is available.
  222.      */
  223.     if (pLeaseData->eventHookRtn != NULL)
  224.         (* pLeaseData->eventHookRtn) (DHCPC_LEASE_NEW, pCookie);
  225.     return (0);
  226.     }
  227. /*******************************************************************************
  228. *
  229. * release - relinquish a DHCP lease
  230. *
  231. * This routine sends a message to the DHCP server relinquishing the active
  232. * lease contained in the <pEvent> event descriptor. If <shutdownFlag> is TRUE,
  233. * the routine cleans up all lease-specific data structures because the user
  234. * issued a dhcpcRelease() or dhcpcShutdown() call. Otherwise, the routine is
  235. * handling a fatal error in the state machine and the lease-specific data is
  236. * retained to allow retries of the dhcpcBind() or dhcpcInformGet() operation.
  237. *
  238. * RETURNS: N/A
  239. *
  240. * ERRNO: N/A
  241. *
  242. * NOMANUAL
  243. */
  244. void release
  245.     (
  246.     LEASE_DATA *  pLeaseData,  /* lease-specific status information */
  247.     BOOL  shutdownFlag  /* remove lease-specific data? */
  248.     )
  249.     {
  250.     char  errmsg[255];
  251.     struct dhcp_reqspec tmp_reqspec;
  252.     int  boundstat;
  253.     bzero ( (char *)&tmp_reqspec, sizeof (tmp_reqspec));
  254.     bzero ( (char *)&errmsg, sizeof (errmsg));
  255.     semTake (dhcpcMutexSem, WAIT_FOREVER);    /* Reset status indicator. */
  256.     if (pLeaseData->leaseGood)
  257.         {
  258.         boundstat = 1;
  259.         pLeaseData->leaseGood = FALSE;
  260.         }
  261.     else                     /* Not bound - don't send release message. */
  262.         boundstat = 0;
  263.     semGive (dhcpcMutexSem);
  264.     if (boundstat)
  265.         {
  266.         switch (pLeaseData->currState) 
  267.             {
  268.             case BOUND: /* fall-through */
  269.             case RENEWING: /* fall-through */
  270.             case REBINDING: /* fall-through */
  271.             case VERIFY: /* fall-through */
  272.             case VERIFYING: /* fall-through */
  273.                 if (pLeaseData->dhcpcParam != NULL) 
  274.                     {
  275.                     set_relinfo (&tmp_reqspec, pLeaseData, errmsg);
  276.                     dhcp_release (&tmp_reqspec, &pLeaseData->ifData,
  277.                                   pLeaseData->oldFlag);
  278.                     /* 
  279.                      * Disable the underlying network interface if
  280.                      * it used the (soon-to-be) relinquished lease. 
  281.                      */
  282.                     if (pLeaseData->autoConfig || 
  283.                             pLeaseData->leaseType == DHCP_AUTOMATIC)
  284.                         down_if (&pLeaseData->ifData);
  285.  
  286.                     if (pLeaseData->cacheHookRtn != NULL)
  287.                         {
  288.                         (* pLeaseData->cacheHookRtn) (DHCP_CACHE_ERASE, NULL, 
  289.                                                       NULL, NULL);
  290.                         }
  291.                     clean_param (pLeaseData->dhcpcParam);
  292.                     free (pLeaseData->dhcpcParam);
  293.                     pLeaseData->dhcpcParam = NULL;
  294.                     }
  295.                 break;
  296.             default:
  297.                 break;
  298.             }
  299.         }
  300.     /* Remove lease information if appropriate. */
  301.     if (shutdownFlag)
  302.         dhcpcLeaseCleanup (pLeaseData);
  303.         
  304.     return;
  305.     }
  306. /*******************************************************************************
  307. *
  308. * alarm_bound - timeout during bound state
  309. *
  310. * This routine sends a timeout notification to the client monitor task when 
  311. * a lease timer expires. It is called at interrupt level by a watchdog timer.
  312. * The monitor task will eventually advance the lease from the BOUND state to
  313. * the RENEWING or the REBINDING state, depending on which interval elapsed.
  314. *
  315. * RETURNS: N/A
  316. *
  317. * ERRNO: N/A
  318. *
  319. * NOMANUAL
  320. */
  321. void alarm_bound
  322.     (
  323.     LEASE_DATA *  pLeaseData  /* lease-specific status information */
  324.     )
  325.     {
  326.     /*
  327.      * Ignore the timeout if a state transition occurred
  328.      * before processing completed.
  329.      */
  330.     if (pLeaseData->currState != BOUND)
  331.         return;
  332.     /* Construct and send a timeout message to the lease monitor task. */
  333.     dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, pLeaseData, TRUE);
  334.     return;
  335.     }
  336. /*******************************************************************************
  337. *
  338. * retrans_renewing - signal when reception interval for renewal reply expires
  339. *
  340. * This routine sends a timeout notification to the client monitor task when 
  341. * the interval for receiving a server reply to a renewal request expires. It
  342. * is called at interrupt level by a watchdog timer. The monitor task will 
  343. * eventually execute the RENEWING state to process the timeout event and
  344. * retransmit the DHCP request message.
  345. *
  346. * RETURNS: N/A
  347. *
  348. * ERRNO: N/A
  349. *
  350. * NOMANUAL
  351. */
  352. void retrans_renewing
  353.     (
  354.     LEASE_DATA *  pLeaseData  /* lease-specific status information */
  355.     )
  356.     {
  357.     /*
  358.      * Ignore the timeout if a state transition occurred
  359.      * before processing completed.
  360.      */
  361.     if (pLeaseData->currState != RENEWING)
  362.         return;
  363.     /* Construct and send a timeout message to the lease monitor task. */
  364.     dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, pLeaseData, TRUE);
  365.     return;
  366.     }
  367. /*******************************************************************************
  368. *
  369. * retrans_rebinding - signal when reception interval for rebind offer expires
  370. *
  371. * This routine sends a timeout notification to the client monitor task when 
  372. * the interval for receiving a lease offer from a different server expires. It
  373. * is called at interrupt level by a watchdog timer. The monitor task will 
  374. * eventually execute the REBINDING state to process the timeout event and
  375. * retransmit the DHCP discover message.
  376. *
  377. * RETURNS: N/A
  378. *
  379. * ERRNO: N/A
  380. *
  381. * NOMANUAL
  382. */
  383. void retrans_rebinding
  384.     (
  385.     LEASE_DATA *  pLeaseData  /* lease-specific status information */
  386.     )
  387.     {
  388.     /*
  389.      * Ignore the timeout if a state transition occurred
  390.      * before processing completed.
  391.      */
  392.     if (pLeaseData->currState != REBINDING)
  393.         return;
  394.     /* Construct and send a timeout message to the lease monitor task. */
  395.     dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, pLeaseData, TRUE);
  396.     return;
  397.     }
  398. /*******************************************************************************
  399. *
  400. * retrans_reboot_verify - retransmission in rebooting state
  401. *
  402. * This routine signals the DHCP client monitor task when the timeout interval 
  403. * for receiving a server reply expires for the lease indicated by the 
  404. * <pLeaseData> parameter. The client monitor task will pass the event to the 
  405. * reboot_verify() routine in the finite state machine.
  406. * retrans_reboot_verify - signal when verification reception interval expires
  407. *
  408. * This routine sends a timeout notification to the client monitor task when 
  409. * the interval for receiving a server reply to a reboot (or verify) request 
  410. * expires. It is called at interrupt level by a watchdog timer. The monitor 
  411. * task will eventually execute the REBOOTING or VERIFYING state to process 
  412. * the timeout event and retransmit the appropriate DHCP request message.
  413. *
  414. * RETURNS: N/A
  415. *
  416. * ERRNO: N/A
  417. *
  418. * NOMANUAL
  419. */
  420. void retrans_reboot_verify
  421.     (
  422.     LEASE_DATA *  pLeaseData  /* lease-specific status information */
  423.     )
  424.     {
  425.     /*
  426.      * Ignore the timeout if a state transition occurred
  427.      * before processing completed.
  428.      */
  429.     if (pLeaseData->currState != REBOOTING &&
  430.             pLeaseData->currState != VERIFYING)
  431.         return;
  432.     /* Construct and send a timeout message to the lease monitor task. */
  433.     dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, pLeaseData, TRUE);
  434.     return;
  435.     }
  436. /*******************************************************************************
  437. *
  438. * bound - Active state of client finite state machine
  439. *
  440. * This routine contains the fourth state of the client finite state machine.
  441. * It accepts and services all user requests for BOOTP and infinite DHCP leases
  442. * throughout their lifetimes. For finite DHCP leases, it handles all processing
  443. * until one of the lease timers expires. At that point, processing continues 
  444. * with the renewing() or rebinding() routines.
  445. * .IP
  446. * This routine is invoked by the event handler of the client monitor task,
  447. * and should only be called internally. Any arriving DHCP messages contain
  448. * stale offers or responses and are discarded. User requests generated
  449. * by calls to the dhcpcRelease() and dhcpcVerify() routines are accepted.
  450. *
  451. * RETURNS: OK (processing complete), DHCPC_DONE (remove lease),
  452. *          DHCPC_MORE (continue), or ERROR.
  453. *
  454. * ERRNO: N/A
  455. *
  456. * NOMANUAL
  457. */
  458. int bound
  459.     (
  460.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  461.     )
  462.     {
  463.     int timeout;    /* Epoch when intermediate lease timers expire. */
  464.     int limit;      /* Epoch when lease expires. */
  465.    
  466.     LEASE_DATA *  pLeaseData;
  467.     int status;
  468.     int length;
  469.     time_t curr_epoch = 0;
  470.     struct sockaddr_in dest;
  471.     struct ifnet * pIf;
  472.     struct ifreq   ifr;
  473.     /*
  474.      * Use the cookie to access the lease-specific data structures. For now,
  475.      * just typecast the cookie. This translation could be replaced with a more
  476.      * sophisticated lookup at some point.
  477.      */
  478.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  479.     /* 
  480.      * Process events for BOOTP and infinite DHCP leases. Timeouts and
  481.      * incoming messages should never occur for either type of lease. Also,
  482.      * BOOTP leases require no special processing in response to user requests
  483.      * for verification or shutdown.
  484.      */
  485.      
  486.     if (pLeaseData->dhcpcParam->lease_duration == ~0)
  487.         {
  488.         /* Ignore timeouts and received DHCP messages. */
  489.         if (pEvent->source != DHCP_AUTO_EVENT) 
  490.             {
  491.             /* Process user requests. */
  492.             if (pEvent->type == DHCP_USER_RELEASE)    /* Relinquish lease. */
  493.                 {
  494.                 if (pLeaseData->leaseType != DHCP_BOOTP)
  495.                     release (pLeaseData, TRUE);
  496.                 return (DHCPC_DONE);
  497.                 }
  498.             if (pEvent->type == DHCP_USER_VERIFY)    /* Verify lease. */
  499.                 {
  500.                 if (pLeaseData->leaseType != DHCP_BOOTP)
  501.                     {
  502.                     /* Set the lease data to execute verify() routine. */
  503.                     pLeaseData->prevState = BOUND;
  504.                     pLeaseData->currState = VERIFY;
  505.                     return (DHCPC_MORE);
  506.                     }
  507.                 }
  508.             }
  509.         return (OK);
  510.         }
  511.     /* The rest of the routine handles processing for finite DHCP leases. */
  512.     bzero (sbuf.buf, sbuf.size);
  513.     if (dhcpTime (&curr_epoch) == -1) 
  514.         {
  515. #ifdef DHCPC_DEBUG
  516.         logMsg ("time() error in bound()n", 0, 0, 0, 0, 0, 0);
  517. #endif
  518.         return (ERROR);
  519.         }
  520.     if (pLeaseData->prevState != BOUND)
  521.         {
  522.         /* 
  523.          * The interval between lease acknowledgement and the entry to the 
  524.          * bound() routine depends on the workload of the client monitor task 
  525.          * and is completely unpredictable. Check all lease timers, since they 
  526.          * might have expired during that time.
  527.          */
  528.         wdCancel (pLeaseData->timer);
  529. #ifdef DHCPC_DEBUG
  530.         logMsg ("dhcpc: Entering BOUND state.n", 0, 0, 0, 0, 0, 0);
  531. #endif
  532.         timeout = pLeaseData->dhcpcParam->lease_origin + 
  533.                       pLeaseData->dhcpcParam->dhcp_t2;
  534.         limit = pLeaseData->dhcpcParam->lease_origin + 
  535.                     pLeaseData->dhcpcParam->lease_duration;
  536.         if (curr_epoch >= limit || timeout <= curr_epoch)
  537.             {
  538.             /* Lease or second timer expired - create a timeout event. */
  539.             pEvent->source = DHCP_AUTO_EVENT;
  540.             pEvent->type = DHCP_TIMEOUT;
  541.             }
  542.         else
  543.             {
  544.             timeout =  pLeaseData->dhcpcParam->lease_origin + 
  545.                            pLeaseData->dhcpcParam->dhcp_t1;
  546.             if (timeout <= curr_epoch)
  547.                 {
  548.                 /* First timer expired - create a timeout event. */
  549.                 pEvent->source = DHCP_AUTO_EVENT;
  550.                 pEvent->type = DHCP_TIMEOUT;
  551.                 }
  552.             else
  553.                 {
  554.                 /* No timers expired - set to time remaining with T1. */
  555.                 timeout = pLeaseData->dhcpcParam->lease_origin + 
  556.                               pLeaseData->dhcpcParam->dhcp_t1 - curr_epoch;
  557.                 wdStart (pLeaseData->timer, sysClkRateGet() * timeout,
  558.                          (FUNCPTR)alarm_bound, (int)pLeaseData);
  559.                 }
  560.             }
  561.         pLeaseData->prevState = BOUND;
  562. #ifdef DHCPC_DEBUG
  563.         logMsg ("dhcpc: Ready for user requests.n", 0, 0, 0, 0, 0, 0); 
  564. #endif
  565.         }
  566.     if (pEvent->type == DHCPC_STATE_BEGIN)   /* Initial processing finished. */
  567.         return (OK);
  568.     if (pEvent->source == DHCP_AUTO_EVENT)
  569.         {
  570.         /* If no timers have expired, ignore received DHCP messages. */
  571.         if (pEvent->type == DHCP_MSG_ARRIVED)
  572.             return (OK);
  573.         else
  574.             {
  575.             /*
  576.              * Initiate renewal or rebinding when lease timers expire.
  577.              * If the client monitor task is overloaded, processing may
  578.              * occur well after the event notification is received.
  579.              * In the worst case, the lease could expire before any
  580.              * processing is performed. The timers can also expire
  581.              * during a requested lease verification. Excess timeout 
  582.              * notifications which might be present from earlier states 
  583.              * are ignored.
  584.              */
  585.             limit = pLeaseData->dhcpcParam->lease_origin + 
  586.                         pLeaseData->dhcpcParam->lease_duration;
  587.             if (curr_epoch >= limit)
  588.                 {
  589.                 /*
  590.                  * Lease expired between notification and processing.
  591.                  * Resume filtering with the BPF device (suspended before
  592.                  * entry to this routine) before restarting.
  593.                  */
  594.                 bzero ( (char *)&ifr, sizeof (struct ifreq));
  595.                 sprintf (ifr.ifr_name, "%s%d",
  596.                          pLeaseData->ifData.iface->if_name,
  597.                          pLeaseData->ifData.iface->if_unit);
  598.                 ioctl (pLeaseData->ifData.bpfDev, BIOCSTART, (int)&ifr);
  599.                 pLeaseData->prevState = REQUESTING;
  600.                 pLeaseData->currState = INIT;
  601.                 return (DHCPC_MORE);
  602.                 }
  603.             timeout = pLeaseData->dhcpcParam->lease_origin +
  604.                           pLeaseData->dhcpcParam->dhcp_t2;
  605.             if (timeout <= curr_epoch && curr_epoch < limit)
  606.                 {
  607.                 /* Second timer expired: contact any server for parameters. */
  608. #ifdef DHCPC_DEBUG
  609.                 logMsg ("Entering REBINDING state.n", 0, 0, 0, 0, 0, 0);
  610. #endif
  611.                 length = make_request (pLeaseData, REBINDING, TRUE);
  612.                 dhcpcMsgOut.udp->uh_sum = 0;
  613.                 dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, 
  614.                                                      (char *)dhcpcMsgOut.udp,
  615.                                                      ntohs (spudph.ulen));
  616.                 bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  617.                 dest.sin_len = sizeof (struct sockaddr_in);
  618.                 dest.sin_family = AF_INET;
  619.                 dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  620.                 pIf = pLeaseData->ifData.iface;
  621.                 /* Remember to re-enable the BPF filter here. */
  622.                 bzero ( (char *)&ifr, sizeof (struct ifreq));
  623.                 sprintf (ifr.ifr_name, "%s%d",
  624.                          pLeaseData->ifData.iface->if_name,
  625.                          pLeaseData->ifData.iface->if_unit);
  626.                 ioctl (pLeaseData->ifData.bpfDev, BIOCSTART, (int)&ifr);
  627.                 status = dhcpSend (pIf, &dest, sbuf.buf, length, TRUE);
  628. #ifdef DHCPC_DEBUG
  629.                 if (status == ERROR)
  630.                     logMsg ("Can't send DHCPREQUEST(REBINDING)n", 
  631.                             0, 0, 0, 0, 0, 0);
  632. #endif
  633.                 pLeaseData->prevState = BOUND;
  634.                 pLeaseData->currState = REBINDING;
  635.                 /* Set a timeout in case we miss the reply. */
  636.                 timeout = limit - curr_epoch;
  637.                 timeout /= 2;
  638.                 if (timeout < 60) 
  639.                     timeout = 60;
  640.                 wdStart (pLeaseData->timer, sysClkRateGet() * timeout, 
  641.                          (FUNCPTR)retrans_rebinding, (int)pLeaseData);
  642.                 return (OK);
  643.                 }
  644.             timeout = pLeaseData->dhcpcParam->lease_origin +
  645.                           pLeaseData->dhcpcParam->dhcp_t1;
  646.             limit = pLeaseData->dhcpcParam->lease_origin +
  647.                         pLeaseData->dhcpcParam->dhcp_t2;
  648.             if (timeout <= curr_epoch && curr_epoch < limit)
  649.                 {
  650.                 /*
  651.                  * First timer expired: 
  652.                  * attempt to renew lease with current server.
  653.                  * Resume filtering with the BPF device (suspended while 
  654.  * bound).
  655.  */
  656.                 bzero ( (char *)&ifr, sizeof (struct ifreq));
  657.                 sprintf (ifr.ifr_name, "%s%d", pLeaseData->ifData.iface->if_name,
  658.                          pLeaseData->ifData.iface->if_unit);
  659.                 
  660.                 ioctl (pLeaseData->ifData.bpfDev, BIOCSTART, (int)&ifr);
  661.                 
  662.                 
  663. #ifdef DHCPC_DEBUG
  664.                 logMsg ("Entering RENEWING state.n", 0, 0, 0, 0, 0, 0);
  665. #endif
  666.                 length = make_request (pLeaseData, RENEWING, TRUE);
  667.                 
  668.                 /* Ignore transmission failures for handling by timeout. */
  669.                 status = send_unicast (&pLeaseData->dhcpcParam->server_id, 
  670.                                        dhcpcMsgOut.dhcp, length);
  671. #ifdef DHCPC_DEBUG
  672.                 if (status < 0)
  673.                     logMsg ("Can't send DHCPREQUEST(RENEWING)n.", 
  674.                             0, 0, 0, 0, 0, 0);
  675. #endif
  676.                 
  677.                 /* DHCP request sent. Set lease data to execute next state. */
  678.                 pLeaseData->prevState = BOUND;
  679.                 pLeaseData->currState = RENEWING;
  680.                 pLeaseData->initEpoch = curr_epoch;
  681.                 /*
  682.                  * Set the retransmission timer to wait for one-half of the 
  683.                  * remaining time before T2 expires, or 60 seconds if T2 
  684.                  * expires in less than one minute.
  685.                  */
  686.                 timeout = limit - curr_epoch;
  687.                 timeout /= 2;
  688.                 if (timeout < 60) 
  689.                     timeout = 60;
  690.                 /* Set timer for retransmission of request message. */
  691.                 wdStart (pLeaseData->timer, sysClkRateGet() * timeout, 
  692.                          (FUNCPTR)retrans_renewing, (int)pLeaseData);
  693.                 return (OK);
  694.                 }
  695.             }    /* End of timeout processing. */
  696.         }    /* End of automatic events. */
  697.     else
  698.         {
  699.         /* Process user requests. */
  700.         if (pEvent->type == DHCP_USER_RELEASE)  /* Relinquish lease. */
  701.             {
  702.             release (pLeaseData, TRUE);
  703.             return (DHCPC_DONE);
  704.             }
  705.         if (pEvent->type == DHCP_USER_VERIFY)   /* Verify lease */
  706.             {
  707.             /* Set the lease data to execute verify() routine. */
  708.             pLeaseData->prevState = BOUND;
  709.             pLeaseData->currState = VERIFY;
  710.             return (DHCPC_MORE);
  711.             }
  712.         }
  713.     return (OK);
  714.     }
  715. /*******************************************************************************
  716. *
  717. * renewing - Specific lease renewal state of client finite state machine
  718. *
  719. * This routine contains the fifth state of the client finite state machine.
  720. * During this state, a DHCP lease is active. The routine handles all 
  721. * processing after the first lease timer has expired. If the server which 
  722. * issued the corresponding lease acknowledges the request for renewal, 
  723. * processing returns to the bound() routine. If the request is denied, the 
  724. * negotiation process restarts with the init() routine. If a timeout occurs
  725. * before the second lease timer has expired, the DHCP request message is 
  726. * retransmitted. Otherwise, processing continues with the rebinding() routine.
  727. * .IP
  728. * This routine is invoked by the event handler of the client monitor task,
  729. * and should only be called internally. Any arriving DHCP messages containing
  730. * stale offers from earlier states are discarded. User requests generated
  731. * by calls to the dhcpcRelease() and dhcpcVerify() routines are accepted.
  732. *
  733. * RETURNS: OK (processing complete), DHCPC_DONE (remove lease),
  734. *          DHCPC_MORE (continue), or ERROR.
  735. *
  736. * ERRNO: N/A
  737. *
  738. * NOMANUAL
  739. */
  740. int renewing
  741.     (
  742.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  743.     )
  744.     {
  745.     char *option = NULL;
  746.     char errmsg[255];
  747.     time_t curr_epoch = 0;
  748.     int timeout = 0;
  749.     int limit;
  750.     int length;
  751.     struct dhcp_param tmpparam;
  752.     int msgtype;
  753. #ifdef DHCPC_DEBUG
  754.     char newAddr [INET_ADDR_LEN];
  755. #endif
  756.     LEASE_DATA *  pLeaseData;
  757.     char *  pMsgData;
  758.     struct sockaddr_in dest;
  759.     struct ifnet * pIf;
  760.     bzero (errmsg, sizeof (errmsg));
  761.     if (dhcpTime (&curr_epoch) == -1) 
  762.         {
  763. #ifdef DHCPC_DEBUG
  764.         logMsg ("time() error in renewing()n", 0, 0, 0, 0, 0, 0);
  765. #endif
  766.         return (ERROR);
  767.         }
  768.     /*
  769.      * Use the cookie to access the lease-specific data structures. For now,
  770.      * just typecast the cookie. This translation could be replaced with a more
  771.      * sophisticated lookup at some point.
  772.      */
  773.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  774.     if (pEvent->source == DHCP_AUTO_EVENT)
  775.         {
  776.         if (pEvent->type == DHCP_TIMEOUT)
  777.             {
  778.             /*
  779.              * The interval between a timeout event and the entry to the 
  780.              * renewing() routine depends on the workload of the client 
  781.              * monitor task and is completely unpredictable. Either the 
  782.              * entire lease or the second lease timer may have expired 
  783.              * during that time. Also, the final (60 second) retransmission 
  784.              * timeout will always end after timer T2 has expired. If T2
  785.              * has expired but the lease has not, set the lease data to 
  786.              * continue with the rebinding() routine. If the lease has
  787.              * expired, return to the initial state. Otherwise (the most
  788.              * likely case), retransmit the request message since T2 has
  789.              * not expired.
  790.              */
  791.             limit = pLeaseData->dhcpcParam->lease_origin +
  792.                         pLeaseData->dhcpcParam->lease_duration;
  793.             if (curr_epoch >= limit)
  794.                 {
  795.                 /* Lease expired before processing started. */
  796.                 pLeaseData->prevState = RENEWING;
  797.                 pLeaseData->currState = INIT;
  798.                 return (DHCPC_MORE);
  799.                 }
  800.             limit = pLeaseData->dhcpcParam->lease_origin +
  801.                         pLeaseData->dhcpcParam->dhcp_t2;
  802.             if (limit <= curr_epoch)
  803.                 {
  804.                 /* 
  805.                  * Second timer expired: 
  806.                  *     request configuration data from any server. 
  807.                  */
  808.                 length = make_request (pLeaseData, REBINDING, TRUE);
  809.                 if (length < 0)
  810.                     {
  811. #ifdef DHCPC_DEBUG
  812.                  logMsg ("Error making rebind request. Entering INIT state.n",
  813.                          0, 0, 0, 0, 0, 0);
  814. #endif
  815.                     pLeaseData->prevState = RENEWING;
  816.                     pLeaseData->currState = INIT;
  817.                     return (DHCPC_MORE);
  818.                     }
  819.                 dhcpcMsgOut.udp->uh_sum = 0;
  820.                 dhcpcMsgOut.udp->uh_sum = udp_cksum(&spudph, 
  821.                                                     (char *)dhcpcMsgOut.udp, 
  822.                                                     ntohs (spudph.ulen));
  823.                 bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  824.                 dest.sin_len = sizeof (struct sockaddr_in);
  825.                 dest.sin_family = AF_INET;
  826.                 dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  827.                 pIf = pLeaseData->ifData.iface;
  828.                 if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  829.                     {
  830. #ifdef DHCPC_DEBUG
  831.                     logMsg ("Can't send DHCPREQUEST(REBINDING)n", 
  832.                             0, 0, 0, 0, 0, 0);
  833. #endif
  834.                     pLeaseData->prevState = RENEWING;
  835.                     pLeaseData->currState = INIT;
  836.                     return (DHCPC_MORE);
  837.                     }
  838.                 /* DHCP request sent. Set lease data to execute next state. */
  839.                 pLeaseData->prevState = RENEWING;
  840.                 pLeaseData->currState = REBINDING;
  841.                 pLeaseData->initEpoch = curr_epoch;
  842.                 /*
  843.                  * Set the retransmission timer to wait for one-half of the
  844.                  * remaining time before the lease expires, or 60 seconds if
  845.                  * it expires in less than one minute.
  846.                  */
  847.                 timeout = pLeaseData->dhcpcParam->lease_origin + 
  848.                             pLeaseData->dhcpcParam->lease_duration - 
  849.                                 curr_epoch;
  850.                 timeout /= 2;
  851.                 if (timeout < 60)
  852.                     timeout = 60;
  853.                 /* Set timer for retransmission of request message. */
  854.                 wdStart (pLeaseData->timer, sysClkRateGet() * timeout,
  855.                          (FUNCPTR)retrans_rebinding, (int)pLeaseData);
  856.                 }
  857.             else
  858.                 {
  859.                 /* Transmit lease renewal request to issuing server. */
  860.                 length = make_request (pLeaseData, RENEWING, FALSE);
  861.                 if (send_unicast (&pLeaseData->dhcpcParam->server_id, 
  862.                                   dhcpcMsgOut.dhcp, length) 
  863.                         < 0)
  864.                     {
  865. #ifdef DHCPC_DEBUG
  866.                     logMsg ("Can't send DHCPREQUEST(RENEWING)n", 
  867.                             0, 0, 0, 0, 0, 0);
  868. #endif
  869.                     pLeaseData->prevState = RENEWING;
  870.                     pLeaseData->currState = INIT;
  871.                     return (DHCPC_MORE);
  872.                     }
  873.                 pLeaseData->prevState = RENEWING;
  874.                 pLeaseData->currState = RENEWING;
  875.                 pLeaseData->initEpoch = curr_epoch;
  876.                 /*
  877.                  * Set the retransmission timer to wait for one-half of the
  878.                  * remaining time before T2 expires, or 60 seconds if T2
  879.                  * expires in less than one minute.
  880.                  */
  881.                 timeout = limit - curr_epoch;
  882.                 timeout /= 2;
  883.                 if (timeout < 60)
  884.                     timeout = 60;
  885.                 /* Set timer for retransmission of request message. */
  886.                 wdStart (pLeaseData->timer, sysClkRateGet() * timeout,
  887.                          (FUNCPTR)retrans_renewing, (int)pLeaseData);
  888.                 }
  889.             }    /* End of timeout processing. */
  890.         else
  891.             {
  892.             bzero ( (char *)&tmpparam, sizeof (tmpparam));
  893.             /*
  894.              * Process DHCP message stored in receive buffer by monitor task.
  895.              * The 4-byte alignment of the IP header needed by Sun BSP's is
  896.              * guaranteed by the Berkeley Packet Filter during input.
  897.              */
  898.             pMsgData = pLeaseData->msgBuffer;
  899.             align_msg (&dhcpcMsgIn, pMsgData);
  900.             /* Examine type of message. Accept DHCPACK or DHCPNAK replies. */
  901.             option = (char *)pickup_opt (dhcpcMsgIn.dhcp, 
  902.                                          DHCPLEN (dhcpcMsgIn.udp),
  903.                                          _DHCP_MSGTYPE_TAG);
  904.             if (option == NULL)
  905.                 {
  906.                 /*
  907.                  * Message type not found -  ignore untyped DHCP messages, and
  908.                  * any BOOTP replies.
  909.                  */
  910.                 return (OK);
  911.                 }
  912.             else
  913.                 {
  914.                 msgtype = *OPTBODY (option);
  915.                 if (msgtype == DHCPNAK)
  916.                     {
  917. #ifdef DHCPC_DEBUG
  918.                     logMsg ("Got DHCPNAK in renewing()n", 0, 0, 0, 0, 0, 0);
  919.                     option = (char *)pickup_opt (dhcpcMsgIn.dhcp,
  920.                                                  DHCPLEN (dhcpcMsgIn.udp),
  921.                                                  _DHCP_ERRMSG_TAG);
  922.                     if (option != NULL &&
  923.                         nvttostr (OPTBODY (option), errmsg,
  924.                                   (int)DHCPOPTLEN (option)) == 0)
  925.                         logMsg ("DHCPNAK contains the error message "%s"n",
  926.                                  (int)errmsg, 0, 0, 0, 0, 0);
  927. #endif
  928.                     clean_param (pLeaseData->dhcpcParam);
  929.                     free (pLeaseData->dhcpcParam);
  930.                     pLeaseData->dhcpcParam = NULL;
  931.                     pLeaseData->prevState = RENEWING;
  932.                     pLeaseData->currState = INIT;
  933.                     return (DHCPC_MORE);
  934.                     }
  935.                 else if (msgtype == DHCPACK)
  936.                     {
  937.                     /* Fill in host requirements defaults. */
  938.                     dhcpcDefaultsSet (&tmpparam);
  939.                     if (dhcp_msgtoparam (dhcpcMsgIn.dhcp, 
  940.                                          DHCPLEN (dhcpcMsgIn.udp),
  941.                                          &tmpparam) == OK)
  942.                         {
  943.                         merge_param (pLeaseData->dhcpcParam, &tmpparam);
  944.                         *(pLeaseData->dhcpcParam) = tmpparam;
  945.                         pLeaseData->dhcpcParam->lease_origin =
  946.                             pLeaseData->initEpoch;
  947. #ifdef DHCPC_DEBUG
  948.                         inet_ntoa_b (pLeaseData->dhcpcParam->yiaddr, newAddr);
  949.                         logMsg ("Got DHCPACK (IP = %s, duration = %d secs)n",
  950.                                 (int)newAddr,
  951.                                 pLeaseData->dhcpcParam->lease_duration,
  952.                                 0, 0, 0, 0);
  953. #endif
  954.                         /* 
  955.                          * Send an ARP reply to update the ARP cache on other
  956.                          * hosts if the assigned IP address was applied to
  957.                          * the underlying network interface.
  958.                          */
  959.                         if (pLeaseData->autoConfig || 
  960.                                 pLeaseData->leaseType == DHCP_AUTOMATIC)
  961.                             arp_reply (&pLeaseData->dhcpcParam->yiaddr, 
  962.                                        &pLeaseData->ifData);
  963.                         pLeaseData->prevState = RENEWING;
  964.                         pLeaseData->currState = BOUND;
  965.                         }
  966.                     return (DHCPC_MORE);
  967.                     }
  968.                 }    /* End of processing for typed DHCP message. */
  969.             }    /* End of DHCP message processing. */
  970.         }
  971.     else
  972.         {
  973.         /* Process user requests. */
  974.         if (pEvent->type == DHCP_USER_RELEASE)    /* Relinquish lease. */
  975.             {
  976.             release (pLeaseData, TRUE);
  977.             return (DHCPC_DONE);
  978.             }
  979.         if (pEvent->type == DHCP_USER_VERIFY)    /* Verify lease. */
  980.             {
  981.             /* Set the lease data to execute verify() routine. */
  982.             pLeaseData->prevState = RENEWING;
  983.             pLeaseData->currState = VERIFY;
  984.             return (DHCPC_MORE);
  985.             }
  986.         }
  987.     return (OK);
  988.     }
  989. /*******************************************************************************
  990. *
  991. * rebinding - Promiscuous lease renewal state of client finite state machine
  992. *
  993. * This routine contains the sixth state of the client finite state machine.
  994. * During this state, a DHCP lease is active. The routine handles all
  995. * processing after the second lease timer has expired. It accepts
  996. * lease acknowledgements from any DHCP server in response to an earlier
  997. * subnet local broadcast of a lease request. If an acknowlegement is received,
  998. * processing returns to the bound() routine. If a DHCP server explicitly 
  999. * denies the request, the negotiation restarts with the init() routine.
  1000. * Otherwise, the broadcast is repeated periodically until the lease expires.
  1001. * .IP
  1002. * This routine is invoked by the event handler of the client monitor task,
  1003. * and should only be called internally. Any arriving DHCP messages containing
  1004. * stale offers from earlier states are discarded. User requests generated
  1005. * by calls to the dhcpcRelease() and dhcpcVerify() routines are accepted.
  1006. *
  1007. * RETURNS: OK (processing complete), DHCPC_DONE (remove lease),
  1008. *          DHCPC_MORE (continue), or ERROR.
  1009. *
  1010. * ERRNO: N/A
  1011. *
  1012. * NOMANUAL
  1013. */
  1014. int rebinding
  1015.     (
  1016.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  1017.     )
  1018.     {
  1019.     char *option = NULL;
  1020.     char errmsg[255];
  1021.     time_t curr_epoch = 0;
  1022.     int timeout;
  1023.     int limit;
  1024.     int msgtype;
  1025.     int status;
  1026.     struct dhcp_param tmpparam;
  1027. #ifdef DHCPC_DEBUG
  1028.     char newAddr [INET_ADDR_LEN];
  1029. #endif
  1030.     LEASE_DATA *  pLeaseData;
  1031.     char *  pMsgData;
  1032.     int  length;
  1033.     struct sockaddr_in  dest;
  1034.     struct ifnet *  pIf;
  1035.     struct ifreq  ifr;
  1036.     bzero (errmsg, sizeof (errmsg));
  1037.     bzero ( (char *)&tmpparam, sizeof (tmpparam));
  1038.     if (dhcpTime (&curr_epoch) == -1) 
  1039.         {
  1040. #ifdef DHCPC_DEBUG
  1041.         logMsg ("time() error in rebinding()n", 0, 0, 0, 0, 0, 0);
  1042. #endif
  1043.         return (ERROR);
  1044.         }
  1045.     /*
  1046.      * Use the cookie to access the lease-specific data structures. For now,
  1047.      * just typecast the cookie. This translation could be replaced with a more
  1048.      * sophisticated lookup at some point.
  1049.      */
  1050.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  1051.     if (pLeaseData->prevState == BOUND)
  1052.         {
  1053.         /* Resume filtering with the BPF device (suspended while bound). */
  1054.         bzero ( (char *)&ifr, sizeof (struct ifreq));
  1055.         sprintf (ifr.ifr_name, "%s%d", pLeaseData->ifData.iface->if_name,
  1056.                                        pLeaseData->ifData.iface->if_unit);
  1057.         ioctl (pLeaseData->ifData.bpfDev, BIOCSTART, (int)&ifr);
  1058.         }
  1059.     if (pEvent->source == DHCP_AUTO_EVENT)
  1060.         {
  1061.         if (pEvent->type == DHCP_TIMEOUT)
  1062.             {
  1063.             /*
  1064.              * The interval between a timeout event and the entry to the
  1065.              * rebinding() routine depends on the workload of the client
  1066.              * monitor task and is completely unpredictable. The lease
  1067.              * may have expired during that time, and the final retransmission 
  1068.              * timeout will always end after the lease has expired. In either 
  1069.              * case, set the lease data to restart the negotiation with the 
  1070.              * init() routine. Otherwise, repeat the broadcast of the request 
  1071.              * message.
  1072.              */
  1073.             limit = pLeaseData->dhcpcParam->lease_origin +
  1074.                         pLeaseData->dhcpcParam->lease_duration;
  1075.             if (limit <= curr_epoch)
  1076.                 {
  1077.                 /* Lease has expired: 
  1078.                  *    shut down network and return to initial state. 
  1079.                  */
  1080. #ifdef DHCPC_DEBUG
  1081.                 logMsg ("Can't extend lease. Entering INIT state.n", 
  1082.                         0, 0, 0, 0, 0, 0);
  1083. #endif
  1084.                 pLeaseData->prevState = REBINDING;
  1085.                 pLeaseData->currState = INIT;
  1086.                 return (DHCPC_MORE);
  1087.                 }
  1088.             /* Retransmit rebinding request. */
  1089.             length = make_request (pLeaseData, REBINDING, FALSE);
  1090.             if (length < 0)
  1091.                 {
  1092. #ifdef DHCPC_DEBUG
  1093.                 logMsg ("Error making rebind request. Entering INIT state.n",
  1094.                         0, 0, 0, 0, 0, 0);
  1095. #endif
  1096.                 pLeaseData->prevState = REBINDING;
  1097.                 pLeaseData->currState = INIT;
  1098.                 return (DHCPC_MORE);
  1099.                 }
  1100.             dhcpcMsgOut.udp->uh_sum = 0;
  1101.             dhcpcMsgOut.udp->uh_sum = udp_cksum(&spudph,
  1102.                                                 (char *)dhcpcMsgOut.udp,
  1103.                                                 ntohs (spudph.ulen));
  1104.             bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  1105.             dest.sin_len = sizeof (struct sockaddr_in);
  1106.             dest.sin_family = AF_INET;
  1107.             dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  1108.             pIf = pLeaseData->ifData.iface;
  1109.             if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  1110.                 {
  1111. #ifdef DHCPC_DEBUG
  1112.                 logMsg ("Can't send DHCPREQUEST(REBINDING)n",
  1113.                         0, 0, 0, 0, 0, 0);
  1114. #endif
  1115.                 pLeaseData->prevState = REBINDING;
  1116.                 pLeaseData->currState = INIT;
  1117.                 return (DHCPC_MORE);
  1118.                 }
  1119.             /* DHCP request sent. Set lease data to repeat current state. */
  1120.             pLeaseData->prevState = REBINDING;
  1121.             pLeaseData->currState = REBINDING;
  1122.             pLeaseData->initEpoch = curr_epoch;
  1123.            /*
  1124.             * Set the retransmission timer to wait for one-half of the
  1125.             * remaining time before the lease expires, or 60 seconds if it
  1126.             * expires in less than one minute.
  1127.             */
  1128.            timeout = pLeaseData->dhcpcParam->lease_origin +
  1129.                         pLeaseData->dhcpcParam->lease_duration -
  1130.                             curr_epoch;
  1131.             timeout /= 2;
  1132.             if (timeout < 60)
  1133.                 timeout = 60;
  1134.             /* Set timer for retransmission of request message. */
  1135.             wdStart (pLeaseData->timer, sysClkRateGet() * timeout,
  1136.                      (FUNCPTR)retrans_rebinding, (int)pLeaseData);
  1137.             }    /* End of timeout processing. */
  1138.         else
  1139.             {
  1140.             bzero ( (char *)&tmpparam, sizeof (tmpparam));
  1141.             /*
  1142.              * Process DHCP message stored in receive buffer by monitor task.
  1143.              * The 4-byte alignment of the IP header needed by Sun BSP's is
  1144.              * guaranteed by the Berkeley Packet Filter during input.
  1145.              */
  1146.             pMsgData = pLeaseData->msgBuffer;
  1147.             align_msg (&dhcpcMsgIn, pMsgData);
  1148.             /* Examine type of message. Accept DHCPACK or DHCPNAK replies. */
  1149.             option = (char *)pickup_opt (dhcpcMsgIn.dhcp,
  1150.                                          DHCPLEN (dhcpcMsgIn.udp),
  1151.                                          _DHCP_MSGTYPE_TAG);
  1152.             if (option == NULL)
  1153.                 {
  1154.                 /*
  1155.                  * Message type not found -  ignore untyped DHCP messages, and
  1156.                  * any BOOTP replies.
  1157.                  */
  1158.                 return (OK);
  1159.                 }
  1160.             else
  1161.                 {
  1162.                 msgtype = *OPTBODY (option);
  1163.                 if (msgtype == DHCPNAK)
  1164.                     {
  1165. #ifdef DHCPC_DEBUG
  1166.                     logMsg ("Got DHCPNAK in rebinding()n", 0, 0, 0, 0, 0, 0);
  1167.                     option = (char *)pickup_opt (dhcpcMsgIn.dhcp,
  1168.                                                  DHCPLEN (dhcpcMsgIn.udp),
  1169.                                                  _DHCP_ERRMSG_TAG);
  1170.                     if (option != NULL &&
  1171.                         nvttostr (OPTBODY (option), errmsg,
  1172.                                   (int)DHCPOPTLEN (option)) == 0)
  1173.                         logMsg ("DHCPNAK contains the error message "%s"n",
  1174.                                  (int)errmsg, 0, 0, 0, 0, 0);
  1175. #endif
  1176.                     clean_param (pLeaseData->dhcpcParam);
  1177.                     free (pLeaseData->dhcpcParam);
  1178.                     pLeaseData->dhcpcParam = NULL;
  1179.                     pLeaseData->prevState = REBINDING;
  1180.                     pLeaseData->currState = INIT;
  1181.                     return (DHCPC_MORE);
  1182.                     }
  1183.                 else if (msgtype == DHCPACK)
  1184.                     {
  1185.                     /* Fill in host requirements defaults. */
  1186.                     dhcpcDefaultsSet (&tmpparam);
  1187.                     if (dhcp_msgtoparam (dhcpcMsgIn.dhcp,
  1188.                                          DHCPLEN (dhcpcMsgIn.udp),
  1189.                                          &tmpparam) == OK)
  1190.                         {
  1191.                         merge_param (pLeaseData->dhcpcParam, &tmpparam);
  1192.                         *(pLeaseData->dhcpcParam) = tmpparam;
  1193.                         pLeaseData->dhcpcParam->lease_origin =
  1194.                             pLeaseData->initEpoch;
  1195. #ifdef DHCPC_DEBUG
  1196.                         inet_ntoa_b (pLeaseData->dhcpcParam->yiaddr, newAddr);
  1197.                         logMsg ("Got DHCPACK (IP = %s, duration = %d secs)n",
  1198.                                 (int)newAddr,
  1199.                                 pLeaseData->dhcpcParam->lease_duration,
  1200.                                 0, 0, 0, 0);
  1201. #endif
  1202.                         status = use_parameter (pLeaseData->dhcpcParam,
  1203.                                                 pLeaseData);
  1204.                         semTake (dhcpcMutexSem, WAIT_FOREVER);
  1205.                         if (status != 0)
  1206.                             {
  1207. #ifdef DHCPC_DEBUG
  1208.                          logMsg ("Error configuring network. Shutting down.n",
  1209.                                   0, 0, 0, 0, 0, 0);
  1210. #endif
  1211.                             pLeaseData->leaseGood = FALSE;
  1212.                             }
  1213.                         else
  1214.                             {
  1215.                             pLeaseData->leaseGood = TRUE;
  1216.                             }
  1217.                         semGive (dhcpcMutexSem);
  1218.                         pLeaseData->prevState = REBINDING;
  1219.                         pLeaseData->currState = BOUND;
  1220.                         }
  1221.                     return (DHCPC_MORE);
  1222.                     }
  1223.                 }    /* End of processing for typed DHCP message. */
  1224.             }    /* End of DHCP message processing. */
  1225.         }
  1226.     else
  1227.         {
  1228.         /* Process user requests. */
  1229.         if (pEvent->type == DHCP_USER_RELEASE)    /* Relinquish lease. */
  1230.             {
  1231.             release (pLeaseData, TRUE);
  1232.             return (DHCPC_DONE);
  1233.             }
  1234.         if (pEvent->type == DHCP_USER_VERIFY)    /* Verify lease. */
  1235.             {
  1236.             /* Set the lease data to execute verify() routine. */
  1237.             pLeaseData->prevState = REBINDING;
  1238.             pLeaseData->currState = VERIFY;
  1239.             return (DHCPC_MORE);
  1240.             }
  1241.         }
  1242.     return (OK);
  1243.     }
  1244. /*******************************************************************************
  1245. *
  1246. * init_reboot - Rebooting state of the client finite state machine
  1247. *
  1248. * This routine implements the "zeroth" state of the client finite state
  1249. * machine. It attempts to renew an active lease after the client has
  1250. * rebooted. This generally requires the presence of a cache, but the lease
  1251. * data may also be read from global variables to renew the lease obtained
  1252. * during system startup. If no lease data is found or renewal fails, processing
  1253. * continues with the INIT state.
  1254. * .IP
  1255. * This routine is invoked by the event handler of the client monitor task,
  1256. * and should only be called internally. Any user requests generated by
  1257. * incorrect calls or delayed responses to the dhcpcVerify() routine are 
  1258. * ignored.
  1259. *
  1260. * RETURNS: OK (processing complete), DHCPC_DONE (remove lease),
  1261. *          DHCPC_MORE (continue), or ERROR.
  1262. *
  1263. * ERRNO: N/A
  1264. *
  1265. * INTERNAL
  1266. *
  1267. * When calculating the values for the lease timers, floating-point calculations
  1268. * can't be used because some boards (notably the SPARC architectures) disable
  1269. * software floating point by default to speed up context switching. These
  1270. * boards abort with an exception when floating point operations are
  1271. * encountered. The error introduced by the integer approximations is not
  1272. * significant.
  1273. *
  1274. * NOMANUAL
  1275. */
  1276. int init_reboot
  1277.     (
  1278.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  1279.     )
  1280.     {
  1281.     char *rbufp = NULL;
  1282.     STATUS result;
  1283.     int length = 0;
  1284.     unsigned long origin = 0;
  1285.     int tmp;
  1286.     int status;
  1287.     struct sockaddr_in dest;
  1288.     struct ifnet *  pIf;
  1289.     LEASE_DATA *  pLeaseData = NULL;
  1290.     /*
  1291.      * Use the cookie to access the lease-specific data structures. For now,
  1292.      * just typecast the cookie. This translation could be replaced with a more
  1293.      * sophisticated lookup at some point.
  1294.      */
  1295.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  1296.     /*
  1297.      * The DHCP_USER_RELEASE event occurs in response to the dhcpcRelease()
  1298.      * or dhcpcShutdown() call. Remove all data structures for this lease.
  1299.      */
  1300.     if (pEvent->type == DHCP_USER_RELEASE)
  1301.         {
  1302.         dhcpcLeaseCleanup (pLeaseData);
  1303.         return (DHCPC_DONE);
  1304.         }
  1305.     /* Ignore verify user events, which are meaningless here. */
  1306.     if (pEvent->source == DHCP_USER_EVENT && pEvent->type != DHCP_USER_BIND)
  1307.         return (OK);
  1308.     /* 
  1309.      * Safety check - ignore timeouts and message arrivals, which are
  1310.      * theoretically possible under extremely unlikely chains of events.
  1311.      */
  1312.       
  1313.     if (pEvent->source == DHCP_AUTO_EVENT)
  1314.         return (OK);
  1315.     /* If a cache is needed and unavailable, restart from the INIT state. */
  1316.     if (pLeaseData->cacheHookRtn == NULL &&
  1317.             pLeaseData->leaseType == DHCP_MANUAL)
  1318.         {
  1319.         pLeaseData->prevState = INIT_REBOOT;
  1320.         pLeaseData->currState = INIT;
  1321.         return (DHCPC_MORE);
  1322.         }
  1323. #ifdef DHCPC_DEBUG
  1324.     logMsg("dhcpc: Attempting to re-use parameters.n", 0, 0, 0, 0, 0, 0);
  1325. #endif
  1326.     bzero (sbuf.buf, sbuf.size);
  1327.     /*
  1328.      * The client might have established a lease (during boot-time) with
  1329.      * an older DHCP server which ignores messages less than the minimum
  1330.      * length obtained with a fixed options field. Set this lease attempt
  1331.      * to pad the renewal request to the minimum size (for RFC 1541) to
  1332.      * avoid unnecessary retransmissions in that case.
  1333.      */
  1334.     pLeaseData->oldFlag = TRUE;
  1335.      
  1336.     if (pLeaseData->leaseType == DHCP_MANUAL)   
  1337.         {
  1338.         /*
  1339.          * Post-boot: read from cache into aligned scratch buffer
  1340.          * (used during other states to transmit DHCP messages).
  1341.          */
  1342.         length = sbuf.size;
  1343.         rbufp = sbuf.buf;
  1344.         result = (* pLeaseData->cacheHookRtn) (DHCP_CACHE_READ, &origin, 
  1345.                                                &length, rbufp);
  1346.         if (result != OK)     /* Can't re-use stored parameters. */
  1347.             {
  1348.             pLeaseData->prevState = INIT_REBOOT;
  1349.             pLeaseData->currState = INIT;
  1350.             return (DHCPC_MORE);
  1351.             }
  1352.         /*
  1353.          * Set the pointers to access the individual DHCP message components.
  1354.          */
  1355.         dhcpcMsgIn.ip = (struct ip *)rbufp;
  1356. #if BSD<44
  1357.     dhcpcMsgIn.udp = (struct udphdr *)&rbufp [(dhcpcMsgIn.ip->ip_v_hl & 0xf) * 
  1358.                                               WORD];
  1359.     dhcpcMsgIn.dhcp = (struct dhcp *) &rbufp [(dhcpcMsgIn.ip->ip_v_hl & 0xf) * 
  1360.                                               WORD + UDPHL];
  1361. #else
  1362.     dhcpcMsgIn.udp = (struct udphdr *)&rbufp [dhcpcMsgIn.ip->ip_hl * WORD];
  1363.     dhcpcMsgIn.dhcp = (struct dhcp *) &rbufp [dhcpcMsgIn.ip->ip_hl * WORD + 
  1364.                                               UDPHL];
  1365. #endif
  1366.         }
  1367.     if (pLeaseData->dhcpcParam == NULL)
  1368.         {
  1369.         pLeaseData->dhcpcParam = (struct dhcp_param *)calloc (1,
  1370.                                                    sizeof (struct dhcp_param));
  1371.         if (pLeaseData->dhcpcParam == NULL)
  1372.             {
  1373. #ifdef DHCPC_DEBUG
  1374.             logMsg ("calloc() error in init_reboot()n", 0, 0, 0, 0, 0, 0);
  1375. #endif
  1376.             pLeaseData->prevState = INIT_REBOOT;
  1377.             pLeaseData->currState = INIT;
  1378.             return (DHCPC_MORE);
  1379.             }
  1380.         }
  1381.     if (pLeaseData->leaseType == DHCP_AUTOMATIC)
  1382.         {
  1383.         /* Get parameters previously read from bootline. */
  1384.         bcopy ( (char *)&dhcpcBootLease.yiaddr, 
  1385.                (char *)&pLeaseData->dhcpcParam->yiaddr,
  1386.                sizeof (struct in_addr));
  1387.         origin = dhcpcBootLease.lease_origin;
  1388.         pLeaseData->dhcpcParam->lease_duration = dhcpcBootLease.lease_duration;
  1389.         pLeaseData->dhcpcParam->dhcp_t1 =
  1390.             pLeaseData->dhcpcParam->lease_duration / 2;
  1391.         SETBIT (pLeaseData->dhcpcParam->got_option, _DHCP_T1_TAG);
  1392.         /* Set t2 to .875 of lease without using floating point. */
  1393.         tmp = (pLeaseData->dhcpcParam->lease_duration * 7) >> 3;
  1394.         pLeaseData->dhcpcParam->dhcp_t2 = (unsigned long)tmp;
  1395.         SETBIT (pLeaseData->dhcpcParam->got_option, _DHCP_T2_TAG);
  1396.         }
  1397.     else                             /* Get parameters from cached message. */
  1398.         {
  1399.         /* Host requirements defaults. */
  1400.         dhcpcDefaultsSet (pLeaseData->dhcpcParam);   
  1401.         if (dhcp_msgtoparam (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp), 
  1402.                              pLeaseData->dhcpcParam) != OK)
  1403.             {
  1404. #ifdef DHCPC_DEBUG
  1405.             logMsg("dhcp_msgtoparam() error in init_reboot()n",
  1406.                     0, 0, 0, 0, 0, 0);
  1407. #endif
  1408.             clean_param (pLeaseData->dhcpcParam);
  1409.             free (pLeaseData->dhcpcParam);
  1410.             pLeaseData->dhcpcParam = NULL;
  1411.             pLeaseData->prevState = INIT_REBOOT;
  1412.             pLeaseData->currState = INIT;
  1413.             return (DHCPC_MORE);
  1414.             }
  1415.         }
  1416.     pLeaseData->dhcpcParam->lease_origin = origin;
  1417.     /*
  1418.      * If the cache contained a BOOTP reply, no further processing is needed.
  1419.      * Set the lease type to prevent the inclusion of timing information in 
  1420.      * the bootline so that a later reboot will not attempt to renew the lease.
  1421.      */
  1422.     if (pLeaseData->leaseType == DHCP_MANUAL &&
  1423.             pLeaseData->dhcpcParam->msgtype == DHCP_BOOTP)
  1424.         {
  1425.         pLeaseData->leaseType = DHCP_BOOTP;
  1426.         pLeaseData->prevState = INIT_REBOOT;
  1427.         pLeaseData->currState = BOUND;
  1428.         status = use_parameter (pLeaseData->dhcpcParam, pLeaseData);
  1429.         semTake (dhcpcMutexSem, WAIT_FOREVER);
  1430.         if (status != 0)
  1431.             {
  1432. #ifdef DHCPC_DEBUG
  1433.             logMsg ("Error configuring network. Shutting down.n",
  1434.                     0, 0, 0, 0, 0, 0);
  1435. #endif
  1436.             pLeaseData->leaseGood = FALSE;
  1437.             pLeaseData->prevState = INIT_REBOOT;
  1438.             pLeaseData->currState = INIT;
  1439.             }
  1440.         else
  1441.             {
  1442.             pLeaseData->leaseGood = TRUE;
  1443.             }
  1444.         semGive (dhcpcMutexSem);
  1445.         if (status != 0)
  1446.             return (DHCPC_MORE);
  1447.         return (OK);
  1448.         }
  1449.     /* The cache contained the record of a DHCP lease. Send the request. */
  1450.     length = make_request (pLeaseData, REBOOTING, TRUE);
  1451.     if (length < 0)
  1452.         {
  1453. #ifdef DHCPC_DEBUG
  1454.         logMsg("error constructing REBOOTING message. Entering INIT state.n",
  1455.                0, 0, 0, 0, 0, 0);
  1456. #endif
  1457.         pLeaseData->prevState = INIT_REBOOT;
  1458.         pLeaseData->currState = INIT;
  1459.         return (DHCPC_MORE);
  1460.         }
  1461.     dhcpcMsgOut.udp->uh_sum = 0;
  1462.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp, 
  1463.                                          ntohs (spudph.ulen));
  1464.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  1465.     dest.sin_len = sizeof (struct sockaddr_in);
  1466.     dest.sin_family = AF_INET;
  1467.     dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  1468.     pIf = pLeaseData->ifData.iface;
  1469.     if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  1470.         {
  1471. #ifdef DHCPC_DEBUG
  1472.         logMsg ("Can't send DHCPREQUEST(REBOOTING)n", 0, 0, 0, 0, 0, 0);
  1473. #endif
  1474.         pLeaseData->prevState = INIT_REBOOT;
  1475.         pLeaseData->currState = INIT;
  1476.         return (DHCPC_MORE);
  1477.         }
  1478.     /* Set lease data to execute next state and start retransmission timer. */
  1479.     pLeaseData->prevState = INIT_REBOOT;
  1480.     pLeaseData->currState = REBOOTING;
  1481.     pLeaseData->timeout = FIRSTTIMER;
  1482.     pLeaseData->numRetry = 0;
  1483.     wdStart (pLeaseData->timer, sysClkRateGet() *
  1484.                                 SLEEP_RANDOM (pLeaseData->timeout),
  1485.              (FUNCPTR)retrans_reboot_verify, (int)pLeaseData);
  1486.     return (OK);
  1487.     }
  1488. /*******************************************************************************
  1489. *
  1490. * verify - Initial lease verification state of client finite state machine
  1491. *
  1492. * This routine begins the verification process by broadcasting a DHCP verify
  1493. * message. It is called in response to the user request generated by the
  1494. * dhcpcVerify() routine in the API.
  1495. *
  1496. * RETURNS: OK (processing complete), ERROR (failure), or DHCPC_MORE (continue).
  1497. *
  1498. * ERRNO: N/A
  1499. *
  1500. * NOMANUAL
  1501. */
  1502. int verify
  1503.     (
  1504.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  1505.     )
  1506.     {
  1507.     int limit = 0;
  1508.     int length;
  1509.     time_t  curr_epoch;
  1510.     LEASE_DATA *  pLeaseData;
  1511.     struct sockaddr_in  dest;
  1512.     struct ifnet *  pIf;
  1513.     struct ifreq  ifr;
  1514.     if (dhcpTime (&curr_epoch) == -1)
  1515.         {
  1516. #ifdef DHCPC_DEBUG
  1517.         logMsg ("time() error in verify()n", 0, 0, 0, 0, 0, 0);
  1518. #endif
  1519.         return (ERROR);
  1520.         }
  1521.     /*
  1522.      * Use the cookie to access the lease-specific data structures. For now,
  1523.      * just typecast the cookie. This translation could be replaced with a more
  1524.      * sophisticated lookup at some point.
  1525.      */
  1526.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  1527.     if (pLeaseData->prevState == BOUND)
  1528.         {
  1529.         /* Resume filtering with the BPF device (suspended while bound). */
  1530.         bzero ( (char *)&ifr, sizeof (struct ifreq));
  1531.         sprintf (ifr.ifr_name, "%s%d", pLeaseData->ifData.iface->if_name,
  1532.                                        pLeaseData->ifData.iface->if_unit);
  1533.         ioctl (pLeaseData->ifData.bpfDev, BIOCSTART, (int)&ifr);
  1534.         }
  1535.     /*
  1536.      * The interval between the user request and the entry to the verify() 
  1537.      * routine depends on the workload of the client monitor task and the
  1538.      * status of the lease timers. The lease may have expired before this
  1539.      * routine executes, which will cause the negotiation process to restart
  1540.      * with the init() routine.
  1541.      */
  1542.     limit = pLeaseData->dhcpcParam->lease_origin +
  1543.                 pLeaseData->dhcpcParam->lease_duration;
  1544.     if (limit <= curr_epoch)
  1545.         {
  1546.         pLeaseData->prevState = VERIFY;
  1547.         pLeaseData->currState = INIT;
  1548.         return (DHCPC_MORE);
  1549.         }
  1550.  
  1551.     length = make_request (pLeaseData, VERIFYING, TRUE);
  1552.     if (length < 0)
  1553.         {
  1554. #ifdef DHCPC_DEBUG
  1555.         logMsg("Unable to construct verify message. Entering INIT state.n",
  1556.                 0, 0, 0, 0, 0, 0);
  1557. #endif
  1558.         pLeaseData->prevState = VERIFY;
  1559.         pLeaseData->currState = INIT;
  1560.         return (DHCPC_MORE);
  1561.         }
  1562.     dhcpcMsgOut.udp->uh_sum = 0;
  1563.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp, 
  1564.                                          ntohs (spudph.ulen));
  1565.     if (dhcpTime (&pLeaseData->initEpoch) == -1)
  1566.         {
  1567. #ifdef DHCPC_DEBUG
  1568.         logMsg ("time() error setting initEpochn", 0, 0, 0, 0, 0, 0);
  1569. #endif
  1570.         return (ERROR);
  1571.         }
  1572.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  1573.     dest.sin_len = sizeof (struct sockaddr_in);
  1574.     dest.sin_family = AF_INET;
  1575.     dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  1576.     pIf = pLeaseData->ifData.iface;
  1577.     if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  1578.         {
  1579. #ifdef DHCPC_DEBUG
  1580.         logMsg("Can't send DHCPREQUEST(VERIFY)n", 0, 0, 0, 0, 0, 0);
  1581. #endif
  1582.         pLeaseData->prevState = VERIFY;
  1583.         pLeaseData->currState = INIT;
  1584.         return (DHCPC_MORE);
  1585.         }
  1586.     /* Set lease data to execute next state and start retransmission timer. */
  1587.     pLeaseData->prevState = VERIFY;
  1588.     pLeaseData->currState = VERIFYING;
  1589.     pLeaseData->timeout = FIRSTTIMER;
  1590.     pLeaseData->numRetry = 0;
  1591.     wdStart (pLeaseData->timer, sysClkRateGet() *
  1592.                                 SLEEP_RANDOM (pLeaseData->timeout),
  1593.              (FUNCPTR)retrans_reboot_verify, (int)pLeaseData);
  1594.     return (OK);    /* Next state is REBOOT_VERIFY */
  1595.     }
  1596. /*******************************************************************************
  1597. *
  1598. * reboot_verify - Final lease verification state of client finite state machine
  1599. *
  1600. * This routine continues the verification process of the finite state machine
  1601. * by waiting for a server response until the current timeout value expires.
  1602. * If a timeout occurs, the DHCP message is retransmitted. This routine collects
  1603. * the replies for manual lease renewals and lease renewals resulting from a
  1604. * reboot of the client.
  1605. *
  1606. * RETURNS: OK (processing complete), DHCPC_DONE (remove lease),
  1607. *          DHCPC_MORE (continue), or ERROR.
  1608. *
  1609. * ERRNO: N/A
  1610. *
  1611. * NOMANUAL
  1612. */
  1613. int reboot_verify
  1614.     (
  1615.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  1616.     )
  1617.     {
  1618.     int arpans = 0;
  1619.     time_t curr_epoch = 0;
  1620.     char *option = NULL;
  1621.     char errmsg[255];
  1622.     int timer = 0;
  1623.     int retry = 0;
  1624.     int msgtype;
  1625.     struct dhcp_param tmpparam;
  1626.     struct dhcp_reqspec tmp_reqspec;
  1627.     int status = 0;
  1628. #ifdef DHCPC_DEBUG
  1629.     char newAddr [INET_ADDR_LEN];
  1630. #endif
  1631.     LEASE_DATA *  pLeaseData = NULL;
  1632.     char *  pMsgData;
  1633.     int  length;
  1634.     /*
  1635.      * Use the cookie to access the lease-specific data structures. For now,
  1636.      * just typecast the cookie. This translation could be replaced with a more
  1637.      * sophisticated lookup at some point.
  1638.      */
  1639.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  1640.     /*
  1641.      * The DHCP_USER_RELEASE event occurs in response to the dhcpcRelease()
  1642.      * or dhcpcShutdown() call. Remove all data structures for this lease.
  1643.      */
  1644.     if (pEvent->type == DHCP_USER_RELEASE)
  1645.         {
  1646.         dhcpcLeaseCleanup (pLeaseData);
  1647.         return (DHCPC_DONE);
  1648.         }
  1649.     /* Ignore bind and verify user events, which are meaningless here. */
  1650.     if (pEvent->source == DHCP_USER_EVENT)
  1651.         return (OK);
  1652.     bzero (errmsg, sizeof (errmsg));
  1653.     bzero ( (char *)&tmpparam, sizeof (tmpparam));
  1654.     bzero( (char *)&tmp_reqspec, sizeof (tmp_reqspec));
  1655.     if (dhcpTime (&curr_epoch) == -1)
  1656.         {
  1657. #ifdef DHCPC_DEBUG
  1658.         logMsg ("time() error in reboot_verify()n", 0, 0, 0, 0, 0, 0);
  1659. #endif
  1660.         return (ERROR);
  1661.         }
  1662.     if (pEvent->type == DHCP_TIMEOUT)
  1663.         {
  1664.         /*
  1665.          * The interval between a timeout event and the entry to the
  1666.          * reboot_verify() routine depends on the workload of the client
  1667.          * monitor task and is completely unpredictable. The lease
  1668.          * may have expired during that time. The lease may also expire
  1669.          * before the retransmission limit is reached. In either case, set 
  1670.          * the lease data to restart the negotiation with the init() routine.
  1671.          * If the retransmission limit is reached before the lease expires,
  1672.          * return to the BOUND state. Otherwise, retransmit the request 
  1673.          * message.
  1674.          */
  1675.         retry = pLeaseData->numRetry;
  1676.         timer = pLeaseData->timeout;
  1677.         retry++;
  1678.         if (retry > REQUEST_RETRANS)    /* Retransmission limit reached. */
  1679.             {
  1680. #ifdef DHCPC_DEBUG
  1681.             logMsg("No server response received. Giving up.n", 
  1682.                    0, 0, 0, 0, 0, 0);
  1683. #endif
  1684.             if (pLeaseData->prevState == INIT_REBOOT)
  1685.                 {
  1686.                 pLeaseData->currState = INIT;
  1687.                 } 
  1688.             else if (pLeaseData->dhcpcParam->lease_origin == 0 ||
  1689.                        pLeaseData->dhcpcParam->lease_origin + 
  1690.                          pLeaseData->dhcpcParam->lease_duration <= curr_epoch)
  1691.                 {
  1692. #ifdef DHCPC_DEBUG
  1693.                 logMsg ("The lease has expired. Entering INIT state.n",
  1694.                         0, 0, 0, 0, 0, 0);
  1695. #endif
  1696.                 if (pLeaseData->prevState == INIT_REBOOT)
  1697.                     pLeaseData->prevState = REBOOTING;
  1698.                 else if (pLeaseData->prevState == VERIFY);
  1699.                     pLeaseData->prevState = VERIFYING;
  1700.                 pLeaseData->currState = INIT;
  1701.                 }
  1702.             else 
  1703.                 {
  1704. #ifdef DHCPC_DEBUG
  1705.                 logMsg ("Entering BOUND state.n", 0, 0, 0, 0, 0, 0);
  1706. #endif
  1707.                 /*
  1708.                  * Send an ARP reply to update the ARP cache on other hosts 
  1709.                  * if the assigned IP address was applied to the underlying 
  1710.                  * network interface.
  1711.                  */
  1712.                 if (pLeaseData->autoConfig ||
  1713.                         pLeaseData->leaseType == DHCP_AUTOMATIC)
  1714.                     arp_reply (&pLeaseData->dhcpcParam->yiaddr,
  1715.                                &pLeaseData->ifData);
  1716.                 pLeaseData->prevState = VERIFYING;
  1717.                 pLeaseData->currState = BOUND;
  1718.                 }
  1719.             return (DHCPC_MORE);
  1720.             }
  1721.         else
  1722.             {
  1723.             /* Try to retransmit appropriate DHCP message for current state. */
  1724.            length = make_request (pLeaseData, pLeaseData->currState, FALSE);
  1725.            if (length < 0)
  1726.                {
  1727. #ifdef DHCPC_DEBUG
  1728.     logMsg("Unable to construct reboot/verify message. Entering INIT state.n",
  1729.            0, 0, 0, 0, 0, 0);
  1730. #endif
  1731.                 if (pLeaseData->prevState == INIT_REBOOT)
  1732.                     pLeaseData->prevState = REBOOTING;
  1733.                 else
  1734.                     pLeaseData->prevState = VERIFYING;
  1735.                 pLeaseData->currState = INIT;
  1736.                 return (DHCPC_MORE);
  1737.                 }
  1738.             gen_retransmit (pLeaseData, length);
  1739.             }
  1740.         if (timer < MAXTIMER)
  1741.             {
  1742.             /* Double retransmission delay with each attempt. (RFC 1541). */
  1743.             timer *= 2;
  1744.             }
  1745.         /* Set retransmission timer to randomized exponential backoff. */
  1746.             
  1747.         wdStart (pLeaseData->timer, sysClkRateGet() * SLEEP_RANDOM (timer),
  1748.                  (FUNCPTR)retrans_reboot_verify, (int)pLeaseData);
  1749.         pLeaseData->timeout = timer;
  1750.         pLeaseData->numRetry = retry;
  1751.         }
  1752.     else
  1753.         {
  1754.         /*
  1755.          * Process DHCP message stored in receive buffer by monitor task.
  1756.          * The 4-byte alignment of the IP header needed by Sun BSP's is
  1757.          * guaranteed by the Berkeley Packet Filter during input.
  1758.          */
  1759.         pMsgData = pLeaseData->msgBuffer;
  1760.         align_msg (&dhcpcMsgIn, pMsgData);
  1761.         /* Examine type of message. Accept DHCPACK or DHCPNAK replies. */
  1762.         option = (char *)pickup_opt (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  1763.                                      _DHCP_MSGTYPE_TAG);
  1764.         if (option == NULL)
  1765.             {
  1766.             /*
  1767.              * Message type not found -  discard untyped DHCP messages, and
  1768.              * any BOOTP replies.
  1769.              */
  1770.             return (OK);
  1771.             }
  1772.         else
  1773.             {
  1774.             msgtype = *OPTBODY (option);
  1775.             if (msgtype == DHCPNAK)
  1776.                 {
  1777. #ifdef DHCPC_DEBUG
  1778.                 logMsg ("Got DHCPNAK in reboot_verify()n", 0, 0, 0, 0, 0, 0);
  1779.                 option = (char *)pickup_opt (dhcpcMsgIn.dhcp,
  1780.                                              DHCPLEN(dhcpcMsgIn.udp),
  1781.                                              _DHCP_ERRMSG_TAG);
  1782.                 if (option != NULL &&
  1783.                     nvttostr (OPTBODY (option), errmsg,
  1784.                               (int)DHCPOPTLEN (option)) == 0)
  1785.                     logMsg ("DHCPNAK contains the error message "%s"n",
  1786.                              (int)errmsg, 0, 0, 0, 0, 0);
  1787. #endif
  1788.                 clean_param (pLeaseData->dhcpcParam);
  1789.                 free (pLeaseData->dhcpcParam);
  1790.                 pLeaseData->dhcpcParam = NULL;
  1791.                 if (pLeaseData->prevState == INIT_REBOOT)
  1792.                     pLeaseData->prevState = REBOOTING;
  1793.                 else if (pLeaseData->prevState == VERIFY);
  1794.                     pLeaseData->prevState = VERIFYING;
  1795.                 pLeaseData->currState = INIT;
  1796.                 return (DHCPC_MORE);
  1797.                 }
  1798.             else if (msgtype == DHCPACK)
  1799.                 {
  1800.                 /* Fill in host requirements defaults. */
  1801.                 dhcpcDefaultsSet (&tmpparam);
  1802.                 if (dhcp_msgtoparam (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  1803.                                      &tmpparam) == OK)
  1804.                     {
  1805.                     if ( (arpans = arp_check (&tmpparam.yiaddr, 
  1806.                                                   &pLeaseData->ifData)) == OK)
  1807.                         {
  1808.                         merge_param (pLeaseData->dhcpcParam, &tmpparam);
  1809.                         *(pLeaseData->dhcpcParam) = tmpparam;
  1810.                         pLeaseData->dhcpcParam->lease_origin =
  1811.                             pLeaseData->initEpoch;
  1812. #ifdef DHCPC_DEBUG
  1813.                         inet_ntoa_b (pLeaseData->dhcpcParam->yiaddr, newAddr);
  1814.                         logMsg ("Got DHCPACK (IP = %s, duration = %d secs)n",
  1815.                                 (int)newAddr,
  1816.                                 pLeaseData->dhcpcParam->lease_duration,
  1817.                                 0, 0, 0, 0);
  1818. #endif
  1819.                         /*
  1820.                          * Send an ARP reply to update the ARP cache on other
  1821.                          * hosts if the assigned IP address was applied to
  1822.                          * the underlying network interface.
  1823.                          */
  1824.                         if (pLeaseData->autoConfig ||
  1825.                                 pLeaseData->leaseType == DHCP_AUTOMATIC)
  1826.                             arp_reply (&pLeaseData->dhcpcParam->yiaddr,
  1827.                                        &pLeaseData->ifData);
  1828.                         pLeaseData->currState = BOUND;
  1829.                         status = 0;
  1830.                         /* Use retrieved configuration parameters. */
  1831.                         if (pLeaseData->prevState == INIT_REBOOT ||
  1832.                                 pLeaseData->prevState == REBOOTING)
  1833.                             {
  1834.                             status = use_parameter (pLeaseData->dhcpcParam,
  1835.                                                     pLeaseData);
  1836.                             if (status != 0)
  1837.                                 {
  1838. #ifdef DHCPC_DEBUG
  1839.                          logMsg ("Error configuring network. Shutting down.n",
  1840.                                  0, 0, 0, 0, 0, 0);
  1841. #endif
  1842.                                 release (pLeaseData, FALSE);
  1843.                                 semTake (dhcpcMutexSem, WAIT_FOREVER);
  1844.                                 pLeaseData->leaseGood = FALSE;
  1845.                                 semGive (dhcpcMutexSem);
  1846.                                 }
  1847.                             else
  1848.                                 {
  1849.                                 semTake (dhcpcMutexSem, WAIT_FOREVER);
  1850.                                 pLeaseData->leaseGood = TRUE;
  1851.                                 semGive (dhcpcMutexSem);
  1852.                                 }
  1853.                             pLeaseData->prevState = REBOOTING;
  1854.                             }
  1855.                         else
  1856.                             {
  1857.                             /*
  1858.                              * Send an ARP reply to update the ARP cache on 
  1859.                              * other hosts if the assigned IP address was
  1860.                              * applied to the underlying network interface.
  1861.                              */
  1862.                             if (pLeaseData->autoConfig ||
  1863.                                     pLeaseData->leaseType == DHCP_AUTOMATIC)
  1864.                                 arp_reply (&pLeaseData->dhcpcParam->yiaddr,
  1865.                                            &pLeaseData->ifData);
  1866.                             pLeaseData->prevState = VERIFYING;
  1867.                             }
  1868.                         if (status == 0)
  1869.                             return (DHCPC_MORE);
  1870.                         else
  1871.                             return (ERROR);
  1872.                         }
  1873.                     }
  1874.                 }
  1875.             /* Unknown message type or invalid parameters - send DHCPDECLINE */
  1876.             set_declinfo (&tmp_reqspec, pLeaseData, errmsg, arpans);
  1877.             dhcp_decline (&tmp_reqspec, &pLeaseData->ifData);
  1878.             clean_param (pLeaseData->dhcpcParam);
  1879.             free (pLeaseData->dhcpcParam);
  1880.             pLeaseData->dhcpcParam = NULL;
  1881. #ifdef DHCPC_DEBUG
  1882.             logMsg ("Received unacceptable DHCPACK. Entering INIT state.n",
  1883.                     0, 0, 0, 0, 0, 0);
  1884. #endif
  1885.             if (pLeaseData->prevState == INIT_REBOOT)
  1886.                 pLeaseData->prevState = REBOOTING;
  1887.             else if (pLeaseData->prevState == VERIFY);
  1888.                 pLeaseData->prevState = VERIFYING;
  1889.             pLeaseData->currState = INIT;
  1890.             return (DHCPC_MORE);
  1891.             }    /* End of processing for typed DHCP message. */
  1892.         }     /* End of DHCP message processing. */
  1893.     return (OK);
  1894.     }