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

VxWorks

开发平台:

C/C++

  1. /* dhcpcState1.c - DHCP client runtime state machine (lease acquisition) */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01r,25apr02,wap  Only do arp_check() once so DHCPDECLINE messages are sent
  8.                  (SPR #76315)
  9. 01q,23apr02,wap  use dhcpTime() instead of time() (SPR #68900)
  10. 01p,05nov01,wap  Fix memory leak in selecting() (SPR #68981)
  11. 01o,12oct01,rae  merge from truestack (modhist update)
  12.                  note: SPRs 29555 30344 fixed here
  13. 01n,24oct00,spm  fixed modification history after tor3_x merge
  14. 01m,23oct00,niq  merged from version 01p of tor3_x branch (base version 01l);
  15.                  upgrade to BPF replaces tagged frame support
  16. 01l,04dec97,spm  added code review modifications
  17. 01k,06oct97,spm  removed reference to deleted endDriver global
  18. 01j,02sep97,spm  moved data retrieval to prevent dereferenced NULL (SPR #9243);
  19.                  removed excess IMPORT statement
  20. 01i,26aug97,spm  major overhaul: reorganized code and changed user interface
  21.                  to support multiple leases at runtime
  22. 01h,06aug97,spm  removed parameters linked list to reduce memory required
  23. 01g,10jun97,spm  isolated incoming messages in state machine from input hooks
  24. 01f,02jun97,spm  changed DHCP option tags to prevent name conflicts (SPR #8667)
  25. 01e,06may97,spm  changed memory access to align IP header on four byte boundary
  26. 01d,28apr97,spm  corrected placement of conditional include to prevent failure
  27. 01c,18apr97,spm  added conditional include DHCPC_DEBUG for displayed output
  28. 01b,07apr97,spm  added code to use Host Requirements defaults, rewrote docs
  29. 01a,27jan97,spm  extracted from dhcpc.c to reduce object size
  30. */
  31. /*
  32. DESCRIPTION
  33. This library contains a portion of the finite state machine for the WIDE 
  34. project DHCP client, modified for vxWorks compatibility.
  35. INTERNAL
  36. This module contains the functions used prior to the BOUND state. It was
  37. created to isolate those functions and reduce the size of the boot ROM image 
  38. so that the DHCP client could be used with targets like the MV147 which have 
  39. limited ROM capacity. When executing at boot time, the DHCP client's state
  40. machine only used the states defined in this module. After the initial port 
  41. was completed, the WIDE project implementation was greatly modified to allow 
  42. the DHCP client library to establish and maintain multiple leases unassociated 
  43. with the network interface used for message transfer. That capability is
  44. completely unnecessary for the boot time client, so it no longer shares any 
  45. code with 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 "rngLib.h"
  105. #include "wdLib.h"
  106. #include "time.h"
  107. #include "inetLib.h"
  108. #include "logLib.h"
  109. #include "taskLib.h"
  110. #include "sysLib.h"
  111. #include "vxLib.h"
  112. #include "netLib.h"
  113. #include "dhcp/dhcpcStateLib.h"
  114. #include "dhcp/dhcpcInternal.h"
  115. #include "dhcp/dhcpcCommonLib.h"
  116. /* defines */
  117. /* Retransmission delay is timer value plus/minus one second (RFC 1541). */
  118. #define SLEEP_RANDOM(timer) ( (timer - 1) + (rand () % 2) )
  119. #define REQUEST_RETRANS   4  /* Max number of retransmissions (RFC 1541). */
  120. /* globals */
  121. IMPORT int  dhcpcMinLease;  /* Minimum accepted lease length. */
  122. IMPORT SEM_ID  dhcpcMutexSem; /* Protects status indicator */
  123.  
  124. unsigned char dhcpCookie [MAGIC_LEN] = RFC1048_MAGIC;
  125. struct buffer sbuf;
  126. int (*fsm [MAX_STATES]) ();
  127. int (*handle_param [MAXTAGNUM]) () = 
  128.     {
  129.     NULL,           /* PAD */
  130.     handle_ip,      /* SUBNET_MASK */
  131.     handle_num,     /* TIME_OFFSET */
  132.     handle_ips,     /* ROUTER */
  133.     handle_ips,     /* TIME_SERVER */
  134.     handle_ips,     /* NAME_SERVER */
  135.     handle_ips,     /* DNS_SERVER */
  136.     handle_ips,     /* LOG_SERVER */
  137.     handle_ips,     /* COOKIE_SERVER */
  138.     handle_ips,     /* LPR_SERVER */
  139.     handle_ips,     /* IMPRESS_SERVER */
  140.     handle_ips,     /* RLS_SERVER */
  141.     handle_str,     /* HOSTNAME */
  142.     handle_num,     /* BOOTSIZE */
  143.     handle_str,     /* MERIT_DUMP */
  144.     handle_str,     /* DNS_DOMAIN */
  145.     handle_ip,      /* SWAP_SERVER */
  146.     handle_str,     /* ROOT_PATH */
  147.     handle_str,     /* EXTENSIONS_PATH */
  148.     handle_bool,    /* IP_FORWARD */
  149.     handle_bool,    /* NONLOCAL_SRCROUTE */
  150.     handle_ippairs, /* POLICY_FILTER */
  151.     handle_num,     /* MAX_DGRAM_SIZE */
  152.     handle_num,     /* DEFAULT_IP_TTL */
  153.     handle_num,     /* MTU_AGING_TIMEOUT */
  154.     handle_nums,    /* MTU_PLATEAU_TABLE */
  155.     handle_num,     /* IF_MTU */
  156.     handle_bool,    /* ALL_SUBNET_LOCAL */
  157.     handle_ip,      /* BRDCAST_ADDR */
  158.     handle_bool,    /* MASK_DISCOVER */
  159.     handle_bool,    /* MASK_SUPPLIER */
  160.     handle_bool,    /* ROUTER_DISCOVER */
  161.     handle_ip,      /* ROUTER_SOLICIT */
  162.     handle_ippairs, /* STATIC_ROUTE */
  163.     handle_bool,    /* TRAILER */
  164.     handle_num,     /* ARP_CACHE_TIMEOUT */
  165.     handle_bool,    /* ETHER_ENCAP */
  166.     handle_num,     /* DEFAULT_TCP_TTL */
  167.     handle_num,     /* KEEPALIVE_INTER */
  168.     handle_bool,    /* KEEPALIVE_GARBA */
  169.     handle_str,     /* NIS_DOMAIN */
  170.     handle_ips,     /* NIS_SERVER */
  171.     handle_ips,     /* NTP_SERVER */
  172.     handle_list,    /* VENDOR_SPEC */
  173.     handle_ips,     /* NBN_SERVER */
  174.     handle_ips,     /* NBDD_SERVER */
  175.     handle_num,     /* NB_NODETYPE */
  176.     handle_str,     /* NB_SCOPE */
  177.     handle_ips,     /* XFONT_SERVER */
  178.     handle_ips,     /* XDISPLAY_MANAGER */
  179.     NULL,           /* REQUEST_IPADDR */
  180.     handle_num,     /* LEASE_TIME */
  181.     NULL,           /* OPT_OVERLOAD */
  182.     NULL,           /* DHCP_MSGTYPE */
  183.     handle_ip,      /* SERVER_ID */
  184.     NULL,           /* REQ_LIST */
  185.     handle_str,     /* DHCP_ERRMSG */
  186.     NULL,           /* DHCP_MAXMSGSIZE */
  187.     handle_num,     /* DHCP_T1 */
  188.     handle_num,     /* DHCP_T2  */
  189.     NULL,           /* CLASS_ID */
  190.     NULL,           /* CLIENT_ID */
  191.     NULL,
  192.     NULL,
  193.     handle_str,     /* NISP_DOMAIN */
  194.     handle_ips,     /* NISP_SERVER */
  195.     handle_str,     /* TFTP_SERVERNAME */
  196.     handle_str,     /* BOOTFILE */
  197.     handle_ips,     /* MOBILEIP_HA */
  198.     handle_ips,     /* SMTP_SERVER */
  199.     handle_ips,     /* POP3_SERVER */
  200.     handle_ips,     /* NNTP_SERVER */
  201.     handle_ips,     /* DFLT_WWW_SERVER */
  202.     handle_ips,     /* DFLT_FINGER_SERVER */
  203.     handle_ips,     /* DFLT_IRC_SERVER */
  204.     handle_ips,     /* STREETTALK_SERVER */
  205.     handle_ips      /* STDA_SERVER */
  206.     };
  207. /*******************************************************************************
  208. *
  209. * gen_retransmit - generic retransmission after timeout
  210. *
  211. * This routine retransmits the current DHCP client message (a discover or
  212. * a request message) after the appropriate timeout interval expires.
  213. * It is called from multiple locations in the finite state machine.
  214. *
  215. * RETURNS: 0 if transmission completed, or negative value on error.
  216. *
  217. * ERRNO: N/A
  218. *
  219. * NOMANUAL
  220. */
  221. int gen_retransmit
  222.     (
  223.     LEASE_DATA *  pLeaseData,  /* lease-specific data structures */
  224.     int  length  /* length of DHCP message */
  225.     )
  226.     {
  227.     time_t curr_epoch = 0;
  228.     struct ifnet *  pIf;  /* interface used for retransmission */
  229.     struct sockaddr_in  dest;
  230.     BOOL bcastFlag;
  231.     pIf = pLeaseData->ifData.iface;
  232.     if (dhcpTime (&curr_epoch) == -1)
  233.         return (-1);
  234.     /* Update the appropriate fields in the current DHCP message. */
  235.     if (pLeaseData->currState != REQUESTING)
  236.         dhcpcMsgOut.dhcp->secs = htons (curr_epoch - pLeaseData->initEpoch);
  237.     dhcpcMsgOut.udp->uh_sum = 0;
  238.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp, 
  239.                                          ntohs (spudph.ulen));
  240.     /*
  241.      * Retransmit the message. Set the flag to use a link-level broadcast
  242.      * address if needed (prevents ARP messages if using Ethernet devices).
  243.      */
  244.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  245.     dest.sin_len = sizeof (struct sockaddr_in);
  246.     dest.sin_family = AF_INET;
  247.     dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  248.     if (dest.sin_addr.s_addr == 0xffffffff)
  249.         bcastFlag = TRUE;
  250.     else
  251.         bcastFlag = FALSE;
  252.     pIf = pLeaseData->ifData.iface;
  253.     if (dhcpSend (pIf, &dest, sbuf.buf, length, bcastFlag) == ERROR)
  254.         return (-2);
  255.     return(0);
  256.     }
  257. /*******************************************************************************
  258. *
  259. * retrans_wait_offer - signal reception interval for initial offer expires
  260. *
  261. * This routine sends a timeout notification to the client monitor task when
  262. * the interval for receiving an initial lease offer expires. It is called at 
  263. * interrupt level by a watchdog timer. The monitor task will eventually execute
  264. * the WAIT_OFFER state to process the timeout event and retransmit the
  265. * DHCP discover message.
  266. *
  267. * RETURNS: N/A
  268. *
  269. * ERRNO: N/A
  270. *
  271. * NOMANUAL
  272. */
  273. void retrans_wait_offer
  274.     (
  275.     LEASE_DATA *  pLeaseData  /* lease-specific status information */
  276.     )
  277.     { 
  278.     /* 
  279.      * Ignore the timeout if a state transition occurred during 
  280.      * the scheduled timer interval.
  281.      */
  282.     if (pLeaseData->currState != WAIT_OFFER)
  283.         return;
  284.     /* Construct and send a timeout message to the lease monitor task. */
  285.     dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, pLeaseData, TRUE);
  286.     return;
  287.     }
  288. /*******************************************************************************
  289. *
  290. * alarm_selecting - signal when collection time expires 
  291. *
  292. * This routine sends a timeout notification to the client monitor task so
  293. * that the corresponding lease will stop collecting DHCP offers. It is called 
  294. * at interrupt level by a watchdog timer. The monitor task will eventually 
  295. * advance the lease from the SELECTING to the REQUESTING state.
  296. *
  297. * RETURNS: N/A
  298. *
  299. * ERRNO: N/A
  300. *
  301. * NOMANUAL
  302. */
  303. void alarm_selecting
  304.     (
  305.     LEASE_DATA *  pLeaseData  /* lease-specific status information */
  306.     )
  307.     {
  308.     STATUS result;
  309.     /* 
  310.      * Ignore the timeout if a state transition occurred during 
  311.      * the scheduled timer interval.
  312.      */
  313.     if (pLeaseData->currState != SELECTING)
  314.         return;
  315.     /* Construct and send a timeout message to the lease monitor task. */
  316.     result = dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, pLeaseData, TRUE);
  317. #ifdef DHCPC_DEBUG
  318.     if (result == ERROR)
  319.         logMsg ("Warning: couldn't add timeout event for SELECTING state.n", 
  320.                 0, 0, 0, 0, 0, 0);
  321. #endif
  322.     return;
  323.     }
  324. /*******************************************************************************
  325. *
  326. * retrans_requesting - signal when reception interval for initial reply expires
  327. *
  328. * This routine sends a timeout notification to the client monitor task when
  329. * the interval for receiving a server reply to a lease request expires. It
  330. * is called at interrupt level by a watchdog timer. The monitor task will 
  331. * eventually execute the REQUESTING state to process the timeout event and 
  332. * retransmit the DHCP request message.
  333. *
  334. * RETURNS: N/A
  335. *
  336. * ERRNO: N/A
  337. *
  338. * NOMANUAL
  339. */
  340. void retrans_requesting
  341.     (
  342.     LEASE_DATA *  pLeaseData  /* lease-specific status information */
  343.     )
  344.     {
  345.     /* 
  346.      * Ignore the timeout if a state transition occurred during 
  347.      * the scheduled timer interval.
  348.      */
  349.     if (pLeaseData->currState != REQUESTING)
  350.         return;
  351.     /* Construct and send a timeout message to the lease monitor task. */
  352.     dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, pLeaseData, TRUE);
  353. #ifdef DHCPC_DEBUG
  354.     logMsg ("retransmit DHCPREQUEST(REQUESTING)n", 0, 0, 0, 0, 0, 0);
  355. #endif
  356.     return;
  357.     }
  358. /*******************************************************************************
  359. *
  360. * inform - external configuration state of client finite state machine
  361. *
  362. * This routine begins the inform message process, which obtains additional
  363. * parameters for a host configured with an external address. This processing
  364. * is isolated from the normal progression through the state machine. Like the
  365. * DHCP discover message, the inform message is the first transmission. 
  366. * However, the only valid response is an acknowledgement by a server. As a
  367. * result, the process is a hybrid between the implementations of the initial
  368. * state and the requesting state which finalizes the lease establishment.
  369. *
  370. * The routine implements the initial state of the finite state machine for an
  371. * externally assigned IP address. It is invoked by the event handler of the
  372. * client monitor task, and should only be called internally.
  373. *
  374. * RETURNS: OK (processing completes), DHCPC_DONE (remove lease), or ERROR.
  375. *
  376. * ERRNO: N/A
  377. *
  378. * NOMANUAL
  379. */
  380. int inform
  381.     (
  382.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  383.     )
  384.     {
  385.     LEASE_DATA *  pLeaseData = NULL;
  386.     struct sockaddr_in  dest;
  387.     struct ifnet *  pIf;
  388.     int  length;  /* Amount of data in message */
  389.     if (pEvent->source == DHCP_AUTO_EVENT)
  390.         {
  391.         /*
  392.          * Received DHCP messages or timeouts can only reach this
  393.          * routine when repeating the DHCP INFORM message exchange.
  394.          * Ignore these stale notifications.
  395.          */
  396.          return (OK);
  397.          }
  398.     bzero (sbuf.buf, sbuf.size);
  399. #ifdef DHCPC_DEBUG
  400.     logMsg ("dhcpc: Entered INFORM state.n", 0, 0, 0, 0, 0, 0);
  401. #endif
  402.     /*
  403.      * Use the cookie to access the lease-specific data structures. For now,
  404.      * just typecast the cookie. This translation could be replaced with a more
  405.      * sophisticated lookup at some point.
  406.      */
  407.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  408.     wdCancel (pLeaseData->timer);    /* Reset watchdog timer. */
  409.     /*
  410.      * The DHCP_USER_RELEASE event occurs in response to the dhcpcRelease()
  411.      * or dhcpcShutdown() call. Remove all data structures for this lease.
  412.      */
  413.     if (pEvent->type == DHCP_USER_RELEASE)
  414.         {
  415.         dhcpcLeaseCleanup (pLeaseData);
  416.         return (DHCPC_DONE);
  417.         }
  418.     /*
  419.      * Set lease to generate newer RFC 2131 messages. Older servers might
  420.      * ignore messages if their length is less than the minimum length
  421.      * obtained with a fixed options field, but will not recognize an
  422.      * inform message anyway.
  423.      */
  424.  
  425.     pLeaseData->oldFlag = FALSE;
  426.     /* Create DHCP INFORM message and assign new transaction ID. */
  427.     length = make_request (pLeaseData, INFORMING, TRUE);
  428.     if (length < 0)
  429.         {
  430. #ifdef DHCPC_DEBUG
  431.         logMsg ("Error making DHCP inform message. Can't continue.n",
  432.                 0, 0, 0, 0, 0, 0);
  433. #endif
  434.         return (ERROR);
  435.         }
  436.     dhcpcMsgOut.dhcp->secs = 0;
  437.     dhcpcMsgOut.udp->uh_sum = 0;
  438.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp,
  439.                                          ntohs (spudph.ulen));
  440. #ifdef DHCPC_DEBUG
  441.     logMsg ("Sending DHCPINFORM.n", 0, 0, 0, 0, 0, 0);
  442. #endif
  443.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  444.     dest.sin_len = sizeof (struct sockaddr_in);
  445.     dest.sin_family = AF_INET;
  446.     dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  447.     pIf = pLeaseData->ifData.iface;
  448.  
  449.     if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  450.         {
  451. #ifdef DHCPC_DEBUG
  452.         logMsg ("Can't send DHCPINFORM.n", 0, 0, 0, 0, 0, 0);
  453. #endif
  454.         return (ERROR);
  455.         }
  456.     /* Set lease data to execute next state and start retransmission timer. */
  457.     pLeaseData->prevState = INFORMING;
  458.     pLeaseData->currState = REQUESTING;
  459.     pLeaseData->timeout = FIRSTTIMER;
  460.     pLeaseData->numRetry = 0;
  461.     wdStart (pLeaseData->timer, sysClkRateGet() *
  462.                                 SLEEP_RANDOM (pLeaseData->timeout),
  463.              (FUNCPTR)retrans_requesting, (int)pLeaseData);
  464.     return (OK);    /* Next state is REQUESTING */
  465.     }
  466. /*******************************************************************************
  467. *
  468. * init - initial state of client finite state machine
  469. *
  470. * This routine implements the initial state of the finite state machine. 
  471. * After a random backoff delay, it resets the network interface if necessary
  472. * and transmits the DHCP discover message. This state may be repeated after a 
  473. * later state if a lease is not renewed or a recoverable error occurs. It 
  474. * could also be executed following unrecoverable errors. The routine is 
  475. * invoked by the event handler of the client monitor task, and should only be 
  476. * called internally.
  477. *
  478. * RETURNS: OK (processing completes), DHCPC_DONE (remove lease), or ERROR.
  479. *
  480. * ERRNO: N/A
  481. *
  482. * NOMANUAL
  483. */
  484. int init
  485.     (
  486.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  487.     )
  488.     {
  489.     LEASE_DATA *  pLeaseData = NULL;
  490.     STATUS  result;
  491.     struct sockaddr_in  dest;
  492.     struct ifnet *  pIf;
  493.     int  length;
  494.     bzero (sbuf.buf, sbuf.size);
  495. #ifdef DHCPC_DEBUG
  496.     logMsg ("dhcpc: Entered INIT state.n", 0, 0, 0, 0, 0, 0);
  497. #endif
  498.     /*
  499.      * Use the cookie to access the lease-specific data structures. For now,
  500.      * just typecast the cookie. This translation could be replaced with a more
  501.      * sophisticated lookup at some point.
  502.      */
  503.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  504.     wdCancel (pLeaseData->timer);    /* Reset watchdog timer. */
  505.     /*
  506.      * The DHCP_USER_RELEASE event occurs in response to the dhcpcRelease()
  507.      * or dhcpcShutdown() call. Remove all data structures for this lease.
  508.      */
  509.     if (pEvent->type == DHCP_USER_RELEASE)
  510.         {
  511.         dhcpcLeaseCleanup (pLeaseData);
  512.         return (DHCPC_DONE);
  513.         }
  514.  
  515.     /* 
  516.      * Unrecoverable errors are only removed when the dhcpcBind() call sets
  517.      * the state indicators to INIT_REBOOT. Ignore all other events until then.
  518.      */
  519.     if (pLeaseData->prevState == DHCPC_ERROR)
  520.         return (OK);
  521.    
  522.     semTake (dhcpcMutexSem, WAIT_FOREVER);    /* Reset status indicator. */
  523.     pLeaseData->leaseGood = FALSE;
  524.     semGive (dhcpcMutexSem);
  525.     /*
  526.      * Set lease to generate newer RFC 2131 messages initially. The client
  527.      * will revert to the older message format if it does not receive a
  528.      * response to the initial set of discover messages. Older servers might
  529.      * ignore messages less than the minimum length obtained with a fixed
  530.      * options field. The older format pads the field to reach that length.
  531.      */
  532.     pLeaseData->oldFlag = FALSE;
  533.     /* Create DHCP_DISCOVER message and assign new transaction ID. */
  534.     length = make_discover (pLeaseData, TRUE);
  535.     /* 
  536.      * Random delay from one to ten seconds to avoid startup congestion.
  537.      * (Delay length specified in RFC 1541).
  538.      *
  539.      */
  540.     taskDelay (sysClkRateGet () * (1 + (rand () % INIT_WAITING)) );
  541.     /* 
  542.      * If an event notification hook is present, send a notification of
  543.      * the lease expiration when appropriate. (None is needed after a reboot).
  544.      */
  545.      
  546.     if (pLeaseData->eventHookRtn != NULL)
  547.         {
  548.         if (pLeaseData->prevState != REBOOTING && 
  549.                 pLeaseData->prevState != INIT_REBOOT)
  550.             result = (* pLeaseData->eventHookRtn) (DHCPC_LEASE_INVALID, 
  551.                                                    pEvent->leaseId);
  552.         }
  553.     /* 
  554.      * Reset the network interface if it used the address
  555.      * information provided by the indicated lease.
  556.      */
  557.     if (pLeaseData->autoConfig || pLeaseData->leaseType == DHCP_AUTOMATIC)
  558.         {
  559.         reset_if (&pLeaseData->ifData);
  560.         }
  561.     dhcpcMsgOut.dhcp->secs = 0;
  562.     dhcpcMsgOut.udp->uh_sum = 0;
  563.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp,
  564.                                          ntohs (spudph.ulen));
  565.     if (dhcpTime (&pLeaseData->initEpoch) == -1) 
  566.         {
  567. #ifdef DHCPC_DEBUG
  568.         logMsg ("time() error setting initEpochn", 0, 0, 0, 0, 0, 0);
  569. #endif
  570.         return (ERROR);
  571.         }
  572. #ifdef DHCPC_DEBUG
  573.     logMsg ("Sending DHCPDISCOVERn", 0, 0, 0, 0, 0, 0);
  574. #endif
  575.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  576.     dest.sin_len = sizeof (struct sockaddr_in);
  577.     dest.sin_family = AF_INET;
  578.     dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  579.     pIf = pLeaseData->ifData.iface; 
  580.     if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  581.         {
  582. #ifdef DHCPC_DEBUG
  583.         logMsg ("Can't send DHCPDISCOVERn", 0, 0, 0, 0, 0, 0);
  584. #endif
  585.         return (ERROR);
  586.         }
  587.     /* Set lease data to execute next state and start retransmission timer. */
  588.     pLeaseData->prevState = INIT;
  589.     pLeaseData->currState = WAIT_OFFER;
  590.     pLeaseData->timeout = FIRSTTIMER;
  591.     pLeaseData->numRetry = 0;
  592.     wdStart (pLeaseData->timer, sysClkRateGet() *
  593.                                 SLEEP_RANDOM (pLeaseData->timeout),
  594.              (FUNCPTR)retrans_wait_offer, (int)pLeaseData);
  595.     return (OK);    /* Next state is WAIT_OFFER */
  596.     }
  597. /*******************************************************************************
  598. *
  599. * wait_offer - Initial offering state of client finite state machine
  600. *
  601. * This routine contains the initial part of the second state of the finite 
  602. * state machine. It handles all processing until an acceptable DHCP offer is 
  603. * received. If a timeout occurred, it retransmits the DHCP discover message. 
  604. * Otherwise, it evaluates the parameters contained in the received DHCP offer. 
  605. * If the minimum requirements are met, processing will continue with the 
  606. * selecting() routine. If no offer is received before the retransmission
  607. * limit is reached, the negotiation process fails.
  608. * .IP
  609. * This routine is invoked by the event handler of the client monitor task, 
  610. * and should only be called internally. Any user requests generated by 
  611. * incorrect calls or delayed responses to the dhcpcBind() and dhcpcVerify()
  612. * routines are ignored.
  613. *
  614. * RETURNS: OK (processing completes), DHCPC_DONE (remove lease), or ERROR.
  615. *
  616. * ERRNO: N/A
  617. *
  618. * NOMANUAL
  619. */
  620. int wait_offer
  621.     (
  622.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  623.     )
  624.     {
  625.     char errmsg [255];
  626.     char *  option;
  627.     int timer = 0;
  628.     int retry = 0;
  629.     struct dhcp_param * pParams = NULL;
  630.     LEASE_DATA *  pLeaseData = NULL;
  631.     char *  pMsgData;
  632.     int  length;
  633.     /*
  634.      * Use the cookie to access the lease-specific data structures. For now,
  635.      * just typecast the cookie. This translation could be replaced with a more
  636.      * sophisticated lookup at some point.
  637.      */
  638.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  639.     /*
  640.      * The DHCP_USER_RELEASE event occurs in response to the dhcpcRelease()
  641.      * or dhcpcShutdown() call. Remove all data structures for this lease.
  642.      */
  643.     if (pEvent->type == DHCP_USER_RELEASE)
  644.         {
  645.         dhcpcLeaseCleanup (pLeaseData);
  646.         return (DHCPC_DONE);
  647.         }
  648.     /* Ignore bind and verify user events, which are meaningless here. */
  649.     if (pEvent->source == DHCP_USER_EVENT)
  650.         return (OK);
  651.     bzero (errmsg, sizeof (errmsg));
  652. #ifdef DHCPC_DEBUG
  653.     logMsg ("dhcpc: Entered WAIT_OFFER state.n", 0, 0, 0, 0, 0, 0);
  654. #endif
  655.     if (pLeaseData->prevState == INIT) 
  656.         {
  657.         /* Clear any previous parameter settings. */
  658.         if (pLeaseData->dhcpcParam != NULL)
  659.             {
  660.             clean_param (pLeaseData->dhcpcParam);
  661.             free (pLeaseData->dhcpcParam);
  662.             pLeaseData->dhcpcParam = NULL;
  663.             }
  664.         pLeaseData->prevState = WAIT_OFFER;
  665.         }
  666.     if (pEvent->type == DHCP_TIMEOUT)
  667.         {
  668. #ifdef DHCPC_DEBUG
  669.         logMsg ("dhcp: timed out in WAIT_OFFER state.n", 0, 0, 0, 0, 0, 0);
  670. #endif
  671.         /* Handle timeout - no DHCP offers received yet. */
  672.         retry = pLeaseData->numRetry;
  673.         timer = pLeaseData->timeout;
  674.         retry++;
  675.         if (retry == DISCOVER_RETRANS)    /* Retransmission limit reached. */
  676.             {
  677. #ifdef DHCPC_DEBUG
  678.             logMsg ("No lease offers received by client.n", 0, 0, 0, 0, 0, 0);
  679. #endif
  680.             /*
  681.              * No response to new DHCP message format, which can be ignored
  682.              * by older DHCP servers as too short. Try the earlier format,
  683.              * which padded the options field to a minimum length. If
  684.              * successful, all subsequent messages will add that padding.
  685.              */
  686.             if (!pLeaseData->oldFlag)
  687.                 {
  688.                 pLeaseData->oldFlag = TRUE;
  689.                 timer = FIRSTTIMER / 2;     /* Counteract later doubling. */
  690.                 retry = 0;
  691.                 }
  692.             else
  693.                 return (ERROR);
  694.             }
  695.         /* Try to retransmit appropriate DHCP message for current state. */
  696.         /* Recreate DHCP_DISCOVER message using the same transaction ID. */
  697.         length = make_discover (pLeaseData, FALSE);
  698.         gen_retransmit (pLeaseData, length);
  699.         if (timer < MAXTIMER)
  700.             {
  701.             /* Double retransmission delay with each attempt. (RFC 1541). */
  702.             timer *= 2;
  703.             }
  704.         /* Set retransmission timer to randomized exponential backoff. */
  705.         wdStart (pLeaseData->timer, sysClkRateGet() * SLEEP_RANDOM (timer),
  706.                  (FUNCPTR)retrans_wait_offer, (int)pLeaseData);
  707.         pLeaseData->timeout = timer;
  708.         pLeaseData->numRetry = retry;
  709.         }
  710.     else
  711.         {
  712.         /*
  713.          * Process DHCP message stored in receive buffer by monitor task. 
  714.          * The 4-byte alignment of the IP header needed by Sun BSP's is
  715.          * guaranteed by the Berkeley Packet Filter during input.
  716.          */
  717.         pMsgData = pLeaseData->msgBuffer;
  718.         align_msg (&dhcpcMsgIn, pMsgData);
  719.         /* Examine type of message. Accept DHCP offers or BOOTP replies. */
  720.         option = (char *)pickup_opt (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  721.                                      _DHCP_MSGTYPE_TAG);
  722.         if (option == NULL)
  723.             {
  724.             /* 
  725.              * Message type not found - check message length. Ignore
  726.              * untyped DHCP messages, but accept (shorter) BOOTP replies.
  727.              * This test might still treat (illegal) untyped DHCP messages
  728.              * like BOOTP messages if they are short enough, but that case
  729.              * can't be avoided.
  730.              */
  731.             if (DHCPLEN (dhcpcMsgIn.udp) > DFLTBOOTPLEN)
  732.                 return (OK);
  733.             }
  734.         else
  735.             {
  736.             if (*OPTBODY (option) != DHCPOFFER)
  737.                 return (OK);
  738.             }
  739.         /* Allocate memory for configuration parameters. */
  740.         pParams = (struct dhcp_param *)calloc (1, sizeof (struct dhcp_param));
  741.         if (pParams == NULL)
  742.             return (OK);
  743.         /* Fill in host requirements defaults. */
  744.         dhcpcDefaultsSet (pParams);
  745.         /* Check offered parameters. Save in lease structure if acceptable. */
  746.         if (dhcp_msgtoparam (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  747.                                  pParams) == OK)
  748.             {
  749.             /* 
  750.              * Accept static BOOTP address or verify that the
  751.              * address offered by the DHCP server is non-zero
  752.              * and check offered lease length against minimum value.
  753.              */
  754.             if ( (pParams->msgtype == DHCP_BOOTP ||
  755.                  pParams->server_id.s_addr != 0) &&
  756.                 pParams->lease_duration >= dhcpcMinLease)
  757.                 {
  758.                 /*
  759.                  * Initial offer accepted. Set lease data
  760.                  * to execute next routine and start timer.
  761.                  */
  762.                 pParams->lease_origin = pLeaseData->initEpoch;
  763.                 pLeaseData->dhcpcParam = pParams;
  764.                 pLeaseData->currState = SELECTING;
  765.                 /*
  766.                  * Reset timer from retransmission
  767.                  * interval to limit for collecting replies. 
  768.                  */
  769.                 wdCancel (pLeaseData->timer);
  770.                 wdStart (pLeaseData->timer, sysClkRateGet() * 
  771.                                             pLeaseData->leaseReqSpec.waitsecs,
  772.                          (FUNCPTR)alarm_selecting, (int)pLeaseData);
  773.                 }
  774.             else
  775.                 {
  776.                 /* 
  777.                  * Offer is insufficient. Remove stored parameters
  778.                  * and set lease data to repeat current routine. 
  779.                  */
  780.                 pLeaseData->currState = WAIT_OFFER;
  781.                 clean_param (pParams);
  782.                 free (pParams);
  783.                 }
  784.             }
  785.         else
  786.             {
  787.             /*
  788.              * Conversion unsuccessful - remove stored parameters
  789.              * and set lease data to repeat current routine.
  790.              */
  791.             pLeaseData->currState = WAIT_OFFER;
  792.             clean_param (pParams);
  793.             free (pParams);
  794.             }
  795.         }
  796.     return (OK);
  797.     }
  798. /*******************************************************************************
  799. *
  800. * selecting - Second offering state of client finite state machine
  801. *
  802. * This routine continues the second state of the finite state machine. 
  803. * It compares additional offers received from DHCP servers to the current
  804. * offer, and selects the offer which provides the longest lease. When the 
  805. * time limit specified by the DHCPC_OFFER_TIMEOUT definition passes,
  806. * processing of the selected DHCP offer will continue with the requesting() 
  807. * routine. If no DHCP offers were received, the BOOTP reply selected by the 
  808. * wait_offer() routine will be used by the lease.
  809. *
  810. * .IP
  811. * This routine is invoked by the event handler of the client monitor task,
  812. * and should only be called internally. Any user requests generated by
  813. * incorrect calls or delayed responses to the dhcpcBind() and dhcpcVerify() 
  814. * routines are ignored.
  815. *
  816. * RETURNS: OK (processing complete), DHCPC_DONE (remove lease),
  817. *          DHCPC_MORE (continue), or ERROR.
  818. *
  819. * ERRNO: N/A
  820. *
  821. * NOMANUAL
  822. */
  823. int selecting
  824.     (
  825.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  826.     )
  827.     {
  828.     struct dhcp_param *pParams = NULL;
  829.     struct sockaddr_in dest;
  830.     struct ifnet * pIf;
  831.     int status;
  832.     LEASE_DATA *  pLeaseData = NULL;
  833.     char *  pMsgData;
  834.     int  length;
  835.     char *  option;
  836. #ifdef DHCPC_DEBUG
  837.     logMsg ("dhcp: Entered SELECTING state.n", 0, 0, 0, 0, 0, 0);
  838. #endif
  839.     /*
  840.      * Use the cookie to access the lease-specific data structures. For now,
  841.      * just typecast the cookie. This translation could be replaced with a more
  842.      * sophisticated lookup at some point.
  843.      */
  844.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  845.     /*
  846.      * The DHCP_USER_RELEASE event occurs in response to the dhcpcRelease()
  847.      * or dhcpcShutdown() call. Remove all data structures for this lease.
  848.      */
  849.     if (pEvent->type == DHCP_USER_RELEASE)
  850.         {
  851.         dhcpcLeaseCleanup (pLeaseData);
  852.         return (DHCPC_DONE);
  853.         }
  854.     /* Ignore bind and verify user events, which are meaningless here. */
  855.     if (pEvent->source == DHCP_USER_EVENT)
  856.         return (OK);
  857.     if (pEvent->type == DHCP_TIMEOUT)
  858.         {
  859.         /* Collection time ended - parameters structure holds chosen offer. */
  860.         if (pLeaseData->dhcpcParam->msgtype == DHCP_BOOTP)
  861.             {
  862.             /* 
  863.              * No DHCP request is needed if a BOOTP reply is chosen. Set
  864.              * lease data to process future events with the bound() routine.
  865.              */
  866.             pLeaseData->leaseType = DHCP_BOOTP;
  867.             pLeaseData->prevState = SELECTING;
  868.             pLeaseData->currState = BOUND;
  869.             status = use_parameter (pLeaseData->dhcpcParam, pLeaseData);
  870.             semTake (dhcpcMutexSem, WAIT_FOREVER);
  871.             if (status != 0)
  872.                 {
  873. #ifdef DHCPC_DEBUG
  874.                 logMsg ("Error configuring network. Shutting down.n",
  875.                         0, 0, 0, 0, 0, 0);
  876. #endif
  877.                 pLeaseData->leaseGood = FALSE;
  878.                 }
  879.             else
  880.                 {
  881.                 pLeaseData->leaseGood = TRUE;
  882.                 }
  883.             semGive (dhcpcMutexSem);
  884.             return (OK);
  885.             }
  886.         /* 
  887.          * A DHCP offer was selected. Build and send the DHCP request using
  888.          * the original transaction ID from the discover message.
  889.          */
  890.         length = make_request (pLeaseData, REQUESTING, FALSE);
  891.         if (length < 0) 
  892.             {
  893. #ifdef DHCPC_DEBUG
  894.             logMsg ("Error making DHCP request. Entering INIT state.n", 
  895.                     0, 0, 0, 0, 0, 0);
  896. #endif
  897.             pLeaseData->prevState = SELECTING;
  898.             pLeaseData->currState = INIT;
  899.             return (DHCPC_MORE);
  900.             }
  901.         dhcpcMsgOut.udp->uh_sum = 0;
  902.         dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp, 
  903.                                              ntohs (spudph.ulen));
  904.         bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  905.         dest.sin_len = sizeof (struct sockaddr_in);
  906.         dest.sin_family = AF_INET;
  907.         dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  908.         pIf = pLeaseData->ifData.iface;
  909.         if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  910.             {
  911. #ifdef DHCPC_DEBUG
  912.             logMsg ("Can't send DHCPREQUESTn", 0, 0, 0, 0, 0, 0);
  913. #endif
  914.             pLeaseData->prevState = SELECTING;
  915.             pLeaseData->currState = INIT;
  916.             return (DHCPC_MORE);
  917.             }
  918.         /*
  919.          * DHCP request sent. Set lease data to execute next state and
  920.          * start the retransmission timer.
  921.          */
  922.         pLeaseData->prevState = SELECTING;
  923.         pLeaseData->currState = REQUESTING;
  924.         pLeaseData->timeout = FIRSTTIMER;
  925.         pLeaseData->numRetry = 0;
  926.         wdStart (pLeaseData->timer, sysClkRateGet() * 
  927.                                     SLEEP_RANDOM (pLeaseData->timeout),
  928.                  (FUNCPTR)retrans_requesting, (int)pLeaseData);
  929.         }
  930.     else
  931.         {
  932.         /*
  933.          * Process DHCP message stored in receive buffer by monitor task. 
  934.          * The 4-byte alignment of the IP header needed by Sun BSP's is
  935.          * guaranteed by the Berkeley Packet Filter during input.
  936.          */
  937.         pMsgData = pLeaseData->msgBuffer;
  938.         align_msg (&dhcpcMsgIn, pMsgData);
  939.         /* Examine type of message. Only accept DHCP offers. */
  940.         option = (char *)pickup_opt (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  941.                                      _DHCP_MSGTYPE_TAG);
  942.         if (option == NULL)
  943.             {
  944.             /*
  945.              * Message type not found -  discard untyped DHCP messages, and
  946.              * any BOOTP replies.
  947.              */
  948.             return (OK);
  949.             }
  950.         else
  951.             {
  952.             if (*OPTBODY (option) != DHCPOFFER)
  953.                 return (OK);
  954.             }
  955.         /* Allocate memory for configuration parameters. */
  956.         pParams = (struct dhcp_param *)calloc (1, sizeof (struct dhcp_param));
  957.         if (pParams == NULL)
  958.             return (OK);
  959.         /* Fill in host requirements defaults. */
  960.         dhcpcDefaultsSet (pParams);
  961.         /* Switch to offered parameters if they provide a longer DHCP lease.
  962.          *
  963.  * First, check that we can decode the parameters.
  964.          */
  965.         if ((dhcp_msgtoparam (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  966.                               pParams) == OK) &&
  967.             /* Then check that the lease time is equal to or greater than
  968.              * the minimum lease time.
  969.              */
  970.             (pParams->server_id.s_addr != 0 &&
  971.              pParams->lease_duration >= dhcpcMinLease) &&
  972.             /* Finally, take any DHCP message over BOOTP,
  973.              * or take any lease with a longer duration than
  974.              * we requested.
  975.              */
  976.              (pLeaseData->dhcpcParam->msgtype == DHCP_BOOTP ||
  977.               pParams->lease_duration > 
  978.               pLeaseData->dhcpcParam->lease_duration))
  979.             {
  980.             pParams->lease_origin = pLeaseData->initEpoch;
  981.             clean_param (pLeaseData->dhcpcParam);
  982.             free (pLeaseData->dhcpcParam);
  983.             pLeaseData->dhcpcParam = pParams;
  984.             }
  985.         else
  986.             {
  987.             clean_param (pParams);
  988.             free (pParams);
  989.             }
  990.         }
  991.     return (OK);
  992.     }
  993. /*******************************************************************************
  994. *
  995. * requesting - Lease request state of client finite state machine
  996. *
  997. * This routine implements the third state of the client finite state machine.
  998. * It handles all processing until a response to a transmitted DHCP request
  999. * message is received from the selected DHCP server or the retransmission 
  1000. * limit is reached. The DHCP request is retransmitted if a timeout occurs. 
  1001. * If the request is acknowledged, processing will continue with the bound()
  1002. * routine. If it is refused or the retransmission limit is reached, the 
  1003. * negotiation process will restart with the init() routine.
  1004. * .IP
  1005. * This routine is invoked by the event handler of the client monitor task,
  1006. * and should only be called internally. Any user requests generated by
  1007. * incorrect calls or delayed responses to the dhcpcBind() and dhcpcVerify()
  1008. * routines are ignored.
  1009. *
  1010. * RETURNS: OK (processing complete), DHCPC_DONE (remove lease),
  1011. *          DHCPC_MORE (continue), or ERROR.
  1012. *
  1013. * ERRNO: N/A
  1014. *
  1015. * NOMANUAL
  1016. */
  1017. int requesting
  1018.     (
  1019.     EVENT_DATA *  pEvent  /* pointer to event descriptor */
  1020.     )
  1021.     {
  1022.     int arpans = 0;
  1023.     char *option = NULL;
  1024.     char errmsg[255];
  1025.     int timer = 0;
  1026.     int retry = 0;
  1027.     struct dhcp_param tmpparam;
  1028.     struct dhcp_reqspec tmp_reqspec;
  1029.     int status;
  1030.     int msgtype;
  1031.     LEASE_DATA *  pLeaseData = NULL;
  1032.     char *  pMsgData;
  1033.     int  length;
  1034. #ifdef DHCPC_DEBUG
  1035.     char newAddr [INET_ADDR_LEN];
  1036.     logMsg ("dhcpc: Entering requesting state.n", 0, 0, 0, 0, 0, 0);
  1037. #endif 
  1038.     /*
  1039.      * Use the cookie to access the lease-specific data structures. For now,
  1040.      * just typecast the cookie. This translation could be replaced with a more
  1041.      * sophisticated lookup at some point.
  1042.      */
  1043.     pLeaseData = (LEASE_DATA *)pEvent->leaseId;
  1044.     /*
  1045.      * The DHCP_USER_RELEASE event occurs in response to the dhcpcRelease()
  1046.      * or dhcpcShutdown() call. Remove all data structures for this lease.
  1047.      */
  1048.     if (pEvent->type == DHCP_USER_RELEASE)
  1049.         {
  1050.         dhcpcLeaseCleanup (pLeaseData);
  1051.         return (DHCPC_DONE);
  1052.         }
  1053.     /*
  1054.      * Ignore bind, verify and inform user events,
  1055.      * which are meaningless for this state.
  1056.      */
  1057.     if (pEvent->source == DHCP_USER_EVENT)
  1058.         return (OK);
  1059.     bzero (errmsg, sizeof (errmsg));
  1060.     bzero ( (char *)&tmp_reqspec, sizeof (tmp_reqspec));
  1061.     if (pEvent->type == DHCP_TIMEOUT)
  1062.         {
  1063. #ifdef DHCPC_DEBUG
  1064.         logMsg ("Retransmission from requesting state.n", 0, 0, 0, 0, 0, 0);
  1065. #endif
  1066.         /* Handle timeout - no DHCP reply received yet. */
  1067.         retry = pLeaseData->numRetry;
  1068.         timer = pLeaseData->timeout;
  1069.         retry++;
  1070.         if (retry > REQUEST_RETRANS)    /* Retransmission limit reached. */
  1071.             {
  1072. #ifdef DHCPC_DEBUG
  1073.             logMsg ("Client can't get ACK/NAK reply from servern",
  1074.                     0, 0, 0, 0, 0, 0);
  1075. #endif
  1076.             if (pLeaseData->prevState == INFORMING)
  1077.                 {
  1078.                 /* Unable to get additional parameters. */
  1079.                 return (ERROR);
  1080.                 }
  1081.             pLeaseData->prevState = REQUESTING;
  1082.             pLeaseData->currState = INIT;
  1083.             return (DHCPC_MORE);
  1084.             }
  1085.         else
  1086.             {
  1087.             /*
  1088.              * Try to retransmit DHCP request or inform
  1089.              * message using the same transaction ID.
  1090.              */
  1091.             if (pLeaseData->prevState == INFORMING)
  1092.                 msgtype = INFORMING;
  1093.             else
  1094.                 msgtype = REQUESTING;
  1095.             length = make_request (pLeaseData, msgtype, FALSE);
  1096.             if (length < 0)
  1097.                 {
  1098. #ifdef DHCPC_DEBUG
  1099.                 logMsg ("Error making DHCP request. Can't continue.n",
  1100.                         0, 0, 0, 0, 0, 0);
  1101. #endif
  1102.                 if (pLeaseData->prevState == INFORMING)
  1103.                     {
  1104.                     /* Unable to get additional parameters. */
  1105.                     return (ERROR);
  1106.                     }
  1107.                 pLeaseData->prevState = REQUESTING;
  1108.                 pLeaseData->currState = INIT;
  1109.                 return (DHCPC_MORE);
  1110.                 }
  1111.             gen_retransmit (pLeaseData, length);
  1112.             }
  1113.         if (timer < MAXTIMER)
  1114.             {
  1115.             /* Double retransmission delay with each attempt. (RFC 1541). */
  1116.             timer *= 2;
  1117.             }
  1118.         /* Set retransmission timer to randomized exponential backoff. */
  1119.         wdStart (pLeaseData->timer, sysClkRateGet() * SLEEP_RANDOM (timer),
  1120.                  (FUNCPTR)retrans_requesting, (int)pLeaseData);
  1121.         pLeaseData->timeout = timer;
  1122.         pLeaseData->numRetry = retry;
  1123.         }
  1124.     else
  1125.         {
  1126.         bzero ( (char *)&tmpparam, sizeof (tmpparam));
  1127.         /*
  1128.          * Process DHCP message stored in receive buffer by monitor task. 
  1129.          * The 4-byte alignment of the IP header needed by Sun BSP's is
  1130.          * guaranteed by the Berkeley Packet Filter during input.
  1131.          */
  1132.         pMsgData = pLeaseData->msgBuffer;
  1133.         align_msg (&dhcpcMsgIn, pMsgData);
  1134.         /* Examine type of message. Accept DHCPACK or DHCPNAK replies. */
  1135.         option = (char *)pickup_opt (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  1136.                                      _DHCP_MSGTYPE_TAG);
  1137.         if (option == NULL)
  1138.             {
  1139.             /*
  1140.              * Message type not found -  discard untyped DHCP messages, and
  1141.              * any BOOTP replies.
  1142.              */
  1143.             return (OK);
  1144.             }
  1145.         /*
  1146.          * Message type available. Ignore unexpected values. If the client
  1147.          * does not receive a valid response within the expected interval, it
  1148.          * will timeout and retransmit the request - RFC 2131, section 3.1.5.
  1149.          */
  1150.         msgtype = *OPTBODY (option);
  1151.         if (msgtype != DHCPACK && msgtype != DHCPNAK)
  1152.             {
  1153.             return (OK);
  1154.             }
  1155.         if (msgtype == DHCPNAK)
  1156.             {
  1157. #ifdef DHCPC_DEBUG
  1158.             logMsg ("Got DHCPNAK from servern", 0, 0, 0, 0, 0, 0);
  1159.             option = (char *)pickup_opt (dhcpcMsgIn.dhcp,
  1160.                                          DHCPLEN(dhcpcMsgIn.udp),
  1161.                                          _DHCP_ERRMSG_TAG);
  1162.             if (option != NULL &&
  1163.                 nvttostr (OPTBODY (option), errmsg,
  1164.                           (int)DHCPOPTLEN (option)) == 0)
  1165.                 logMsg ("DHCPNAK contains the error message "%s"n",
  1166.                          (int)errmsg, 0, 0, 0, 0, 0);
  1167. #endif
  1168.             /* Ignore invalid responses to DHCP inform message. */
  1169.             if (pLeaseData->prevState == INFORMING)
  1170.                 return (OK);
  1171.             clean_param (pLeaseData->dhcpcParam);
  1172.             free (pLeaseData->dhcpcParam);
  1173.             pLeaseData->dhcpcParam = NULL;
  1174.             pLeaseData->prevState = REQUESTING;
  1175.             pLeaseData->currState = INIT;
  1176.             return (DHCPC_MORE);
  1177.             }
  1178.         /*
  1179.          * Got acknowledgement: fill in host requirements defaults
  1180.          * and add any parameters from message options.
  1181.          */
  1182.         dhcpcDefaultsSet (&tmpparam);
  1183.         if (dhcp_msgtoparam (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  1184.                              &tmpparam) == OK)
  1185.             {
  1186.             /* Options parsed successfully - test as needed. */
  1187.             if (pLeaseData->prevState == INFORMING)
  1188.                 {
  1189.                 /*
  1190.                  * Bypass ARP test and remaining steps after saving
  1191.                  * additional parameters.
  1192.                  */
  1193.                 merge_param (pLeaseData->dhcpcParam, &tmpparam);
  1194.                 *(pLeaseData->dhcpcParam) = tmpparam;
  1195.                 /*
  1196.                  * If an event notification hook is present, send an
  1197.                  * indication about the new set of parameters.
  1198.                  */
  1199.                 if (pLeaseData->eventHookRtn != NULL)
  1200.                     (* pLeaseData->eventHookRtn) (DHCPC_LEASE_NEW,
  1201.                                                   pEvent->leaseId);
  1202.                 /*
  1203.                  * Signal the successful completion of the message
  1204.                  * exchange if the dhcpcInformGet() call is executing
  1205.                  * synchronously.
  1206.                  */
  1207.                 if (pLeaseData->waitFlag)
  1208.                     semGive (pLeaseData->leaseSem);
  1209.                 return (OK);
  1210.                 }
  1211.             if ( (arpans = arp_check (&tmpparam.yiaddr, 
  1212.                                           &pLeaseData->ifData)) == OK)
  1213.                 {
  1214.                 merge_param (pLeaseData->dhcpcParam, &tmpparam);
  1215.                 *(pLeaseData->dhcpcParam) = tmpparam;
  1216.                 pLeaseData->dhcpcParam->lease_origin = 
  1217.                     pLeaseData->initEpoch;
  1218. #ifdef DHCPC_DEBUG
  1219.                 inet_ntoa_b (pLeaseData->dhcpcParam->yiaddr, newAddr);
  1220.                 logMsg ("Got DHCPACK (IP = %s, duration = %d secs)n",
  1221.                         (int)newAddr,
  1222.                         pLeaseData->dhcpcParam->lease_duration,
  1223.                         0, 0, 0, 0);
  1224. #endif
  1225.                 pLeaseData->prevState = REQUESTING;
  1226.                 pLeaseData->currState = BOUND;
  1227.                 /* Use retrieved configuration parameters. */ 
  1228.                 status = use_parameter (pLeaseData->dhcpcParam, 
  1229.                                         pLeaseData);
  1230.                 if (status != 0)
  1231.                     {
  1232. #ifdef DHCPC_DEBUG
  1233.                     logMsg ("Error configuring network. Shutting down.n",
  1234.                              0, 0, 0, 0, 0, 0);
  1235. #endif
  1236.                     release (pLeaseData, FALSE);
  1237.                     semTake (dhcpcMutexSem, WAIT_FOREVER);
  1238.                     pLeaseData->leaseGood = FALSE;
  1239.                     semGive (dhcpcMutexSem);
  1240.                     }
  1241.                 else
  1242.                     {
  1243.                     semTake (dhcpcMutexSem, WAIT_FOREVER);
  1244.                     pLeaseData->leaseGood = TRUE;
  1245.                     semGive (dhcpcMutexSem);
  1246.                     }
  1247.                 if (status == 0)
  1248.                     return (DHCPC_MORE);
  1249.                 else
  1250.                     return (ERROR);
  1251.                 }
  1252.             }
  1253.         /*
  1254.          * Invalid parameters or (for a full lease negotiation) a
  1255.          * failed ARP probe (address in use). Ignore invalid parameters
  1256.          * for DHCP inform messages.
  1257.          */
  1258.         if (pLeaseData->prevState == INFORMING)
  1259.             return (OK);
  1260.         /*
  1261.          * For the full lease negotiation, send the DHCPDECLINE which
  1262.          * is now required when an ARP probe fails: RFC 2131, section 3.1.5.
  1263.          */
  1264.         set_declinfo (&tmp_reqspec, pLeaseData, errmsg, arpans);
  1265.         dhcp_decline (&tmp_reqspec, &pLeaseData->ifData);
  1266.         clean_param (pLeaseData->dhcpcParam);
  1267.         free (pLeaseData->dhcpcParam);
  1268.         pLeaseData->dhcpcParam = NULL;
  1269. #ifdef DHCPC_DEBUG
  1270.         logMsg ("Received unacceptable DHCPACK. Entering INIT state.n",
  1271.                 0, 0, 0, 0, 0, 0);
  1272. #endif
  1273.         pLeaseData->prevState = REQUESTING;
  1274.         pLeaseData->currState = INIT;
  1275.         return (DHCPC_MORE);
  1276.         }    /* End of DHCP message processing. */
  1277.     return (OK);
  1278.     }