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

VxWorks

开发平台:

C/C++

  1. /* dhcpcLib.c - Dynamic Host Configuration Protocol (DHCP) run-time client API */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc.  */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02k,25apr02,wap  Correct arguments passed to dhcpcOptionAdd() for
  8.                  little-endian targets (SPR #73769)
  9. 02j,23apr02,wap  use dhcpTime() instead of time() (SPR #68900)
  10. 02i,08mar02,wap  Allow DHCP to work at boot time when the boot device is not a
  11.                  network interface (SPR #73762)
  12. 02h,10dec01,wap  Fix bugs in dhcpcConfigSet() (SPR #72056)
  13. 02g,07dec01,vvv  test dhcpcEventAdd return value in dhcpcRelease
  14. 02f,03dec01,vvv  fixed interface configuration after dhcpcRelease (SPR #70026)
  15. 02e,05nov01,wap  dhcpcLeaseCleanup() fails to remove pLeaseData pointers from
  16.                  global dhcpcLeaseList (SPR #68981)
  17. 02d,26oct01,vvv  fixed dhcpcBind doc
  18. 02c,15oct01,rae  merge from truestack ver 02f, base 01u (SPRs 28985, 65264,
  19.                  67272, 65380, 65424, 29785)
  20. 02b,24may01,mil  Bump up dhcp state task stack size to 5000.
  21. 02a,17nov00,spm  added support for BSD Ethernet devices
  22. 01z,16nov00,spm  enabled new DHCP lease for runtime device setup (SPR #20438)
  23. 01y,16nov00,spm  fixed modification history after tor3_x merge
  24. 01x,13nov00,kbw  changed text of dhcpcParamsGet man page (SPR 28985)
  25. 01w,23oct00,niq  merged from version 01z of tor3_x branch (base version 01u)
  26. 01v,19oct00,dgr  docs: clarified sname/file retrieval with dhcpcParamsGet()
  27. 01u,17mar99,spm  fixed dhcpcRelease() and dhcpcVerify() routines (SPR #25482)
  28. 01t,05feb99,dgp  document errno values
  29. 01s,10dec97,kbw  fixed minor spelling issues in man pages
  30. 01r,04dec97,spm  added code review modifications; increased stack size for
  31.                  monitor task to 50% over maximum for ss5 board
  32. 01q,27oct97,spm  corrected name field to contain device name only
  33. 01p,21oct97,kbw  fixed minor spelling issues in man pages
  34. 01o,06oct97,spm  removed reference to deleted endDriver global; replaced with
  35.                  support for dynamic driver type detection
  36. 01n,25sep97,gnn  SENS beta feedback fixes
  37. 01m,02sep97,spm  removed unused global variable for event hook routine
  38. 01l,26aug97,spm  major overhaul: reorganized code and changed user interface
  39.                  to support multiple leases at runtime
  40. 01k,12aug97,gnn  changes necessitated by MUX/END update.
  41. 01j,06aug97,spm  removed parameters linked list to reduce memory required;
  42.                  corrected minor error in man pages introduced by 01i revision
  43. 01i,30jul97,kbw  fixed man page problems found in beta review
  44. 01h,15jul97,spm  fixed byte ordering of netmask from DHCP client (SPR #8739)
  45. 01g,10jun97,spm  fixed code layout and error in client lease indicator
  46. 01f,02jun97,spm  changed DHCP option tags to prevent name conflicts (SPR #8667)
  47.                  and updated man pages
  48. 01e,30apr97,spm  changed dhcpcOptionGet() to return length; expanded man pages
  49. 01d,15apr97,kbw  fixed format problems in man page text, changed some wording
  50. 01c,07apr97,spm  altered to use current value of configAll.h defines, fixed 
  51.                  user requests, inserted code previously in usrNetwork.c,
  52.                  rewrote documentation
  53. 01b,29jan97,spm  added END driver support and modified to fit coding standards.
  54. 01a,03oct96,spm  created by modifying WIDE Project DHCP Implementation.
  55. */
  56. /*
  57. DESCRIPTION
  58. This library implements the run-time access to the client side of the 
  59. Dynamic Host Configuration Protocol (DHCP).  DHCP is an extension of BOOTP. 
  60. Like BOOTP, the protocol allows a host to initialize automatically by obtaining
  61. its IP address, boot file name, and boot host's IP address over a network. 
  62. Additionally, DHCP provides a client with the complete set of parameters
  63. defined in the Host Requirements RFCs and allows automatic reuse of network 
  64. addresses by specifying individual leases for each set of configuration 
  65. parameters.  The compatible message format allows DHCP participants to interact 
  66. with BOOTP participants.  The dhcpcLibInit() routine links this library into 
  67. the VxWorks image. This happens automatically if INCLUDE_DHCPC is defined at 
  68. the time the image is built.
  69. CONFIGURATION INTERFACE
  70. When used during run time, the DHCP client library establishes and maintains
  71. one or more DHCP leases.  Each lease provides access to a set of configuration 
  72. parameters.  If requested, the parameters retrieved will be used to reconfigure 
  73. the associated network interface, but may also be handled separately through 
  74. an event hook.  The dhcpcEventHookAdd() routine specifies a function which is 
  75. invoked whenever the lease status changes.  The dhcpcEventHookDelete() routine 
  76. will disable that notification.  The automatic reconfiguration must be limited 
  77. to one lease for a particular network interface.  Otherwise, multiple leases 
  78. would attempt to reconfigure the same device, with unpredictable results.
  79. HIGH-LEVEL INTERFACE
  80. To access the DHCP client during run time, an application must first call 
  81. the dhcpcInit() routine with a pointer to the network interface to be used 
  82. for communication with a DHCP server.  Each call to the initialization 
  83. routine returns a unique identifier to be used in subsequent calls to the 
  84. DHCP client routines.  Next, the application must specify a client identifier 
  85. for the lease using the dhcpcOptionSet() call.  Typically, the link-level 
  86. hardware address is used for this purpose.  Additional calls to the option set 
  87. routine may be used to request specific DHCP options.  After all calls to that 
  88. routine are completed, a call to dhcpcBind() will retrieve a set of 
  89. configuration parameters according to the client-server interaction detailed 
  90. in RFC 1541.
  91. Each sequence of the three function calls described above, if successful,
  92. will retrieve a set of configuration parameters from a DHCP server.  The
  93. dhcpcServerGet() routine retrieves the address of the server that provided a 
  94. particular lease.  The dhcpcTimerGet() routine will retrieve the current values 
  95. for both lease timers. 
  96. Alternatively, the dhcpcParamsGet() and dhcpcOptionGet() routines will access 
  97. any options provided by a DHCP server.  In addition to the lease identifier
  98. obtained from the initialization routine, the dhcpcParamsGet() routine accepts 
  99. a parameter descriptor structure that selects any combination of the options 
  100. described in RFC 1533 for retrieval.  Similarly, the dhcpcOptionGet() routine 
  101. retrieves the values associated with a single option.
  102. LOW-LEVEL INTERFACE
  103. This library also contains several routines which explicitly generate DHCP 
  104. messages.  The dhcpcVerify() routine causes the client to renew a particular
  105. lease, regardless of the time remaining.  The dhcpcRelease() routine 
  106. relinquishes the specified lease.  The associated parameters are no longer 
  107. valid.  If those parameters were used by the underlying network device, the 
  108. routine also shuts off all network processing for that interface.  Finally,
  109. the dhcpcShutdown() routine will release all active leases and disable all
  110. the DHCP client library routines.
  111. OPTIONAL INTERFACE
  112. The dhcpcCacheHookAdd() routine registers a function that the client will
  113. use to store and retrieve lease data.  The client can then re-use this 
  114. information if it is rebooted.  The dhcpcCacheHookDelete() routine prevents 
  115. the re-use of lease data.  Initially, a function to access permanent storage 
  116. is not provided.
  117. INTERNAL
  118. The diagram below defines the structure chart of dhcpcLib.
  119.      |            |              |
  120.      v            v              v
  121.  dhcpcLibInit  dhcpcSetup    dhcpcConfigSet -------
  122.      |                       /    |                
  123.      v                      |     |     |            |
  124.   dhcpcMon                  v     |     v            |
  125. (spawned task)
  126.                         dhcpcInit | dhcpcBind        |
  127.                                   |                  |
  128.                                   |                  |
  129.                                   |                  |
  130.                                   v                  v
  131.                             dhcpcOptionSet     dhcpcParamsGet
  132. This library provides a wrapper for the WIDE project DHCP code found in the
  133. directory /vobs/wpwr/target/src/dhcp, which contains the state machine and
  134. other supporting functions.  The monitor task redirects incoming messages,
  135. timeout events, and user requests to the appropriate state in the state
  136. machine.  The input hook used to retrieve incoming messages and the
  137. monitor task routines are both in the dhcpcCommonLib module in this directory.
  138. The current RFC specification does not allow users to obtain parameters
  139. with DHCP without also obtaining a new IP address.  This limitation requires
  140. network shutdown if the lease used by an interface is not maintained.  It also 
  141. artificially limits the use of this library to routines involving an active 
  142. lease.  The draft RFC for the successor to RFC 1541 adds a new message which 
  143. avoids this problem.  Once published, DHCP can safely be used within an 
  144. application without risking network shutdown for any interface which was 
  145. statically configured during system boot.  The code which shuts down the 
  146. network should then be limited to execute conditionally on interfaces which
  147. have no backup source of addressing information.
  148. INCLUDE FILES: dhcpcLib.h
  149. SEE ALSO: RFC 1541, RFC 1533
  150. */
  151. /* includes */
  152. #include "dhcp/copyright_dhcp.h"
  153. #include "vxWorks.h"
  154. #include "bootLib.h"
  155. #include "sockLib.h"
  156. #include "ioLib.h"  /* ioctl() declaration */
  157. #include "vxLib.h"  /* checksum() declaration */
  158. #include "sysLib.h"
  159. #include "wdLib.h"
  160. #include "semLib.h"
  161. #include "inetLib.h"
  162. #include "taskLib.h"
  163. #ifdef DHCPC_DEBUG
  164. #include "logLib.h"
  165. #endif
  166. #include "muxLib.h"
  167. #include "stdio.h"
  168. #include "stdlib.h"
  169. #include "unistd.h"
  170. #include "string.h"
  171. #include "errno.h"
  172. #include "signal.h"
  173. #include "fcntl.h"
  174. #include "sys/types.h"
  175. #include "sys/socket.h"
  176. #include "sys/ioctl.h"
  177. #include "net/if.h"
  178. #include "netinet/in.h"
  179. #include "netinet/in_systm.h"
  180. #include "netinet/if_ether.h"
  181. #include "netinet/ip.h"
  182. #include "netinet/udp.h"
  183. #include "arpa/inet.h"
  184. #include "time.h"
  185. #include "dhcpcLib.h"
  186. #include "dhcp/dhcpcStateLib.h"
  187. #include "dhcp/dhcpcCommonLib.h"
  188. #include "dhcp/dhcpcInternal.h"
  189. #include "end.h"
  190. #include "ipProto.h"
  191. #include "bpfDrv.h"
  192. /* defines */
  193. #define _DHCP_MAX_OPTLEN  255  /* Max. number of bytes in an option */
  194. #define _DHCPC_MAX_DEVNAME  21  /* "/bpf/dhcpc" + max unit number */
  195. /* externals */
  196. IMPORT RING_ID  dhcpcEventRing; /* Ring buffer of DHCP events */
  197. IMPORT SEM_ID  dhcpcEventSem;  /* DHCP event notification */
  198. IMPORT int dhcpcReadTaskId; /* Identifier for data retrieval task */
  199. IMPORT int _dhcpcReadTaskPriority;      /* Priority level of data retriever */
  200. IMPORT int _dhcpcReadTaskOptions;       /* Option settings of data retriever */
  201. IMPORT int _dhcpcReadTaskStackSize;     /* Stack size of data retriever */
  202. IMPORT struct bpf_insn dhcpfilter[];    /* Needed to update client port. */
  203. IMPORT struct bpf_program dhcpread;     /* Installs filter for DHCP messages */
  204. IMPORT LEASE_DATA **  dhcpcLeaseList;  /* List of available cookies. */
  205. IMPORT MESSAGE_DATA *  dhcpcMessageList;  /* Available DHCP messages. */
  206. IMPORT int  dhcpcMaxLeases;  /* configAll.h #define value */
  207. IMPORT int  dhcpcMinLease;  /* configAll.h #define value */
  208. IMPORT int  dhcpcBufSize;  /* sets size of transmit and receive buffers */
  209. IMPORT int dhcpcDataSock;  /* Receives DHCP messages */
  210. /* globals */
  211. void *  pDhcpcBootCookie = NULL;  /* Access to boot-time lease. */
  212. BOOL dhcpcInitialized = FALSE;  /* Client initialized? */
  213. SEM_ID  dhcpcMutexSem;  /* Protects the DHCP status indicator */
  214. DHCP_LEASE_DATA  dhcpcBootLease;  /* Boot-time lease settings. */
  215. int _dhcpcStateTaskPriority  = 56;      /* Priority level of lease monitor */
  216. int _dhcpcStateTaskOptions   = 0;       /* Option settings of lease monitor */
  217. int _dhcpcStateTaskStackSize = 5000;    /* Stack size of lease monitor */
  218. LOCAL int dhcpcOfferTimeout;           /* configAll.h #define value */
  219. LOCAL int dhcpcDefaultLease;           /* configAll.h #define value */
  220. LOCAL FUNCPTR dhcpcCacheHookRtn;  /* Data storage/retrieval function */
  221. LOCAL int dhcpcSignalSock;              /* Indicates start of lease session */
  222. LOCAL char dhcpcSignalData [UDPHL + IPHL + 1];    /* Contents of signal */
  223. LOCAL int dhcpcSignalSize = UDPHL + IPHL + 1;
  224. /* forward declarations */
  225. LOCAL void dhcpcState (void);           /* Monitor pending/active leases */
  226. LOCAL STATUS dhcpcEventGet (EVENT_DATA *);
  227. LOCAL STATUS dhcpcEventHandle (EVENT_DATA *);
  228. LOCAL void dhcpcCleanup (void);
  229. LOCAL char *dhcpcOptionFind (LEASE_DATA *, int, int *);   /* Locate option */
  230. IMPORT void dhcpcRead (void);            /* Retrieve incoming DHCP messages */
  231. STATUS dhcpcVerify (void *); /* Renew lease */
  232. /*******************************************************************************
  233. *
  234. * dhcpcLibInit - DHCP client library initialization
  235. *
  236. * This routine creates and initializes the global data structures used by 
  237. * the DHCP client library to maintain multiple leases, up to the limit 
  238. * specified by the <maxLeases> parameter.  Every subsequent lease attempt will
  239. * collect additional DHCP offers until the interval specified by <offerTimeout>
  240. * expires and will request the lease duration indicated by <defaultLease>.
  241. * The <maxSize> parameter specifies the maximum length supported for any DHCP
  242. * message, including the UDP and IP headers and the largest link level header
  243. * for all supported devices. The maximum length of the DHCP options field is
  244. * based on this value or the MTU size for a lease's underlying interface,
  245. * whichever is less. The smallest valid value for the <maxSize> parameter is
  246. * 576 bytes, corresponding to the minimum IP datagram a host must accept.
  247. * Larger values will allow the client to handle longer DHCP messages.
  248. *
  249. * This routine must be called before calling any other library routines.  The 
  250. * routine is called automatically if INCLUDE_DHCPC is defined at the time the 
  251. * system is built and assigns the global lease settings to the values specified
  252. * by DHCPC_SPORT, DHCPC_CPORT, DHCPC_MAX_LEASES, DHCPC_MAX_MSGSIZE,
  253. * DHCPC_DEFAULT_LEASE, and DHCPC_OFFER_TIMEOUT.
  254. *
  255. * RETURNS: OK, or ERROR if initialization fails.
  256. *
  257. * ERRNO: S_dhcpcLib_MEM_ERROR
  258. */
  259. STATUS dhcpcLibInit 
  260.     (
  261.     int  serverPort,  /* port used by DHCP servers (default 67) */
  262.     int  clientPort,  /* port used by DHCP clients (default 68) */
  263.     int         maxLeases,  /* max number of simultaneous leases allowed */
  264.     int  maxSize,  /* largest DHCP message supported, in bytes */
  265.     int  offerTimeout,  /* interval to get additional DHCP offers */ 
  266.     int  defaultLease,  /* default value for requested lease length */
  267.     int  minLease  /* minimum accepted lease length */
  268.     )
  269.     {
  270.     int offset;
  271.     int loop;
  272.     int bufSize;  /* Size of receive buffer (maxSize + BPF header) */
  273.     int stateTaskId;  /* Identifier for client monitor task */
  274.     STATUS result;
  275.     struct sockaddr_in dstaddr;
  276.     struct ip *  pIph;
  277.     struct udphdr *  pUdph;
  278.     if (dhcpcInitialized)
  279.         return (OK);
  280.     if (maxSize < DFLTDHCPLEN + UDPHL + IPHL)
  281.         {
  282.         errno = S_dhcpcLib_MEM_ERROR;
  283.         return (ERROR);
  284.         }
  285.     /* Create a socket to signal the read task when a new session starts. */
  286.     dhcpcSignalSock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
  287.     if (dhcpcSignalSock < 0)
  288.         return (ERROR);
  289.     offset = 1;
  290.     result = setsockopt (dhcpcSignalSock, IPPROTO_IP, IP_HDRINCL,
  291.                          (char *)&offset, sizeof (int));
  292.     if (result != OK)
  293.         {
  294.         close (dhcpcSignalSock);
  295.         return (ERROR);
  296.         }
  297.     bzero ( (char *)&dstaddr, sizeof (dstaddr));
  298.     dstaddr.sin_family = AF_INET;
  299.     dstaddr.sin_addr.s_addr = htonl (0x7f000001);    /* 127.0.0.1: loopback */
  300.     result = connect (dhcpcSignalSock, (struct sockaddr *) &dstaddr,
  301.                           sizeof (dstaddr));
  302.     if (result != OK)
  303.         {
  304.         close (dhcpcSignalSock);
  305.         return (ERROR);
  306.         }
  307.     /* Create the signalling message (sent to loopback at DHCP client port). */
  308.     bzero (dhcpcSignalData, UDPHL + IPHL + 1);
  309.     pIph = (struct ip *)dhcpcSignalData;
  310.     pUdph = (struct udphdr *) (dhcpcSignalData + IPHL);
  311.     pIph->ip_v = IPVERSION;
  312.     pIph->ip_hl = IPHL >> 2;
  313.     pIph->ip_tos = 0;
  314.     pIph->ip_len = UDPHL + IPHL + 1;
  315.     pIph->ip_id = htons (0xF1C);
  316.     pIph->ip_off = IP_DF;
  317.     pIph->ip_ttl = 0x20;
  318.     pIph->ip_p = IPPROTO_UDP;
  319.     pIph->ip_src.s_addr = 0;
  320.     pIph->ip_dst.s_addr = htonl(0x7f000001);    /* 127.0.0.1: loopback */
  321.     pIph->ip_sum = checksum ( (u_short *)pIph, IPHL);
  322.     pUdph->uh_sport = 0;
  323.     pUdph->uh_dport = htons (clientPort);
  324.     pUdph->uh_ulen = htons (UDPHL + 1);
  325.     dhcpcSignalData [UDPHL + IPHL] = 'a';
  326.     /* Create a socket to send and receive DHCP messages. */
  327.     dhcpcDataSock = socket (AF_INET, SOCK_DGRAM, 0);
  328.     if (dhcpcDataSock < 0)
  329.         {
  330.         close (dhcpcSignalSock);
  331.         return (ERROR);
  332.         }
  333.     bzero ( (char *)&dstaddr, sizeof (dstaddr));
  334.     dstaddr.sin_family = AF_INET;
  335.     dstaddr.sin_addr.s_addr = htonl (INADDR_ANY);
  336.     dstaddr.sin_port = htons (clientPort); 
  337.     result = bind (dhcpcDataSock, (struct sockaddr *) &dstaddr,
  338.                        sizeof (dstaddr));
  339.     if (result != OK)
  340.         {
  341.         close (dhcpcSignalSock);
  342.         close (dhcpcDataSock);
  343.         return (ERROR);
  344.         }
  345.     if (bpfDrv () == ERROR)
  346.         {
  347.         close (dhcpcSignalSock);
  348.         close (dhcpcDataSock);
  349.         return (ERROR);
  350.         }
  351.     bufSize = maxSize + sizeof (struct bpf_hdr);
  352.     if (bpfDevCreate ("/bpf/dhcpc", maxLeases, bufSize) == ERROR)
  353.         {
  354.         close (dhcpcSignalSock);
  355.         close (dhcpcDataSock);
  356.         bpfDrvRemove ();
  357.         return (ERROR);
  358.         }
  359.     /* Create and initialize storage for active leases. */
  360.     dhcpcLeaseList = malloc (maxLeases * sizeof (LEASE_DATA *));
  361.     if (dhcpcLeaseList == NULL)
  362.         {
  363.         close (dhcpcSignalSock);
  364.         close (dhcpcDataSock);
  365.         bpfDevDelete ("/bpf/dhcpc");
  366.         bpfDrvRemove ();
  367.         errno = S_dhcpcLib_MEM_ERROR;
  368.         return (ERROR);
  369.         }
  370.     for (loop = 0; loop < maxLeases; loop++)
  371.         dhcpcLeaseList [loop] = NULL;
  372.     dhcpcMaxLeases = maxLeases;
  373.     dhcpcDefaultLease = defaultLease;
  374.     dhcpcOfferTimeout = offerTimeout;
  375.     dhcpcMinLease = minLease;
  376.     /*
  377.      * Create protection semaphore for all lease status indicators.  User 
  378.      * requests which require an active lease check this indicator before 
  379.      * executing.  A single semaphore is used to reduce system resource 
  380.      * requirements, even though this behavior may allow user requests to
  381.      * slightly delay status updates for unrelated leases.
  382.      */
  383.     dhcpcMutexSem = semBCreate (SEM_Q_FIFO, SEM_FULL);
  384.     if (dhcpcMutexSem == NULL)
  385.         {
  386.         close (dhcpcSignalSock);
  387.         close (dhcpcDataSock);
  388.         bpfDevDelete ("/bpf/dhcpc");
  389.         bpfDrvRemove ();
  390.         free (dhcpcLeaseList);
  391.         errno = S_dhcpcLib_MEM_ERROR;
  392.         return (ERROR);
  393.         }
  394.     /* Create signalling semaphore for event notification ring.  */
  395.     dhcpcEventSem = semCCreate (SEM_Q_FIFO, 0);
  396.     if (dhcpcEventSem == NULL)
  397.         {
  398.         close (dhcpcSignalSock);
  399.         close (dhcpcDataSock);
  400.         bpfDevDelete ("/bpf/dhcpc");
  401.         bpfDrvRemove ();
  402.         free (dhcpcLeaseList);
  403.         semDelete (dhcpcMutexSem);
  404.         errno = S_dhcpcLib_MEM_ERROR;
  405.         return (ERROR);
  406.         }
  407.     /* Create event storage.  */
  408.     dhcpcEventRing = rngCreate (EVENT_RING_SIZE);
  409.     if (dhcpcEventRing == NULL)
  410.         {
  411.         close (dhcpcSignalSock);
  412.         close (dhcpcDataSock);
  413.         bpfDevDelete ("/bpf/dhcpc");
  414.         bpfDrvRemove ();
  415.         free (dhcpcLeaseList);
  416.         semDelete (dhcpcMutexSem);
  417.         semDelete (dhcpcEventSem);
  418.         errno = S_dhcpcLib_MEM_ERROR;
  419.         return (ERROR);
  420.         }
  421.     /* Create message storage (matches number of elements in event ring). */
  422.     dhcpcMessageList = malloc (10 * sizeof (MESSAGE_DATA));
  423.     if (dhcpcMessageList == NULL)
  424.         {
  425.         close (dhcpcSignalSock);
  426.         close (dhcpcDataSock);
  427.         bpfDevDelete ("/bpf/dhcpc");
  428.         bpfDrvRemove ();
  429.         free (dhcpcLeaseList);
  430.         semDelete (dhcpcMutexSem);
  431.         semDelete (dhcpcEventSem);
  432.         rngDelete (dhcpcEventRing);
  433.         errno = S_dhcpcLib_MEM_ERROR;
  434.         return (ERROR);
  435.         }
  436.     /* Allocate receive buffers based on maximum message size. */
  437.     for (loop = 0; loop < 10; loop++)
  438.         {
  439.         dhcpcMessageList [loop].msgBuffer = memalign (4, bufSize);
  440.         if (dhcpcMessageList [loop].msgBuffer == NULL)
  441.             break;
  442.         dhcpcMessageList [loop].writeFlag = TRUE;
  443.         }
  444.     if (loop < 10)
  445.         {
  446.         for (offset = 0; offset < loop; offset++)
  447.             free (dhcpcMessageList [offset].msgBuffer);
  448.         close (dhcpcSignalSock);
  449.         close (dhcpcDataSock);
  450.         bpfDevDelete ("/bpf/dhcpc");
  451.         bpfDrvRemove ();
  452.         free (dhcpcLeaseList);
  453.         semDelete (dhcpcMutexSem);
  454.         semDelete (dhcpcEventSem);
  455.         rngDelete (dhcpcEventRing);
  456.         free (dhcpcMessageList);
  457.         errno = S_dhcpcLib_MEM_ERROR;
  458.         return (ERROR);
  459.         }
  460.  
  461.     /* Set up state machine and data structures for outgoing messages.  */
  462.     result = dhcp_client_setup (serverPort, clientPort, maxSize);
  463.     if (result == ERROR)
  464.         {
  465.         close (dhcpcSignalSock);
  466.         close (dhcpcDataSock);
  467.         bpfDevDelete ("/bpf/dhcpc");
  468.         bpfDrvRemove ();
  469.         free (dhcpcLeaseList);
  470.         semDelete (dhcpcMutexSem);
  471.         semDelete (dhcpcEventSem);
  472.         rngDelete (dhcpcEventRing);
  473.         for (offset = 0; offset < 10; offset++)
  474.             free (dhcpcMessageList [offset].msgBuffer);
  475.         free (dhcpcMessageList);
  476.         errno = S_dhcpcLib_MEM_ERROR;
  477.         return (ERROR);
  478.         }
  479.     dhcpcCacheHookRtn = NULL;
  480.     /*
  481.      * Spawn the monitor task.  The entry routine will drive the client
  482.      * state machine after processing all incoming DHCP messages and timer
  483.      * related or user generated events.
  484.      */
  485.     result = taskSpawn ("tDhcpcStateTask", _dhcpcStateTaskPriority,
  486.                         _dhcpcStateTaskOptions, _dhcpcStateTaskStackSize,
  487.                         (FUNCPTR) dhcpcState, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  488.     if (result == ERROR)
  489.         {
  490.         close (dhcpcSignalSock);
  491.         close (dhcpcDataSock);
  492.         bpfDevDelete ("/bpf/dhcpc");
  493.         bpfDrvRemove ();
  494.         free (dhcpcLeaseList);
  495.         semDelete (dhcpcMutexSem);
  496.         semDelete (dhcpcEventSem);
  497.         rngDelete (dhcpcEventRing);
  498.         for (offset = 0; offset < 10; offset++)
  499.             free (dhcpcMessageList [offset].msgBuffer);
  500.         free (dhcpcMessageList);
  501.         errno = S_dhcpcLib_MEM_ERROR;
  502.         return (ERROR);
  503.         }
  504.     stateTaskId = result;
  505.     /*
  506.      * Spawn the data retrieval task.  The entry routine will read all 
  507.      * incoming DHCP messages and signal the monitor task when a
  508.      * valid one arrives.
  509.      */
  510.     result = taskSpawn ("tDhcpcReadTask", _dhcpcReadTaskPriority,
  511.                         _dhcpcReadTaskOptions, _dhcpcReadTaskStackSize,
  512.                         (FUNCPTR) dhcpcRead, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  513.     if (result == ERROR)
  514.         {
  515.         close (dhcpcSignalSock);
  516.         close (dhcpcDataSock);
  517.         bpfDevDelete ("/bpf/dhcpc");
  518.         bpfDrvRemove ();
  519.         free (dhcpcLeaseList);
  520.         semDelete (dhcpcMutexSem);
  521.         semDelete (dhcpcEventSem);
  522.         rngDelete (dhcpcEventRing);
  523.         for (offset = 0; offset < 10; offset++)
  524.             free (dhcpcMessageList [offset].msgBuffer);
  525.         free (dhcpcMessageList);
  526.         taskDelete (stateTaskId);
  527.         errno = S_dhcpcLib_MEM_ERROR;
  528.         return (ERROR);
  529.         }
  530.     dhcpcReadTaskId = result;
  531.     dhcpcBufSize = maxSize;
  532.     /* Reset the filter to use the specified client port. */
  533.     dhcpfilter [12].k = clientPort;
  534.     /* Minimum IP and UDP packet lengths */
  535.     dhcpfilter [14].k = (DFLTDHCPLEN - DFLTOPTLEN + 4) + UDPHL + IPHL;
  536.     dhcpfilter [16].k = (DFLTDHCPLEN - DFLTOPTLEN + 4) + UDPHL;
  537.     dhcpcInitialized = TRUE;
  538.     return (OK);
  539.     }
  540. /*******************************************************************************
  541. *
  542. * dhcpcLeaseGet - read lease information from boot line
  543. *
  544. * If an automatic configuration protocol was used by the bootstrap loader
  545. * (i.e. - SYSFLG_AUTOCONFIG was set), this routine is called to handle
  546. * possible DHCP values in the address string.  If the target address indicated 
  547. * by <pAddrString> contains both lease duration and lease origin values, it was
  548. * assigned by a DHCP server and the routine sets the status flag accessed by 
  549. * <pDhcpStatus> so that the lease will be verified or renewed.  This routine is 
  550. * called when initializing the network during system startup and will not 
  551. * function correctly if used in any other context.  Any lease information 
  552. * attached to the address string is removed when this routine is executed.
  553. *
  554. * RETURNS: OK if setup completes, or ERROR if the address string is invalid.
  555. *
  556. * ERRNO: N/A
  557. *
  558. * NOMANUAL
  559. */
  560. STATUS dhcpcLeaseGet
  561.     (
  562.     char *  pAddrString,  /* client address string from bootline */
  563.     BOOL *  pDhcpStatus  /* DHCP lease values found? */
  564.     )
  565.     {
  566.     char *  pDelim;
  567.     char *  pOffset;
  568.     int  result;
  569.     dhcpcBootLease.lease_duration = 0;  /* Defaults to expired.  */
  570.     dhcpcBootLease.lease_origin = 0;  /* Defaults to invalid value.  */
  571.     /* Read DHCP lease values and remove from address string.  */
  572.     result = bootLeaseExtract (pAddrString, &dhcpcBootLease.lease_duration,
  573.                                &dhcpcBootLease.lease_origin);
  574.     if (result == 2)
  575.         *pDhcpStatus = TRUE;    /* DHCP lease values read successfully.  */
  576.     else
  577.         {
  578.         *pDhcpStatus = FALSE;    /* Valid DHCP lease values not present.  */
  579.         if (result == 0)
  580.             {
  581.             /* 
  582.              * The ":" field separator for either the netmask or duration was
  583.              * not found, so no DHCP lease values are present. 
  584.              */
  585.             return (OK);
  586.             }
  587.         if (result == 1)
  588.             {
  589.             /* 
  590.              * Only the lease duration field was present.
  591.              * The DHCP lease values have been removed.
  592.              */
  593.            return (ERROR);
  594.            }
  595.         /* 
  596.          * Parsing one of the lease values failed.  Remove
  597.          * any DHCP lease data from the address string.
  598.          */
  599.         /* Find delimiter for netmask.  */
  600.         pOffset = index (pAddrString, ':');
  601.         /*
  602.          * Start at the delimiter for DHCP lease values.  The netmask separator
  603.          * is actually always present at this point, but check for it anyway.
  604.          */
  605.         if (pOffset != NULL)
  606.             {
  607.             pDelim = pOffset + 1;
  608.             /* 
  609.              * Find the lease duration tag.  This field separator is also
  610.              * guaranteed to be present, or the extract routine would have
  611.              * returned 0.
  612.              */
  613.             pOffset = index (pDelim, ':');
  614.             /* Remove the DHCP lease values from string.  */
  615.             if (pOffset != NULL)
  616.                 *pOffset = EOS;
  617.             }
  618.         return (ERROR);
  619.         }
  620.     return (OK);
  621.     }
  622. /*******************************************************************************
  623. *
  624. * dhcpcConfigSet - set system configuration according to active DHCP lease
  625. *
  626. * This routine verifies or renews any DHCP lease established during the system 
  627. * boot.  If a DHCP lease was established, the dhcpcInit() call in this routine
  628. * will setup the necessary data structures and create a cookie identifying the 
  629. * boot lease.  The cookie is stored in the pDhcpcBootCookie global variable to
  630. * provide users with access to the boot-time lease.  This routine is called when
  631. * initializing the network during system startup and will not function
  632. * correctly if executed in any other context.
  633. *
  634. * RETURNS: OK if configuration completed, or ERROR otherwise.
  635. *
  636. * ERRNO: N/A
  637. *
  638. * NOMANUAL
  639. */
  640. STATUS dhcpcConfigSet
  641.     (
  642.     BOOT_PARAMS *  pParams,  /* structure for parsed bootline */
  643.     char *  pAddrString,  /* specified IP address */
  644.     int *  pNetmask,  /* specified subnet mask */
  645.     BOOL * pDhcpStatus,  /* DHCP used to get address? */
  646.     BOOL  attachFlag  /* Device configuration required? */
  647.     )
  648.     {
  649.     char  netDev [BOOT_DEV_LEN + 1];
  650.     struct dhcp_param  bootParams;
  651.     BOOL  dhcpStatus;
  652.     u_long  result;
  653.     struct ifnet *  pIf;
  654.     LEASE_DATA *  pLeaseData;
  655.     char bootFile[BOOT_FILE_LEN];
  656.     int netmask;
  657.     dhcpStatus = *pDhcpStatus;
  658.     if (dhcpStatus && !attachFlag)
  659.         {
  660.         /*
  661.          * Fatal error: automatic configuration is required but not available.
  662.          */
  663.         return (ERROR);
  664.         }
  665.     if (dhcpStatus == FALSE && pAddrString [0] != EOS)
  666.         {
  667.         /* 
  668.          * BOOTP reply was selected during system startup or the IP address
  669.          * was assigned manually.  Lease renewal (or new lease) is not needed.
  670.          */
  671.         return (OK);
  672.         }
  673.     
  674.     /* Verify DHCP lease obtained during boot or get a new one.  */
  675.     bzero ( (char *)&bootParams, sizeof (struct dhcp_param));
  676.     if (((strncmp (pParams->bootDev, "scsi", 4) == 0) ||
  677.         (strncmp (pParams->bootDev, "ide", 3) == 0) ||
  678.         (strncmp (pParams->bootDev, "ata", 3) == 0) ||
  679.         (strncmp (pParams->bootDev, "fd", 2) == 0)  ||
  680.         (strncmp (pParams->bootDev, "tffs", 4) == 0)) &&
  681.         pParams->other [0] != EOS)
  682.         sprintf (netDev, "%s%d", pParams->other, pParams->unitNum);
  683.     else
  684.         sprintf (netDev, "%s%d", pParams->bootDev, pParams->unitNum);
  685.     if (pAddrString [0] != EOS)
  686.         {
  687.         /* Fill in client address obtained from bootline. */
  688.         result = inet_addr (pAddrString);
  689.         if (result == ERROR)
  690.             {
  691.             printf ("Invalid target address "%s"n", pAddrString);
  692.             return (ERROR);
  693.             }
  694.         dhcpcBootLease.yiaddr.s_addr = result;
  695.         }
  696.     pIf = ifunit (netDev);
  697.     if (pIf == NULL)
  698.         {
  699.         printf ("Invalid device "%s"n", netDev);
  700.         return (ERROR);
  701.         }
  702.     /* 
  703.      * Initialize required variables and get the lease identifier.  
  704.      * The resulting lease will always apply the address information
  705.      * to the specified network interface.  
  706.      */
  707.     pDhcpcBootCookie = dhcpcInit (pIf, TRUE);
  708.     if (pDhcpcBootCookie == NULL)
  709.         {
  710.         printf ("Error initializing DHCP boot lease.n");
  711.         return (ERROR);
  712.         }
  713.     if (pAddrString [0] != EOS)
  714.         {
  715.         unsigned long duration;
  716.         /*
  717.          * Setup to renew the boot lease. Use the cookie to access the
  718.          * lease-specific data structures.  For now, just typecast
  719.          * the cookie.  This translation could be replaced with a more
  720.          * sophisticated lookup at some point.
  721.          */
  722.         pLeaseData = (LEASE_DATA *)pDhcpcBootCookie;
  723.         /* Set the lease descriptor to identify the boot lease.  */
  724.         pLeaseData->leaseType = DHCP_AUTOMATIC;
  725.         /* Make sure the lease duration is in network byte order. */
  726.         duration = htonl(dhcpcBootLease.lease_duration);
  727.         dhcpcOptionAdd (pDhcpcBootCookie, _DHCP_LEASE_TIME_TAG, 
  728.                         4, (UCHAR *)&duration);
  729.         }
  730.     /*
  731.      * Execute the bind call synchronously to verify any boot lease
  732.      * or get the required IP address.
  733.      */
  734.     if (dhcpcBind (pDhcpcBootCookie, TRUE) != OK)
  735.         {
  736.         if (dhcpStatus == TRUE)
  737.             printf ("Can't renew DHCP boot lease.n");
  738.         else
  739.             printf ("Can't get IP address for device.n");
  740.         pDhcpcBootCookie = NULL;
  741.         return (ERROR);
  742.         }
  743.     bootParams.file = bootFile;
  744.     bootParams.subnet_mask = (struct in_addr *)&netmask;
  745.     if (dhcpcParamsGet (pDhcpcBootCookie, &bootParams) == ERROR)
  746.         {
  747.         printf ("Can't get network data from DHCP lease.n");
  748.         pDhcpcBootCookie = NULL;
  749.         return (ERROR);
  750.         }
  751.     /*
  752.      * The netmask is returned to us in network byte order,
  753.      * but the caller expects it in host order.
  754.      */
  755.     *pNetmask = ntohl(netmask);
  756.     /* Fill in boot file */
  757.     if (bootParams.file[0] != EOS)
  758. bcopy (bootFile, pParams->bootFile, BOOT_FILE_LEN);
  759.     /* Fill in host address.  */
  760.     if (bootParams.siaddr.s_addr)
  761.         inet_ntoa_b (bootParams.siaddr, pParams->had);
  762.     /* Fill in new or verified target address. */
  763.     inet_ntoa_b (bootParams.yiaddr, pAddrString);
  764.     /* Save timing information so later reboots will detect DHCP leases. */
  765.     dhcpcBootLease.lease_duration = bootParams.lease_duration;
  766.     dhcpcBootLease.lease_origin = bootParams.lease_origin;
  767.     /* Update status in case IP address is newly assigned. */
  768.     *pDhcpStatus = TRUE;
  769.     return (OK);
  770.     }
  771. /*******************************************************************************
  772. *
  773. * dhcpcInit - assign network interface and setup lease request
  774. *
  775. * This routine creates the data structures used to obtain a set of parameters 
  776. * with DHCP and must be called before each attempt at establishing a DHCP 
  777. * lease, but after the dhcpcLibInit() routine has initialized the global data
  778. * structures.
  779. *
  780. * The <pIf> argument indicates the network device which will be used for
  781. * transmission and reception of DHCP messages during the lifetime of the
  782. * lease.  The DHCP client supports devices attached to the IP protocol
  783. * with the MUX/END interface.  The specified device must be capable of
  784. * sending broadcast messages.  It also supports BSD Ethernet devices
  785. * attached to the IP protocol. The MTU size of any interface must be large
  786. * enough to receive a minimum IP datagram of 576 bytes. If the interface MTU
  787. * size is less than the maximum message size set in the library initialization
  788. * it also determines the maximum length of the DHCP options field.
  789. *
  790. * If the <autoConfig> parameter is set to TRUE, any address information
  791. * obtained will automatically be applied to the specified interface. The
  792. * <autoConfig> parameter also selects the default option request list for
  793. * a lease.  If set to FALSE, no specific lease options are requested since
  794. * any configuration parameters obtained are not intended for the underlying
  795. * network device.  In that case, any specific options required may be added
  796. * to the request list at any time before the corresponding dhcpcBind() call.
  797. * If <autoConfig> is TRUE, this routine sets the configuration parameters to
  798. * request the minimal address information (subnet mask and broadcast address)
  799. * necessary for reconfiguring the network device specified by <pIf>.
  800. *
  801. * The internal lease identifier returned by this routine must be used in
  802. * subsequent calls to the DHCP client library.
  803. *
  804. * NOTE
  805. * This routine is called automatically during system startup if the DHCP 
  806. * client was used to obtain the VxWorks boot parameters.  The resulting 
  807. * lease will always reconfigure the network boot device.  Therefore, any
  808. * further calls to this routine which specify the network boot device for 
  809. * use in obtaining additional DHCP leases must set <autoConfig> to FALSE.
  810. * Otherwise, that device will be unable to maintain a stable configuration.
  811. * The global variable pDhcpcBootCookie provides access to the configuration 
  812. * parameters for any DHCP lease created during system startup.
  813. * RETURNS: Lease handle for later use, or NULL if lease setup fails.
  814. *
  815. * ERRNO: S_dhcpcLib_NOT_INITIALIZED, S_dhcpcLib_BAD_DEVICE, S_dhcpcLib_BAD_OPTION,
  816. *  S_dhcpcLib_MAX_LEASES_REACHED, S_dhcpcLib_MEM_ERROR
  817. *
  818. * SEE ALSO
  819. * dhcpcOptionSet(), dhcpcEventHookAdd()
  820. */
  821. void * dhcpcInit
  822.     (
  823.     struct ifnet * pIf,  /* network device used by client */
  824.     BOOL  autoConfig  /* reconfigure network device? */
  825.     )
  826.     {
  827.     void *  pCookie;
  828.     LEASE_DATA *   pLeaseData;
  829.     struct dhcp_reqspec *  pReqSpec;
  830.     int offset;
  831.     int result;
  832.     int maxSize;  /* Largest message, based on MTU and buffer sizes */
  833.     int bufSize;  /* Size of internal BPF buffer for lease */
  834.     BOOL bsdFlag = FALSE;
  835.     char bpfDevName [_DHCPC_MAX_DEVNAME];  /* "/bpf/dhcpc" + max unit number */
  836.     int bpfDev;
  837.     if (!dhcpcInitialized)
  838.         {
  839.         errno = S_dhcpcLib_NOT_INITIALIZED;
  840.         return (NULL);
  841.         }
  842.     if (pIf == NULL)
  843.         {
  844.         errno = S_dhcpcLib_BAD_DEVICE;
  845.         return (NULL);
  846.         }
  847.     if (muxDevExists (pIf->if_name, pIf->if_unit) == FALSE)
  848.         {
  849.         bsdFlag = TRUE; 
  850.         }
  851.     /* Verify interface data sizes are appropriate for message. */
  852.     if (pIf->if_mtu == 0)
  853.         {
  854.         errno = S_dhcpcLib_BAD_DEVICE;
  855.         return (NULL);
  856.         }
  857.     maxSize = pIf->if_mtu;
  858.     if (maxSize < DHCP_MSG_SIZE)
  859.         {
  860.         /*
  861.          * Devices must accept messages equal to the minimum IP datagram
  862.          * of 576 bytes, which corresponds to a DHCP message with up to
  863.          * 312 bytes of options.
  864.          */
  865.         errno = S_dhcpcLib_BAD_DEVICE;
  866.         return (NULL);
  867.         }
  868.     /* Reduce maximum DHCP message to size of transmit buffer if necessary. */
  869.     if (maxSize > dhcpcBufSize)
  870.         maxSize = dhcpcBufSize;
  871.     if (autoConfig != TRUE && autoConfig != FALSE)
  872.         {
  873.         errno = S_dhcpcLib_BAD_OPTION;
  874.         return (NULL);
  875.         }
  876.     /* Find an unused entry in the array of lease-specific variables.  */
  877.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  878.         if (dhcpcLeaseList [offset] == NULL)
  879.             break; 
  880.    
  881.     if (offset == dhcpcMaxLeases)
  882.         {
  883.         errno = S_dhcpcLib_MAX_LEASES_REACHED;
  884.         return (NULL);
  885.         }
  886.     /* Get a BPF file descriptor to read/write DHCP messages. */
  887.     sprintf (bpfDevName, "/bpf/dhcpc%d", offset);
  888.     bpfDev = open (bpfDevName, 0, 0);
  889.     if (bpfDev < 0)
  890.         {
  891.         errno = S_dhcpcLib_BAD_DEVICE;
  892.         return (NULL);
  893.         }
  894.     /* Enable immediate mode for reading messages. */
  895.     result = 1;
  896.     result = ioctl (bpfDev, BIOCIMMEDIATE, (int)&result);
  897.     if (result != 0)
  898.         {
  899.         close (bpfDev);
  900.         errno = S_dhcpcLib_BAD_DEVICE;
  901.         return (NULL);
  902.         }
  903.     /*
  904.      * To save space, reset the internal BPF buffer to a value based
  905.      * on the interface MTU size, if it is less than the maximum receive
  906.      * buffer size assigned during the library initialization. The
  907.      * DHCP client's read task handles the possibility of multiple
  908.      * messages per receive buffer.
  909.      */
  910.     bufSize = pIf->if_mtu + pIf->if_hdrlen;
  911.     if (bufSize < dhcpcBufSize)
  912.         {
  913.         bufSize += sizeof (struct bpf_hdr);
  914.         result = ioctl (bpfDev, BIOCSBLEN, (int)&bufSize);
  915.         if (result != 0)
  916.             {
  917.             close (bpfDev);
  918.             errno = S_dhcpcLib_BAD_DEVICE;
  919.             return (NULL);
  920.             }
  921.         }
  922.     else
  923.         bufSize = dhcpcBufSize + sizeof (struct bpf_hdr);
  924.     /* Allocate all lease-specific variables.  */
  925.     
  926.     pLeaseData = (LEASE_DATA *)calloc (1, sizeof (LEASE_DATA));
  927.     if (pLeaseData == NULL)
  928.         {
  929.         close (bpfDev);
  930.         errno = S_dhcpcLib_MEM_ERROR;
  931.         return (NULL);
  932.         }
  933.     pLeaseData->initFlag = FALSE;
  934.     pLeaseData->autoConfig = autoConfig;
  935.     /* 
  936.      * Use the current data storage hook routine (if any)
  937.      * throughout the lifetime of this lease.
  938.      */
  939.     pLeaseData->cacheHookRtn = dhcpcCacheHookRtn;
  940.     /* 
  941.      * For now, use the lease data pointer as the unique lease identifier.
  942.      * This could be changed later to shield the internal structures from
  943.      * the user, but it allows fast data retrieval.
  944.      */
  945.     pCookie = (void *)pLeaseData;
  946.     pReqSpec = &pLeaseData->leaseReqSpec;
  947.     bzero ( (char *)pReqSpec, sizeof (struct dhcp_reqspec));
  948.     bzero ( (char *)&pLeaseData->ifData, sizeof (struct if_info));
  949.     /* Initialize WIDE project global containing network device data.  */ 
  950.     sprintf (pLeaseData->ifData.name, "%s", pIf->if_name);
  951.     pLeaseData->ifData.unit = pIf->if_unit;
  952.     pLeaseData->ifData.iface = pIf;
  953.     pLeaseData->ifData.bpfDev = bpfDev;
  954.     pLeaseData->ifData.bufSize = bufSize;
  955.     /*
  956.      * For END devices, use hardware address information set when
  957.      * driver attached to IP. Assume BSD devices use Ethernet frames.
  958.      */
  959.     if (bsdFlag)
  960.         pLeaseData->ifData.haddr.htype = ETHER;
  961.     else
  962.         pLeaseData->ifData.haddr.htype = dhcpConvert (pIf->if_type);
  963.     pLeaseData->ifData.haddr.hlen = pIf->if_addrlen;
  964.     if (pLeaseData->ifData.haddr.hlen > MAX_HLEN)
  965.         pLeaseData->ifData.haddr.hlen = MAX_HLEN;
  966.     bcopy ( (char *) ( (struct arpcom *)pIf)->ac_enaddr,
  967.            (char *)&pLeaseData->ifData.haddr.haddr, 
  968.            pLeaseData->ifData.haddr.hlen); 
  969.     /*
  970.      * Set the maximum message length based on the MTU size and the
  971.      * maximum message/buffer size specified during initialization.
  972.      */
  973.     pReqSpec->maxlen = maxSize;
  974.     /* set duration of client's wait for multiple offers */
  975.     pReqSpec->waitsecs = dhcpcOfferTimeout; 
  976.     pReqSpec->reqlist.len = 0;    /* No options requested yet.  */
  977.     /*
  978.      * If executing with startup lease, or if automatic configuration is
  979.      * requested, initialize request list with tags for options required 
  980.      * by all network interfaces, using RFC 1533 tag values.
  981.      */
  982.     if (pLeaseData->autoConfig || pLeaseData->leaseType == DHCP_AUTOMATIC)
  983.         {
  984.         pReqSpec->reqlist.list [pReqSpec->reqlist.len++] =
  985.                                                         _DHCP_SUBNET_MASK_TAG;
  986.         pReqSpec->reqlist.list [pReqSpec->reqlist.len++] =
  987.                                                         _DHCP_BRDCAST_ADDR_TAG;
  988.         }
  989.     /*
  990.      * For now, create a separate watchdog timer for each lease.  Eventually,
  991.      * a single watchdog timer will suffice for all leases, when combined
  992.      * with a sorted queue containing relative firing times.  This enhancement
  993.      * can wait.
  994.      */
  995.     /* Create event timer for state machine.  */
  996.     pLeaseData->timer = wdCreate ();
  997.     if (pLeaseData->timer == NULL)
  998.         {
  999.         free (pLeaseData);
  1000.         close (bpfDev);
  1001.         errno = S_dhcpcLib_MEM_ERROR;
  1002.         return (NULL);
  1003.         }
  1004.     /* Create signalling semaphore for completion of negotiation process.  */
  1005.     pLeaseData->leaseSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
  1006.     if (pLeaseData->leaseSem == NULL)
  1007.         {
  1008.         wdDelete (pLeaseData->timer);
  1009.         free (pLeaseData);
  1010.         close (bpfDev);
  1011.         errno = S_dhcpcLib_MEM_ERROR;
  1012.         return (NULL);
  1013.         }
  1014.     /* 
  1015.      * Manual leases will not reset the network interface unless specifically
  1016.      * requested to do so.  This lease type is replaced with DHCP_AUTOMATIC for 
  1017.      * the lease established during system startup.  The parameters for
  1018.      * an automatic lease are always applied to the underlying interface.
  1019.      */
  1020.     pLeaseData->leaseType = DHCP_MANUAL;
  1021.     pLeaseData->initFlag = TRUE;
  1022.     /* Store the lease-specific data in the global list.  */
  1023.     dhcpcLeaseList [offset] = pLeaseData;
  1024.     /* Notify the DHCP read task that a new session is available. */
  1025.     send (dhcpcSignalSock, dhcpcSignalData, dhcpcSignalSize, 0);
  1026.     return (pCookie);
  1027.     }
  1028. /*******************************************************************************
  1029. *
  1030. * dhcpcEventHookAdd - add a routine to handle configuration parameters
  1031. *
  1032. * This routine installs a hook routine to handle changes in the configuration
  1033. * parameters provided for the lease indicated by <pCookie>.  The hook provides 
  1034. * an alternate configuration method for DHCP leases and uses the following 
  1035. * interface:
  1036. * .CS
  1037. * void dhcpcEventHookRtn
  1038. *     (
  1039. *     int  leaseEvent, /@ new or expired parameters @/
  1040. *     void *  pCookie  /@ lease identifier from dhcpcInit() @/
  1041. *     )
  1042. * .CE
  1043. *
  1044. * The routine is called with the <leaseEvent> parameter set to DHCPC_LEASE_NEW
  1045. * whenever a lease is successfully established.  The DHCPC_LEASE_NEW event
  1046. * does not occur when a lease is renewed by the same DHCP server, since the
  1047. * parameters do not change in that case.  However, it does occur if the 
  1048. * client rebinds to a different DHCP server.  The DHCPC_LEASE_INVALID event
  1049. * indicates that the configuration parameters for the corresponding lease may
  1050. * no longer be used.  That event occurs when a lease expires or a renewal
  1051. * or verification attempt fails, and coincides with re-entry into the initial 
  1052. * state of the negotiation process.
  1053. *
  1054. * If the lease initialization specified automatic configuration of the
  1055. * corresponding network interface, any installed hook routine will be invoked
  1056. * after the new address information is applied.
  1057. *
  1058. * RETURNS: OK if notification hook added, or ERROR otherwise.
  1059. *
  1060. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED
  1061. */
  1062. STATUS dhcpcEventHookAdd
  1063.     (
  1064.     void *  pCookie,  /* identifier returned by dhcpcInit() */
  1065.     FUNCPTR  pEventHook /* routine to handle lease parameters */
  1066.     )
  1067.     {
  1068.     LEASE_DATA *  pLeaseData;
  1069.     int offset;
  1070.     /*
  1071.      * Use the cookie to access the lease-specific data structures.  For now,
  1072.      * just typecast the cookie.  This translation could be replaced with a more
  1073.      * sophisticated lookup at some point.
  1074.      */
  1075.     pLeaseData = (LEASE_DATA *)pCookie;
  1076.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  1077.         if (dhcpcLeaseList [offset] != NULL &&
  1078.                 dhcpcLeaseList [offset] == pLeaseData)
  1079.             break;
  1080.     if (offset == dhcpcMaxLeases)
  1081.         {
  1082.         errno = S_dhcpcLib_BAD_COOKIE;
  1083.         return (ERROR);
  1084.         }
  1085.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  1086.         {
  1087.         errno = S_dhcpcLib_NOT_INITIALIZED;
  1088.         return (ERROR);
  1089.         }
  1090.     /* Assign the event notification hook.  */
  1091.     pLeaseData->eventHookRtn = pEventHook;
  1092.     return (OK);
  1093.     }
  1094. /*******************************************************************************
  1095. *
  1096. * dhcpcEventHookDelete - remove the configuration parameters handler
  1097. *
  1098. * This routine removes the hook routine that handled changes in the 
  1099. * configuration parameters for the lease indicated by <pCookie>.
  1100. * If the lease initialization specified automatic configuration of the
  1101. * corresponding network interface, the assigned address could change
  1102. * without warning after this routine is executed.
  1103. *
  1104. * RETURNS: OK if notification hook removed, or ERROR otherwise.
  1105. *
  1106. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED
  1107. */
  1108. STATUS dhcpcEventHookDelete
  1109.     (
  1110.     void *  pCookie  /* identifier returned by dhcpcInit() */
  1111.     )
  1112.     {
  1113.     LEASE_DATA *  pLeaseData;
  1114.     int offset;
  1115.     /*
  1116.      * Use the cookie to access the lease-specific data structures. For now,
  1117.      * just typecast the cookie. This translation could be replaced with a more
  1118.      * sophisticated lookup at some point.
  1119.      */
  1120.     pLeaseData = (LEASE_DATA *)pCookie;
  1121.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  1122.         if (dhcpcLeaseList [offset] != NULL &&
  1123.                 dhcpcLeaseList [offset] == pLeaseData)
  1124.             break;
  1125.     if (offset == dhcpcMaxLeases)
  1126.         {
  1127.         errno = S_dhcpcLib_BAD_COOKIE;
  1128.         return (ERROR);
  1129.         }
  1130.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  1131.         {
  1132.         errno = S_dhcpcLib_NOT_INITIALIZED;
  1133.         return (ERROR);
  1134.         }
  1135.     /* Remove the event notification hook. */
  1136.     pLeaseData->eventHookRtn = NULL;
  1137.     return (OK);
  1138.     }
  1139. /*******************************************************************************
  1140. *
  1141. * dhcpcCacheHookAdd - add a routine to store and retrieve lease data
  1142. *
  1143. * This routine adds a hook routine that is called at the bound state
  1144. * (to store the lease data) and during the INIT_REBOOT state (to re-use the
  1145. * parameters if the lease is still active).  The calling sequence of the 
  1146. * input hook routine is:
  1147. * .CS
  1148. * STATUS dhcpcCacheHookRtn
  1149. *     (
  1150. *     int command, /@ requested cache operation @/
  1151. *     unsigned long *pTimeStamp, /@ lease timestamp data @/
  1152. *     int *pDataLen, /@ length of data to access @/
  1153. *     char *pBuffer /@ pointer to data buffer @/
  1154. *     )
  1155. *
  1156. * .CE
  1157. * The hook routine should return OK if the requested operation is completed
  1158. * successfully, or ERROR otherwise.  All the supplied pointers reference memory 
  1159. * locations that are reused upon return from the hook.  The hook routine 
  1160. * must copy the data elsewhere.
  1161. *
  1162. * NOTE
  1163. * The setting of the cache hook routine during a dhcpcInit() call is
  1164. * recorded and used by the resulting lease throughout its lifetime.
  1165. * Since the hook routine is intended to store a single lease record,
  1166. * a separate hook routine should be specified before the dhcpcInit()
  1167. * call for each lease which will re-use its parameters across reboots.
  1168. *
  1169. * IMPLEMENTATION
  1170. * The <command> parameter specifies one of the following operations:
  1171. * .IP DHCP_CACHE_WRITE 25
  1172. * Save the indicated data.  The write operation must preserve the value
  1173. * referenced by <pTimeStamp> and the contents of <pBuffer>.  The <pDataLen> 
  1174. * parameter indicates the number of bytes in that buffer.
  1175. * .IP DHCP_CACHE_READ 
  1176. * Restore the saved data.  The read operation must copy the data from the
  1177. * most recent write operation into the location indicated by <pBuffer>,
  1178. * set the contents of <pDataLen> to the amount of data provided, and store 
  1179. * the corresponding timestamp value in <pTimeStamp>.
  1180. * .IP
  1181. * The read operation has very specific requirements.  On entry, the value 
  1182. * referenced by <pDataLen> indicates the maximum buffer size available at
  1183. * <pBuffer>.  If the amount of data stored by the previous write exceeds this 
  1184. * value, the operation must return ERROR.  A read must also return ERROR if the 
  1185. * saved timestamp value is 0.  Finally, the read operation must return ERROR if 
  1186. * it is unable to retrieve all the data stored by the write operation or if the
  1187. * previous write was unsuccessful.
  1188. * .IP DHCP_CACHE_ERASE 
  1189. * Ignore all stored data.  Following this operation, subsequent read operations
  1190. * must return ERROR until new data is written.  All parameters except 
  1191. * <command> are NULL.
  1192. * .LP
  1193. *
  1194. * RETURNS: OK, always.
  1195. *
  1196. * ERRNO: N/A
  1197. */
  1198. STATUS dhcpcCacheHookAdd
  1199.     (
  1200.     FUNCPTR  pCacheHookRtn  /* routine to store/retrieve lease data */
  1201.     )
  1202.     {
  1203.     dhcpcCacheHookRtn = pCacheHookRtn;
  1204.     return (OK);
  1205.     }
  1206. /*******************************************************************************
  1207. *
  1208. * dhcpcCacheHookDelete - delete a lease data storage routine
  1209. *
  1210. * This routine deletes the hook used to store lease data, preventing
  1211. * re-use of the configuration parameters across system reboots for
  1212. * all subsequent lease attempts.  Currently active leases will continue
  1213. * to use the routine specified before the lease initialization.
  1214. *
  1215. * RETURNS: OK, always.
  1216. *
  1217. * ERRNO: N/A
  1218. */
  1219. STATUS dhcpcCacheHookDelete (void)
  1220.     {
  1221.     dhcpcCacheHookRtn = NULL;
  1222.     return (OK);
  1223.     }
  1224. /*******************************************************************************
  1225. *
  1226. * dhcpcBind - obtain a set of network configuration parameters with DHCP
  1227. *
  1228. * This routine initiates a DHCP negotiation according to the process described 
  1229. * in RFC 1541.  The <pCookie> argument contains the return value of an earlier 
  1230. * dhcpcInit() call and is used to identify a particular lease.
  1231. *
  1232. * The <syncFlag> parameter specifies whether the DHCP negotiation started by 
  1233. * this routine will execute synchronously or asynchronously.  An asynchronous 
  1234. * execution will return after starting the DHCP negotiation, but a synchronous 
  1235. * execution will only return once the negotiation process completes.
  1236. *
  1237. * When a new lease is established, any event hook provided for the lease
  1238. * will be called to process the configuration parameters.  The hook is also 
  1239. * called when the lease expires or the negotiation process fails.  The results 
  1240. * of an asynchronous DHCP negotiation are not available unless an event hook 
  1241. * is installed.
  1242. *
  1243. * If automatic configuration of the underlying network interface was specified
  1244. * during the lease initialization, this routine will prevent all higher-level 
  1245. * protocols from accessing the underlying network interface used during the 
  1246. * initial lease negotiation until that process is complete.  In addition, any 
  1247. * addressing information obtained will be applied to that network interface, 
  1248. * which will remain disabled if the initial negotiation fails.  Finally, the
  1249. * interface will be disabled if the lease expires.
  1250. *
  1251. * NOTE
  1252. * If the DHCP client is used to obtain the VxWorks boot parameters, this 
  1253. * routine is called automatically during system startup using the automatic 
  1254. * reconfiguration.  Therefore, any calls to this routine which use the network 
  1255. * boot device for message transfer when the DHCP client was used at boot time 
  1256. * must not request automatic reconfiguration during initialization.  Otherwise, 
  1257. * the resulting lease settings will conflict with the configuration maintained 
  1258. * by the lease established during system startup. 
  1259. *
  1260. * RETURNS: OK if routine completes, or ERROR otherwise.
  1261. *
  1262. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED, 
  1263. *        S_dhcpcLib_BAD_OPTION, S_dhcpcLib_BAD_DEVICE
  1264. */
  1265. STATUS dhcpcBind 
  1266.     (
  1267.     void *  pCookie,  /* identifier returned by dhcpcInit() */
  1268.     BOOL  syncFlag  /* synchronous or asynchronous execution */
  1269.     )
  1270.     {
  1271.     int  offset;
  1272.     STATUS result = OK;
  1273.     LEASE_DATA *  pLeaseData = NULL;
  1274.     struct dhcpcOpts *  pOptList;
  1275.     char *  pOptions;
  1276.     struct ifreq  ifr;
  1277.     /*
  1278.      * Use the cookie to access the lease-specific data structures.  For now,
  1279.      * just typecast the cookie.  This translation could be replaced with a more
  1280.      * sophisticated lookup at some point.
  1281.      */
  1282.     pLeaseData = (LEASE_DATA *)pCookie;
  1283.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  1284.         if (dhcpcLeaseList [offset] != NULL &&
  1285.                 dhcpcLeaseList [offset] == pLeaseData)
  1286.             break;
  1287.     if (offset == dhcpcMaxLeases)
  1288.         {
  1289.         errno = S_dhcpcLib_BAD_COOKIE;
  1290.         return (ERROR);
  1291.         }
  1292.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  1293.         {
  1294.         errno = S_dhcpcLib_NOT_INITIALIZED;
  1295.         return (ERROR);
  1296.         }
  1297.     if (syncFlag != TRUE && syncFlag != FALSE)
  1298.         {
  1299.         errno = S_dhcpcLib_BAD_OPTION;
  1300.         return (ERROR);
  1301.         }
  1302.     /* Examine type of DHCP lease to determine action required.  */
  1303.     if (pLeaseData->leaseType == DHCP_BOOTP)
  1304.         {
  1305.         return (OK);    /* BOOTP leases are always valid.  */
  1306.         }
  1307.     /*
  1308.      * Allocate space for any options in outgoing messages
  1309.      * and fill in the options field.
  1310.      */
  1311.     pOptList = pLeaseData->leaseReqSpec.pOptList;
  1312.     if (pOptList != NULL)
  1313.         {
  1314.         pOptions = malloc (pOptList->optlen);
  1315.         if (pOptions == NULL)
  1316.             {
  1317.             errno = S_dhcpcLib_BAD_OPTION;
  1318.             return (ERROR);
  1319.             }
  1320.         pLeaseData->leaseReqSpec.optlen = pOptList->optlen;
  1321.         dhcpcOptFieldCreate (pOptList, pOptions);
  1322.         free (pOptList);
  1323.         pLeaseData->leaseReqSpec.pOptList = NULL;
  1324.         pLeaseData->leaseReqSpec.pOptions = pOptions;
  1325.         }
  1326.     /* Wait for results if the startup lease is being renewed.  */
  1327.     if (pLeaseData->leaseType == DHCP_AUTOMATIC)
  1328.         pLeaseData->waitFlag = TRUE;
  1329.     else
  1330.         pLeaseData->waitFlag = syncFlag;
  1331.     if (pLeaseData->leaseType == DHCP_MANUAL && pLeaseData->leaseGood) 
  1332.         {  
  1333.         /* If redundant bind is requested, change to verification.  */
  1334.         result = dhcpcVerify (pCookie); 
  1335.         return (result);
  1336.         } 
  1337.     else /* Obtain initial lease or renew startup lease.  */ 
  1338.         {
  1339.         /*
  1340.          * Add a filter for incoming DHCP packets and assign the selected
  1341.          * interface to the BPF device.
  1342.          */
  1343.         result = ioctl (pLeaseData->ifData.bpfDev, BIOCSETF, (int)&dhcpread);
  1344.         if (result != 0)
  1345.             {
  1346.             errno = S_dhcpcLib_BAD_DEVICE;
  1347.             return (ERROR);
  1348.             }
  1349.         bzero ( (char *)&ifr, sizeof (struct ifreq));
  1350.         sprintf (ifr.ifr_name, "%s%d", pLeaseData->ifData.iface->if_name,
  1351.                                        pLeaseData->ifData.iface->if_unit);
  1352.         result = ioctl (pLeaseData->ifData.bpfDev, BIOCSETIF, (int)&ifr);
  1353.         if (result != 0)
  1354.             {
  1355.             errno = S_dhcpcLib_BAD_DEVICE;
  1356.             return (ERROR);
  1357.             }
  1358.         dhcp_client (pCookie, TRUE);    /* Perform bind process.  */
  1359.         /* Check results of synchronous lease attempt.  */
  1360.         if (pLeaseData->waitFlag)
  1361.             {
  1362.             pLeaseData->waitFlag = FALSE;    /* Disable further signals.  */
  1363.             semTake (dhcpcMutexSem, WAIT_FOREVER);
  1364.             if (pLeaseData->leaseGood)
  1365.                 result = OK;
  1366.             else
  1367.                 result = ERROR;
  1368.             semGive (dhcpcMutexSem);
  1369.             }
  1370.         else
  1371.             result = OK;
  1372.         }
  1373.     /* 
  1374.      * If waitFlag was TRUE, the negotiation has completed.  Otherwise, it
  1375.      * has begun, and the installed event hook routine will be called at the
  1376.      * appropriate time.
  1377.      */
  1378.     return (result);
  1379.     }
  1380. /*******************************************************************************
  1381. *
  1382. * dhcpcVerify - renew an established lease
  1383. *
  1384. * This routine schedules the lease identified by the <pCookie> parameter
  1385. * for immediate renewal according to the process described in RFC 1541.
  1386. * If the renewal is unsuccessful, the lease negotiation process restarts.
  1387. * The routine is valid as long as the lease is currently active.  The
  1388. * routine is also called automatically in response to a dhcpcBind() call
  1389. * for an existing lease.
  1390. *
  1391. * NOTE
  1392. * This routine is only intended for active leases obtained with the
  1393. * dhcpcBind() routine. It should not be used for parameters resulting
  1394. * from the dhcpcInformGet() routine.
  1395. *
  1396. * NOTE
  1397. * This routine will disable the underlying network interface if the 
  1398. * verification fails and automatic configuration was requested.  This may
  1399. * occur without warning if no event hook is installed.
  1400. *
  1401. * RETURNS: OK if verification scheduled, or ERROR otherwise.
  1402. *
  1403. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED, S_dhcpcLib_NOT_BOUND
  1404. */
  1405. STATUS dhcpcVerify 
  1406.     (
  1407.     void *  pCookie  /* identifier returned by dhcpcInit() */
  1408.     )
  1409.     {
  1410.     int offset;
  1411.     LEASE_DATA *  pLeaseData = NULL;
  1412.     STATUS result = OK;
  1413.     /*
  1414.      * Use the cookie to access the lease-specific data structures.  For now,
  1415.      * just typecast the cookie.  This translation could be replaced with a more
  1416.      * sophisticated lookup at some point.
  1417.      */
  1418.     pLeaseData = (LEASE_DATA *)pCookie;
  1419.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  1420.         if (dhcpcLeaseList [offset] != NULL &&
  1421.                 dhcpcLeaseList [offset] == pLeaseData)
  1422.             break;
  1423.     if (offset == dhcpcMaxLeases)
  1424.         {
  1425.         errno = S_dhcpcLib_BAD_COOKIE;
  1426.         return (ERROR);
  1427.         }
  1428.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  1429.         {
  1430.         errno = S_dhcpcLib_NOT_INITIALIZED;
  1431.         return (ERROR);
  1432.         }
  1433.     semTake (dhcpcMutexSem, WAIT_FOREVER);
  1434.     if (!pLeaseData->leaseGood)
  1435.         result = ERROR;
  1436.     semGive (dhcpcMutexSem);
  1437.     if (result == ERROR)
  1438.         {
  1439.         errno = S_dhcpcLib_NOT_BOUND;
  1440.         return (ERROR);
  1441.         }
  1442.     /* Construct and send a verification request to the client monitor task.  */
  1443.     result = dhcpcEventAdd (DHCP_USER_EVENT, DHCP_USER_VERIFY,
  1444.                             pLeaseData, FALSE);
  1445.     return (result);
  1446.     }
  1447. /*******************************************************************************
  1448. *
  1449. * dhcpcRelease - relinquish specified lease
  1450. *
  1451. * This routine schedules the lease identified by the <pCookie> parameter
  1452. * for immediate release, regardless of time remaining, and removes all
  1453. * the associated data structures.  After the release completes, a new
  1454. * call to dhcpcInit() is required before attempting another lease.
  1455. *
  1456. * NOTE
  1457. * This routine will disable the underlying network interface if automatic 
  1458. * configuration was requested.  This may occur without warning if no event 
  1459. * hook is installed.
  1460. *
  1461. * RETURNS: OK if release scheduled, or ERROR otherwise.
  1462. *
  1463. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED
  1464. *
  1465. */
  1466. STATUS dhcpcRelease
  1467.     (
  1468.     void *  pCookie  /* identifier returned by dhcpcInit() */
  1469.     )
  1470.     {
  1471.     int offset;
  1472.     LEASE_DATA *        pLeaseData = NULL;
  1473.     STATUS result = OK;
  1474.     /*
  1475.      * Use the cookie to access the lease-specific data structures.  For now,
  1476.      * just typecast the cookie.  This translation could be replaced with a more
  1477.      * sophisticated lookup at some point.
  1478.      */
  1479.     pLeaseData = (LEASE_DATA *)pCookie;
  1480.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  1481.         if (dhcpcLeaseList [offset] != NULL &&
  1482.                 dhcpcLeaseList [offset] == pLeaseData)
  1483.             break;
  1484.     if (offset == dhcpcMaxLeases)
  1485.         {
  1486.         errno = S_dhcpcLib_BAD_COOKIE;
  1487.         return (ERROR);
  1488.         }
  1489.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  1490.         {
  1491.         errno = S_dhcpcLib_NOT_INITIALIZED;
  1492.         return (ERROR);
  1493.         }
  1494.     /*
  1495.      * Use the cookie to access the lease-specific data structures.  For now,
  1496.      * just typecast the cookie.  This translation could be replaced with a more
  1497.      * sophisticated lookup at some point.
  1498.      */
  1499.     pLeaseData = (LEASE_DATA *)pCookie;
  1500.     /* Construct and send a release request to the client monitor task.  */
  1501.     result = dhcpcEventAdd (DHCP_USER_EVENT, DHCP_USER_RELEASE,
  1502.                             pLeaseData, FALSE);
  1503.     /* Wait for lease cleanup to complete before returning */
  1504.     if (result == OK)
  1505.         while (dhcpcLeaseList [offset] != NULL)
  1506.             taskDelay (1);
  1507.     return (result);
  1508.     }
  1509. /*******************************************************************************
  1510. *
  1511. * dhcpcInformGet - obtain additional configuration parameters with DHCP
  1512. *
  1513. * This routine uses DHCP to retrieve additional configuration parameters for
  1514. * a client with the externally configured network address given by the
  1515. * <pAddrString> parameter. It sends an INFORM message and waits for a reply
  1516. * following the process described in RFC 2131. The <pCookie> argument contains
  1517. * the return value of an earlier dhcpcInit() call and is used to access the
  1518. * resulting configuration. Unlike the dhcpcBind() call, this routine does not
  1519. * establish a lease with a server.
  1520. *
  1521. * The <syncFlag> parameter specifies whether the message exchange started by 
  1522. * this routine will execute synchronously or asynchronously.  An asynchronous 
  1523. * execution will return after sending the initial message, but a synchronous 
  1524. * execution will only return once the process completes.
  1525. *
  1526. * When a server responds with an acknowledgement message, any event hook
  1527. * provided will be called to process the configuration parameters.  The hook
  1528. * is also called if the message exchange fails.  The results of an asynchronous
  1529. * execution are not available unless an event hook is installed.
  1530. *
  1531. * NOTE
  1532. * This routine is designed as an alternative to the dhcpcBind() routine.
  1533. * It should not be used for any dhcpcInit() identifer corresponding to an
  1534. * active or pending lease.
  1535. *
  1536. * RETURNS: OK if routine completes, or ERROR otherwise.
  1537. *
  1538. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED, S_dhcpcLib_BAD_OPTION
  1539. */
  1540. STATUS dhcpcInformGet
  1541.     (
  1542.     void *  pCookie,  /* identifier returned by dhcpcInit() */
  1543.     char *  pAddrString,  /* known address assigned to client */
  1544.     BOOL  syncFlag  /* synchronous or asynchronous execution? */
  1545.     )
  1546.     {
  1547.     int  offset;
  1548.     STATUS result = OK;
  1549.     LEASE_DATA *  pLeaseData = NULL;
  1550.     struct dhcpcOpts *  pOptList;
  1551.     char *  pOptions;
  1552.     /*
  1553.      * Use the cookie to access the lease-specific data structures.  For now,
  1554.      * just typecast the cookie.  This translation could be replaced with a more
  1555.      * sophisticated lookup at some point.
  1556.      */
  1557.     pLeaseData = (LEASE_DATA *)pCookie;
  1558.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  1559.         if (dhcpcLeaseList [offset] != NULL &&
  1560.                 dhcpcLeaseList [offset] == pLeaseData)
  1561.             break;
  1562.     if (offset == dhcpcMaxLeases)
  1563.         {
  1564.         errno = S_dhcpcLib_BAD_COOKIE;
  1565.         return (ERROR);
  1566.         }
  1567.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  1568.         {
  1569.         errno = S_dhcpcLib_NOT_INITIALIZED;
  1570.         return (ERROR);
  1571.         }
  1572.     if (syncFlag != TRUE && syncFlag != FALSE)
  1573.         {
  1574.         errno = S_dhcpcLib_BAD_OPTION;
  1575.         return (ERROR);
  1576.         }
  1577.     /* Set the requested IP address field to the externally assigned value. */
  1578.     pLeaseData->leaseReqSpec.ipaddr.s_addr = inet_addr (pAddrString);
  1579.     if (pLeaseData->leaseReqSpec.ipaddr.s_addr == -1)
  1580.         {
  1581.         errno = S_dhcpcLib_BAD_OPTION;
  1582.         return (ERROR);
  1583.         }
  1584.     /*
  1585.      * Allocate space for any options in outgoing messages
  1586.      * and fill in the options field.
  1587.      */
  1588.     pOptList = pLeaseData->leaseReqSpec.pOptList;
  1589.     if (pOptList != NULL)
  1590.         {
  1591.         pOptions = malloc (pOptList->optlen);
  1592.         if (pOptions == NULL)
  1593.             {
  1594.             errno = S_dhcpcLib_BAD_OPTION;
  1595.             return (ERROR);
  1596.             }
  1597.         pLeaseData->leaseReqSpec.optlen = pOptList->optlen;
  1598.         dhcpcOptFieldCreate (pOptList, pOptions);
  1599.         free (pOptList);
  1600.         pLeaseData->leaseReqSpec.pOptList = NULL;
  1601.         pLeaseData->leaseReqSpec.pOptions = pOptions;
  1602.         }
  1603.     /* Start the message exchange to get additional parameters. */
  1604.     pLeaseData->waitFlag = syncFlag;
  1605.     dhcp_client (pCookie, FALSE);
  1606.     /* Wait for results of synchronous execution.  */
  1607.     if (pLeaseData->waitFlag)
  1608.         {
  1609.         pLeaseData->waitFlag = FALSE;    /* Disable further signals.  */
  1610.         semTake (dhcpcMutexSem, WAIT_FOREVER);
  1611.         if (pLeaseData->leaseGood)
  1612.             result = OK;
  1613.         else
  1614.             result = ERROR;
  1615.         semGive (dhcpcMutexSem);
  1616.         }
  1617.     else
  1618.         result = OK;
  1619.     /* 
  1620.      * If waitFlag was TRUE, the message exchange has completed.  Otherwise,
  1621.      * it has begun, and the installed event hook routine will be called at
  1622.      * the appropriate time.
  1623.      */
  1624.     return (result);
  1625.     }
  1626. /*******************************************************************************
  1627. *
  1628. * dhcpcShutdown - disable DHCP client library
  1629. *
  1630. * This routine schedules the lease monitor task to clean up memory and exit,
  1631. * after releasing all currently active leases.  The network boot device
  1632. * will be disabled if the DHCP client was used to obtain the VxWorks boot 
  1633. * parameters and the resulting lease is still active.  Any other interfaces 
  1634. * using the addressing information from leases set for automatic configuration
  1635. * will also be disabled.  Notification of a disabled interface will not occur
  1636. * unless an event hook has been installed.  After the processing started by
  1637. * this request completes, the DHCP client library is unavailable until 
  1638. * restarted with the dhcpcLibInit() routine.
  1639. *
  1640. * RETURNS: OK if shutdown scheduled, or ERROR otherwise.
  1641. *
  1642. * ERRNO: S_dhcpcLib_NOT_INITIALIZED
  1643. */
  1644. STATUS dhcpcShutdown (void)
  1645.     {
  1646.     STATUS  result;
  1647.     if (!dhcpcInitialized)
  1648.         {
  1649.         errno = S_dhcpcLib_NOT_INITIALIZED;
  1650.         return (ERROR);
  1651.         }
  1652.     /* Construct and send a shutdown request to the client monitor task.  */
  1653.     result = dhcpcEventAdd (DHCP_USER_EVENT, DHCP_USER_SHUTDOWN, NULL, FALSE);
  1654.     if (result == OK)
  1655.         {
  1656.         /*
  1657.  * Library shutdown pending. Disable user API routines and
  1658.  * remove (local) signal socket indicating start of new session.
  1659.  * Wait for cleanup to complete before indicating that shutdown is
  1660.  * done.
  1661.  */
  1662.         close (dhcpcSignalSock);
  1663. while (dhcpcInitialized)
  1664.     taskDelay (1);
  1665.         }
  1666.     return (result);
  1667.     }
  1668. /*******************************************************************************
  1669. *
  1670. * dhcpcOptionGet - retrieve an option provided to a client and store in a buffer
  1671. *
  1672. * This routine retrieves the data for a specified option from a lease
  1673. * indicated by the <pCookie> parameter. The <option> parameter specifies
  1674. * an option tag as defined in RFC 2132. See the dhcp/dhcp.h include file
  1675. * for a listing of defined aliases for the available option tags. This
  1676. * routine will not accept the following <option> values, which are either
  1677. * used by the server for control purposes or only supplied by the client:
  1678. *
  1679. *     _DHCP_PAD_TAG
  1680. *     _DHCP_REQUEST_IPADDR_TAG
  1681. *     _DHCP_OPT_OVERLOAD_TAG
  1682. *     _DHCP_MSGTYPE_TAG
  1683. *     _DHCP_REQ_LIST_TAG
  1684. *     _DHCP_MAXMSGSIZE_TAG
  1685. *     _DHCP_CLASS_ID_TAG
  1686. *     _DHCP_CLIENT_ID_TAG
  1687. *     _DHCP_END_TAG
  1688. *
  1689. * If the option is found, the data is stored in the provided buffer, up to
  1690. * the limit specified in the <pLength> parameter.  The option is not available
  1691. * if the DHCP client is not in the bound state or if the server did not
  1692. * provide it.  After returning, the <pLength> parameter indicates the amount
  1693. * of data actually retrieved. The provided buffer may contain IP addresses
  1694. * stored in network byte order. All other numeric values are stored in host
  1695. * byte order.  See RFC 2132 for specific details on the data retrieved. 
  1696. * RETURNS: OK if option available, or ERROR otherwise.
  1697. *
  1698. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED, S_dhcpcLib_NOT_BOUND,
  1699. *  S_dhcpcLib_OPTION_NOT_PRESENT
  1700. *
  1701. * SEE ALSO
  1702. * dhcpcOptionSet()
  1703. */
  1704. STATUS dhcpcOptionGet
  1705.     (
  1706.     void *  pCookie,  /* identifier returned by dhcpcInit() */
  1707.     int  option, /* RFC 2132 option tag */
  1708.     int *  pLength,  /* size of provided buffer and data returned */
  1709.     char * pBuf  /* location for option data */
  1710.     )
  1711.     {
  1712.     char * pData;
  1713.     int   amount;
  1714.     int  limit;
  1715.     int  offset;
  1716.     LEASE_DATA *  pLeaseData;
  1717.     limit = *pLength;
  1718.     /*
  1719.      * Use the cookie to access the lease-specific data structures.  For now,
  1720.      * just typecast the cookie.  This translation could be replaced with a more
  1721.      * sophisticated lookup at some point.
  1722.      */
  1723.     pLeaseData = (LEASE_DATA *)pCookie;
  1724.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  1725.         if (dhcpcLeaseList [offset] != NULL && 
  1726.                 dhcpcLeaseList [offset] == pLeaseData)
  1727.             break;
  1728.     if (offset == dhcpcMaxLeases)
  1729.         {
  1730.         errno = S_dhcpcLib_BAD_COOKIE;
  1731.         return (ERROR);
  1732.         }
  1733.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  1734.         {
  1735.         errno = S_dhcpcLib_NOT_INITIALIZED;
  1736.         return (ERROR);
  1737.         }
  1738.     /* Check if client is bound.  */
  1739.     semTake (dhcpcMutexSem, WAIT_FOREVER);
  1740.     if (!pLeaseData->leaseGood)
  1741.         {
  1742.         errno = S_dhcpcLib_NOT_BOUND;
  1743.         semGive (dhcpcMutexSem);
  1744.         return (ERROR);
  1745.         }
  1746.     semGive (dhcpcMutexSem);
  1747.     /* Check if requested parameter is available.  */
  1748.     if (!ISSET (pLeaseData->dhcpcParam->got_option, option))
  1749.         {
  1750.         errno = S_dhcpcLib_OPTION_NOT_PRESENT;
  1751.         return (ERROR);
  1752.         }
  1753.     /* Find the location of option data. Ignores unsupported tag values. */
  1754.     pData = dhcpcOptionFind (pLeaseData, option, &amount);
  1755.     if (pData == NULL)
  1756.         {
  1757.         errno = S_dhcpcLib_OPTION_NOT_PRESENT;
  1758.         return (ERROR);
  1759.         }
  1760.     if (amount == 0)
  1761.         {
  1762.         /* Empty option provided by server - no data returned.  */
  1763.         *pLength = 0;
  1764.         return (OK);
  1765.         }
  1766.     if (amount < limit)         /* Adjust for size of option data.  */
  1767.         limit = amount;
  1768.  
  1769.     bcopy (pData, pBuf, limit);
  1770.     *pLength = limit;
  1771.     return (OK);
  1772.     }
  1773. /*******************************************************************************
  1774. *
  1775. * dhcpcOptionFind - find the requested option
  1776. *
  1777. * This routine returns the address and length of a requested option
  1778. * for use by dhcpcOptionGet(). It should only be called internally.
  1779. * Options which that routine does not support are ignored.
  1780. *
  1781. * RETURNS: Pointer to start of data for option, or NULL if not present.
  1782. *
  1783. * ERRNO: N/A
  1784. *
  1785. * NOMANUAL
  1786. *
  1787. * INTERNAL
  1788. * The <pAmount> parameter is dereferenced unconditionally, but since this
  1789. * routine is only called internally, it is never NULL.
  1790. */
  1791. LOCAL char *dhcpcOptionFind
  1792.     (
  1793.     LEASE_DATA *        pLeaseData,     /* lease-specific data structures */
  1794.     int                 option,         /* RFC 1533 option tag */
  1795.     int *               pAmount         /* Number of bytes for option */
  1796.     )
  1797.     {
  1798.     char *      pData = NULL;   /* Location of option data. */
  1799.     struct dhcp_param *         pDhcpcParam;
  1800.     pDhcpcParam = pLeaseData->dhcpcParam;
  1801.     /*
  1802.      * Only retrieve supported options. Ignore the following:
  1803.      *
  1804.      *     _DHCP_PAD_TAG (0)
  1805.      *     _DHCP_REQUEST_IPADDR_TAG (50)
  1806.      *     _DHCP_OPT_OVERLOAD_TAG (52)
  1807.      *     _DHCP_MSGTYPE_TAG (53)
  1808.      *     _DHCP_REQ_LIST_TAG (55)
  1809.      *     _DHCP_MAXMSGSIZE_TAG (57)
  1810.      *     _DHCP_CLASS_ID_TAG (60)
  1811.      *     _DHCP_CLIENT_ID_TAG (61)
  1812.      *     _DHCP_END_TAG (255)
  1813.      *
  1814.      * Also ignore the two undefined values (62 and 63) and all values
  1815.      * out of the expected range from 1 through 76.
  1816.      */
  1817.     switch (option)
  1818.         {
  1819.         case _DHCP_SUBNET_MASK_TAG:
  1820.             if (pDhcpcParam->subnet_mask != NULL)
  1821.                 {
  1822.                 *pAmount = sizeof (struct in_addr);
  1823.                 pData = (char *)pDhcpcParam->subnet_mask;
  1824.                 }
  1825.             break;
  1826.         case _DHCP_TIME_OFFSET_TAG:
  1827.             *pAmount = sizeof (long);
  1828.             pData = (char *)&pDhcpcParam->time_offset;
  1829.             break;
  1830.         case _DHCP_ROUTER_TAG:
  1831.             if (pDhcpcParam->router != NULL)
  1832.                 {
  1833.                 *pAmount = pDhcpcParam->router->num * sizeof (struct in_addr);
  1834.                 pData = (char *)pDhcpcParam->router->addr;
  1835.                 }
  1836.             break;
  1837.         case _DHCP_TIME_SERVER_TAG:
  1838.             if (pDhcpcParam->time_server != NULL)
  1839.                 {
  1840.                 *pAmount = pDhcpcParam->time_server->num *
  1841.                            sizeof (struct in_addr);
  1842.                 pData = (char *)pDhcpcParam->time_server->addr;
  1843.                 }
  1844.             break;
  1845.         case _DHCP_NAME_SERVER_TAG:
  1846.             if (pDhcpcParam->name_server != NULL)
  1847.                 {
  1848.                 *pAmount = pDhcpcParam->name_server->num *
  1849.                            sizeof (struct in_addr);
  1850.                 pData = (char *)pDhcpcParam->name_server->addr;
  1851.                 }
  1852.             break;
  1853.         case _DHCP_DNS_SERVER_TAG:
  1854.             if (pDhcpcParam->dns_server != NULL)
  1855.                 {
  1856.                 *pAmount = pDhcpcParam->dns_server->num *
  1857.                            sizeof (struct in_addr);
  1858.                 pData = (char *)pDhcpcParam->dns_server->addr;
  1859.                 }
  1860.             break;
  1861.         case _DHCP_LOG_SERVER_TAG:
  1862.             if (pDhcpcParam->log_server != NULL)
  1863.                 {
  1864.                 *pAmount = pDhcpcParam->log_server->num *
  1865.                            sizeof (struct in_addr);
  1866.                 pData = (char *)pDhcpcParam->log_server->addr;
  1867.                 }
  1868.             break;
  1869.         case _DHCP_COOKIE_SERVER_TAG:
  1870.             if (pDhcpcParam->cookie_server != NULL)
  1871.                 {
  1872.                 *pAmount = pDhcpcParam->cookie_server->num *
  1873.                            sizeof (struct in_addr);
  1874.                 pData = (char *)pDhcpcParam->cookie_server->addr;
  1875.                 }
  1876.             break;
  1877.         case _DHCP_LPR_SERVER_TAG:
  1878.             if (pDhcpcParam->lpr_server != NULL)
  1879.                 {
  1880.                 *pAmount = pDhcpcParam->lpr_server->num *
  1881.                            sizeof (struct in_addr);
  1882.                 pData = (char *)pDhcpcParam->lpr_server->addr;
  1883.                 }
  1884.             break;
  1885.         case _DHCP_IMPRESS_SERVER_TAG:
  1886.             if (pDhcpcParam->impress_server != NULL)
  1887.                 {
  1888.                 *pAmount = pDhcpcParam->impress_server->num *
  1889.                            sizeof (struct in_addr);
  1890.                 pData = (char *)pDhcpcParam->impress_server->addr;
  1891.                 }
  1892.             break;
  1893.         case _DHCP_RLS_SERVER_TAG:
  1894.             if (pDhcpcParam->rls_server != NULL)
  1895.                 {
  1896.                 *pAmount = pDhcpcParam->rls_server->num *
  1897.                            sizeof (struct in_addr);
  1898.                 pData = (char *)pDhcpcParam->rls_server->addr;
  1899.                 }
  1900.             break;
  1901.         case _DHCP_HOSTNAME_TAG:
  1902.             *pAmount = strlen (pDhcpcParam->hostname);
  1903.             pData = pDhcpcParam->hostname;
  1904.             break;
  1905.         case _DHCP_BOOTSIZE_TAG:
  1906.             *pAmount = sizeof (unsigned short);
  1907.             pData = (char *)&pDhcpcParam->bootsize;
  1908.             break;
  1909.         case _DHCP_MERIT_DUMP_TAG:
  1910.             *pAmount = strlen (pDhcpcParam->merit_dump);
  1911.             pData = pDhcpcParam->merit_dump;
  1912.             break;
  1913.         case _DHCP_DNS_DOMAIN_TAG:
  1914.             *pAmount = strlen (pDhcpcParam->dns_domain);
  1915.             pData = pDhcpcParam->dns_domain;
  1916.             break;
  1917.         case _DHCP_SWAP_SERVER_TAG:
  1918.             if (pDhcpcParam->swap_server != NULL)
  1919.                 {
  1920.                 *pAmount = sizeof (struct in_addr);
  1921.                 pData = (char *)pDhcpcParam->swap_server;
  1922.                 }
  1923.             break;
  1924.         case _DHCP_ROOT_PATH_TAG:
  1925.             *pAmount = strlen (pDhcpcParam->root_path);
  1926.             pData = pDhcpcParam->root_path;
  1927.             break;
  1928.         case _DHCP_EXTENSIONS_PATH_TAG:
  1929.             *pAmount = strlen (pDhcpcParam->extensions_path);
  1930.             pData = pDhcpcParam->extensions_path;
  1931.             break;
  1932.         case _DHCP_IP_FORWARD_TAG:
  1933.             *pAmount = sizeof (unsigned char);
  1934.             pData = (char *)&pDhcpcParam->ip_forward;
  1935.             break;
  1936.         case _DHCP_NONLOCAL_SRCROUTE_TAG:
  1937.             *pAmount = sizeof (unsigned char);
  1938.             pData = (char *)&pDhcpcParam->nonlocal_srcroute;
  1939.             break;
  1940.         case _DHCP_POLICY_FILTER_TAG:
  1941.             if (pDhcpcParam->policy_filter != NULL)
  1942.                 {
  1943.                 *pAmount = pDhcpcParam->policy_filter->num *
  1944.                            2 * sizeof (struct in_addr);
  1945.                 pData = (char *)pDhcpcParam->policy_filter->addr;
  1946.                 }
  1947.             break;
  1948.         case _DHCP_MAX_DGRAM_SIZE_TAG:
  1949.             *pAmount = sizeof (unsigned short);
  1950.             pData = (char *)&pDhcpcParam->max_dgram_size;
  1951.             break;
  1952.         case _DHCP_DEFAULT_IP_TTL_TAG:
  1953.             *pAmount = sizeof (unsigned char);
  1954.             pData = (char *)&pDhcpcParam->default_ip_ttl;
  1955.             break;
  1956.         case _DHCP_MTU_AGING_TIMEOUT_TAG:
  1957.             *pAmount = sizeof (unsigned long);
  1958.             pData = (char *)&pDhcpcParam->mtu_aging_timeout;
  1959.             break;
  1960.         case _DHCP_MTU_PLATEAU_TABLE_TAG:
  1961.             if (pDhcpcParam->mtu_plateau_table != NULL)
  1962.                 {
  1963.                 *pAmount = pDhcpcParam->mtu_plateau_table->num *
  1964.                            sizeof (unsigned short);
  1965.                 pData = (char *)pDhcpcParam->mtu_plateau_table->shortnum;
  1966.                 }
  1967.             break;
  1968.         case _DHCP_IF_MTU_TAG:
  1969.             *pAmount = sizeof (unsigned short);
  1970.             pData = (char *)&pDhcpcParam->intf_mtu;
  1971.             break;
  1972.         case _DHCP_ALL_SUBNET_LOCAL_TAG:
  1973.             *pAmount = sizeof (unsigned char);
  1974.             pData = (char *)&pDhcpcParam->all_subnet_local;
  1975.             break;
  1976.         case _DHCP_BRDCAST_ADDR_TAG:
  1977.             if (pDhcpcParam->brdcast_addr != NULL)
  1978.                 {
  1979.                 *pAmount = sizeof (struct in_addr);
  1980.                 pData = (char *)pDhcpcParam->brdcast_addr;
  1981.                 }
  1982.             break;
  1983.         case _DHCP_MASK_DISCOVER_TAG:
  1984.             *pAmount = sizeof (unsigned char);
  1985.             pData = (char *)&pDhcpcParam->mask_discover;
  1986.             break;
  1987.         case _DHCP_MASK_SUPPLIER_TAG:
  1988.             *pAmount = sizeof (unsigned char);
  1989.             pData = (char *)&pDhcpcParam->mask_supplier;
  1990.             break;
  1991.         case _DHCP_ROUTER_DISCOVER_TAG:
  1992.             *pAmount = sizeof (unsigned char);
  1993.             pData = (char *)&pDhcpcParam->router_discover;
  1994.             break;
  1995.         case _DHCP_ROUTER_SOLICIT_TAG:
  1996.             if (pDhcpcParam->router_solicit.s_addr != 0)
  1997.                 {
  1998.                 *pAmount = sizeof (struct in_addr);
  1999.                 pData = (char *)&pDhcpcParam->router_solicit;
  2000.                 }
  2001.             break;
  2002.         case _DHCP_STATIC_ROUTE_TAG:
  2003.             if (pDhcpcParam->static_route != NULL)
  2004.                 {
  2005.                 *pAmount = pDhcpcParam->static_route->num *
  2006.                            2 * sizeof (struct in_addr);
  2007.                 pData = (char *)pDhcpcParam->static_route->addr;
  2008.                 }
  2009.             break;
  2010.         case _DHCP_TRAILER_TAG:
  2011.             *pAmount = sizeof (unsigned char);
  2012.             pData = (char *)&pDhcpcParam->trailer;
  2013.             break;
  2014.         case _DHCP_ARP_CACHE_TIMEOUT_TAG:
  2015.             *pAmount = sizeof (unsigned long);
  2016.             pData = (char *)&pDhcpcParam->arp_cache_timeout;
  2017.             break;
  2018.         case _DHCP_ETHER_ENCAP_TAG:
  2019.             *pAmount = sizeof (unsigned char);
  2020.             pData = (char *)&pDhcpcParam->ether_encap;
  2021.             break;
  2022.         case _DHCP_DEFAULT_TCP_TTL_TAG:
  2023.             *pAmount = sizeof (unsigned char);
  2024.             pData = (char *)&pDhcpcParam->default_tcp_ttl;
  2025.             break;
  2026.         case _DHCP_KEEPALIVE_INTERVAL_TAG:
  2027.             *pAmount = sizeof (unsigned long);
  2028.             pData = (char *)&pDhcpcParam->keepalive_inter;
  2029.             break;
  2030.         case _DHCP_KEEPALIVE_GARBAGE_TAG:
  2031.             *pAmount = sizeof (unsigned char);
  2032.             pData = (char *)&pDhcpcParam->keepalive_garba;
  2033.             break;
  2034.         case _DHCP_NIS_DOMAIN_TAG:
  2035.             *pAmount = strlen (pDhcpcParam->nis_domain);
  2036.             pData = pDhcpcParam->nis_domain;
  2037.             break;
  2038.         case _DHCP_NIS_SERVER_TAG:
  2039.             if (pDhcpcParam->nis_server != NULL)
  2040.                 {
  2041.                 *pAmount = pDhcpcParam->nis_server->num *
  2042.                            sizeof (struct in_addr);
  2043.                 pData = (char *)pDhcpcParam->nis_server->addr;
  2044.                 }
  2045.             break;
  2046.         case _DHCP_NTP_SERVER_TAG:
  2047.             if (pDhcpcParam->ntp_server != NULL)
  2048.                 {
  2049.                 *pAmount = pDhcpcParam->ntp_server->num *
  2050.                            sizeof (struct in_addr);
  2051.                 pData = (char *)pDhcpcParam->ntp_server->addr;
  2052.                 }
  2053.             break;
  2054.         case _DHCP_VENDOR_SPEC_TAG:
  2055.             if (pDhcpcParam->vendlist != NULL)
  2056.                 {
  2057.                 *pAmount = pDhcpcParam->vendlist->len;
  2058.                 pData = pDhcpcParam->vendlist->list;
  2059.                 }
  2060.             break;
  2061.         case _DHCP_NBN_SERVER_TAG:
  2062.             if (pDhcpcParam->nbn_server != NULL)
  2063.                 {
  2064.                 *pAmount = pDhcpcParam->nbn_server->num *
  2065.                            sizeof (struct in_addr);
  2066.                 pData = (char *)pDhcpcParam->nbn_server->addr;
  2067.                 }
  2068.             break;
  2069.         case _DHCP_NBDD_SERVER_TAG:
  2070.             if (pDhcpcParam->nbdd_server != NULL)
  2071.                 {
  2072.                 *pAmount = pDhcpcParam->nbdd_server->num *
  2073.                            sizeof (struct in_addr);
  2074.                 pData = (char *)pDhcpcParam->nbdd_server->addr;
  2075.                 }
  2076.             break;
  2077.         case _DHCP_NB_NODETYPE_TAG:
  2078.             *pAmount = sizeof (unsigned char);
  2079.             pData = (char *)&pDhcpcParam->nb_nodetype;
  2080.             break;
  2081.         case _DHCP_NB_SCOPE_TAG:
  2082.             *pAmount = strlen (pDhcpcParam->nb_scope);
  2083.             pData = pDhcpcParam->nb_scope;
  2084.             break;
  2085.         case _DHCP_XFONT_SERVER_TAG:
  2086.             if (pDhcpcParam->xfont_server != NULL)
  2087.                 {
  2088.                 *pAmount = pDhcpcParam->xfont_server->num *
  2089.                            sizeof (struct in_addr);
  2090.                 pData = (char *)pDhcpcParam->xfont_server->addr;
  2091.                 }
  2092.             break;
  2093.         case _DHCP_XDISPLAY_MANAGER_TAG:
  2094.             if (pDhcpcParam->xdisplay_manager != NULL)
  2095.                 {
  2096.                 *pAmount = pDhcpcParam->xdisplay_manager->num *
  2097.                            sizeof (struct in_addr);
  2098.                 pData = (char *)pDhcpcParam->xdisplay_manager->addr;
  2099.                 }
  2100.             break;
  2101.         case _DHCP_LEASE_TIME_TAG:
  2102.             *pAmount = sizeof (unsigned long);
  2103.             pData = (char *)&pDhcpcParam->lease_duration;
  2104.             break;
  2105.         case _DHCP_SERVER_ID_TAG:
  2106.             *pAmount = sizeof (struct in_addr);
  2107.             pData = (char *)&pDhcpcParam->server_id;
  2108.             break;
  2109.         case _DHCP_ERRMSG_TAG:
  2110.             *pAmount = strlen (pDhcpcParam->errmsg);
  2111.             pData = pDhcpcParam->errmsg;
  2112.             break;
  2113.         case _DHCP_T1_TAG:
  2114.             *pAmount = sizeof (unsigned long);
  2115.             pData = (char *)&pDhcpcParam->dhcp_t1;
  2116.             break;
  2117.         case _DHCP_T2_TAG:
  2118.             *pAmount = sizeof (unsigned long);
  2119.             pData = (char *)&pDhcpcParam->dhcp_t2;
  2120.             break;
  2121.         case _DHCP_NISP_DOMAIN_TAG:
  2122.             *pAmount = strlen (pDhcpcParam->nisp_domain);
  2123.             pData = pDhcpcParam->nisp_domain;
  2124.             break;
  2125.         case _DHCP_NISP_SERVER_TAG:
  2126.             if (pDhcpcParam->nisp_server != NULL)
  2127.                 {
  2128.                 *pAmount = pDhcpcParam->nisp_server->num *
  2129.                            sizeof (struct in_addr);
  2130.                 pData = (char *)pDhcpcParam->nisp_server->addr;
  2131.                 }
  2132.             break;
  2133.       
  2134. case _DHCP_TFTP_SERVERNAME_TAG:
  2135.             *pAmount = sizeof (struct in_addr);
  2136.             pData = (char *)&pDhcpcParam->siaddr;
  2137.     break;
  2138. case _DHCP_BOOTFILE_TAG:
  2139.     *pAmount = strlen (pDhcpcParam->file);
  2140.     pData = pDhcpcParam->file;
  2141.     break;
  2142.         case _DHCP_MOBILEIP_HA_TAG:
  2143.             if (pDhcpcParam->mobileip_ha != NULL)
  2144.                 {
  2145.                 *pAmount = pDhcpcParam->mobileip_ha->num *
  2146.                            sizeof (struct in_addr);
  2147.                 pData = (char *)pDhcpcParam->mobileip_ha->addr;
  2148.                 }
  2149.             break;
  2150.         case _DHCP_SMTP_SERVER_TAG:
  2151.             if (pDhcpcParam->smtp_server != NULL)
  2152.                 {
  2153.                 *pAmount = pDhcpcParam->smtp_server->num *
  2154.                            sizeof (struct in_addr);
  2155.                 pData = (char *)pDhcpcParam->smtp_server->addr;
  2156.                 }
  2157.             break;
  2158.         case _DHCP_POP3_SERVER_TAG:
  2159.             if (pDhcpcParam->pop3_server != NULL)
  2160.                 {
  2161.                 *pAmount = pDhcpcParam->pop3_server->num *
  2162.                            sizeof (struct in_addr);
  2163.                 pData = (char *)pDhcpcParam->pop3_server->addr;
  2164.                 }
  2165.             break;
  2166.         case _DHCP_NNTP_SERVER_TAG:
  2167.             if (pDhcpcParam->nntp_server != NULL)
  2168.                 {
  2169.                 *pAmount = pDhcpcParam->nntp_server->num *
  2170.                            sizeof (struct in_addr);
  2171.                 pData = (char *)pDhcpcParam->nntp_server->addr;
  2172.                 }
  2173.             break;
  2174.         case _DHCP_DFLT_WWW_SERVER_TAG:
  2175.             if (pDhcpcParam->dflt_www_server != NULL)
  2176.                 {
  2177.                 *pAmount = pDhcpcParam->dflt_www_server->num *
  2178.                            sizeof (struct in_addr);
  2179.                 pData = (char *)pDhcpcParam->dflt_www_server->addr;
  2180.                 }
  2181.             break;
  2182.         case _DHCP_DFLT_FINGER_SERVER_TAG:
  2183.             if (pDhcpcParam->dflt_finger_server != NULL)
  2184.                 {
  2185.                 *pAmount = pDhcpcParam->dflt_finger_server->num *
  2186.                            sizeof (struct in_addr);
  2187.                 pData = (char *)pDhcpcParam->dflt_finger_server->addr;
  2188.                 }
  2189.             break;
  2190.         case _DHCP_DFLT_IRC_SERVER_TAG:
  2191.             if (pDhcpcParam->dflt_irc_server != NULL)
  2192.                 {
  2193.                 *pAmount = pDhcpcParam->dflt_irc_server->num *
  2194.                            sizeof (struct in_addr);
  2195.                 pData = (char *)pDhcpcParam->dflt_irc_server->addr;
  2196.                 }
  2197.             break;
  2198.         case _DHCP_STREETTALK_SERVER_TAG:
  2199.             if (pDhcpcParam->streettalk_server != NULL)
  2200.                 {
  2201.                 *pAmount = pDhcpcParam->streettalk_server->num *
  2202.                            sizeof (struct in_addr);
  2203.                 pData = (char *)pDhcpcParam->streettalk_server->addr;
  2204.                 }
  2205.             break;
  2206.         case _DHCP_STDA_SERVER_TAG:
  2207.             if (pDhcpcParam->stda_server != NULL)
  2208.                 {
  2209.                 *pAmount = pDhcpcParam->stda_server->num *
  2210.                            sizeof (struct in_addr);
  2211.                 pData = (char *)pDhcpcParam->stda_server->addr;
  2212.                 }
  2213.             break;
  2214.         default:
  2215.             break;
  2216.         }
  2217.     return (pData);
  2218.     }
  2219. /*******************************************************************************
  2220. *
  2221. * dhcpcServerGet - retrieve the current DHCP server
  2222. *
  2223. * This routine returns the DHCP server that supplied the configuration
  2224. * parameters for the lease specified by the <pCookie> argument.  This 
  2225. * information is available only if the lease is in the bound state.
  2226. *
  2227. * RETURNS: OK if in bound state and server available, or ERROR otherwise.
  2228. *
  2229. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED, S_dhcpcLib_NOT_BOUND
  2230. */
  2231. STATUS dhcpcServerGet
  2232.     (
  2233.     void *  pCookie,  /* identifier returned by dhcpcInit() */
  2234.     struct in_addr *  pServerAddr  /* location for address of server */
  2235.     )
  2236.     {
  2237.     int offset;
  2238.     LEASE_DATA *  pLeaseData;
  2239.     STATUS  result = OK;
  2240.     /*
  2241.      * Use the cookie to access the lease-specific data structures.  For now,
  2242.      * just typecast the cookie.  This translation could be replaced with a more
  2243.      * sophisticated lookup at some point.
  2244.      */
  2245.     pLeaseData = (LEASE_DATA *)pCookie;
  2246.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  2247.         if (dhcpcLeaseList [offset] != NULL &&
  2248.                 dhcpcLeaseList [offset] == pLeaseData)
  2249.             break;
  2250.     if (offset == dhcpcMaxLeases)
  2251.         {
  2252.         errno = S_dhcpcLib_BAD_COOKIE;
  2253.         return (ERROR);
  2254.         }
  2255.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  2256.         {
  2257.         errno = S_dhcpcLib_NOT_INITIALIZED;
  2258.         return (ERROR);
  2259.         }
  2260.     semTake (dhcpcMutexSem, WAIT_FOREVER);
  2261.     if (!pLeaseData->leaseGood)
  2262.         result = ERROR;
  2263.     semGive (dhcpcMutexSem);
  2264.     if (result == ERROR)
  2265.         {
  2266.         errno = S_dhcpcLib_NOT_BOUND;
  2267.         return (ERROR);
  2268.         }
  2269.     if (pLeaseData->dhcpcParam->server_id.s_addr != 0)
  2270.         bcopy ( (char *)&pLeaseData->dhcpcParam->server_id, 
  2271.                (char *)pServerAddr, sizeof (struct in_addr));
  2272.     else 
  2273.         result = ERROR;
  2274.     return (result);
  2275.     }
  2276. /*******************************************************************************
  2277. *
  2278. * dhcpcTimerGet - retrieve current lease timers
  2279. *
  2280. * This routine returns the number of clock ticks remaining on the timers
  2281. * governing the DHCP lease specified by the <pCookie> argument.  This 
  2282. * information is only available if the lease is in the bound state.
  2283. * Therefore, this routine will return ERROR if a BOOTP reply was accepted.
  2284. *
  2285. * RETURNS: OK if in bound state and values available, or ERROR otherwise.
  2286. *
  2287. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED, S_dhcpcLib_NOT_BOUND, 
  2288. *  S_dhcpcLib_OPTION_NOT_PRESENT, S_dhcpcLib_TIMER_ERROR
  2289. */
  2290. STATUS dhcpcTimerGet
  2291.     (
  2292.     void *  pCookie,  /* identifier returned by dhcpcInit() */
  2293.     int *  pT1,  /* time until lease renewal */
  2294.     int *  pT2  /* time until lease rebinding */
  2295.     )
  2296.     {
  2297.     int  offset;
  2298.     time_t current = 0;
  2299.     long timer1;
  2300.     long timer2;
  2301.     LEASE_DATA *        pLeaseData;
  2302.     STATUS  result = OK;
  2303.     /*
  2304.      * Use the cookie to access the lease-specific data structures.  For now,
  2305.      * just typecast the cookie.  This translation could be replaced with a more
  2306.      * sophisticated lookup at some point.
  2307.      */
  2308.     pLeaseData = (LEASE_DATA *)pCookie;
  2309.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  2310.         if (dhcpcLeaseList [offset] != NULL &&
  2311.                 dhcpcLeaseList [offset] == pLeaseData)
  2312.             break;
  2313.     if (offset == dhcpcMaxLeases)
  2314.         {
  2315.         errno = S_dhcpcLib_BAD_COOKIE;
  2316.         return (ERROR);
  2317.         }
  2318.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  2319.         {
  2320.         errno = S_dhcpcLib_NOT_INITIALIZED;
  2321.         return (ERROR);
  2322.         }
  2323.     if (pLeaseData->leaseType == DHCP_BOOTP)
  2324.         {
  2325. #ifdef DHCPC_DEBUG
  2326.         logMsg ("No timer values: BOOTP reply accepted.n", 0, 0, 0, 0, 0, 0);
  2327. #endif
  2328.         errno = S_dhcpcLib_OPTION_NOT_PRESENT;
  2329.         return (ERROR);
  2330.         }
  2331.     if (dhcpTime (&current) == -1)
  2332.         {
  2333. #ifdef DHCPC_DEBUG
  2334.         logMsg ("time() error in dhcpTimerGet().n", 0, 0, 0, 0, 0, 0);
  2335. #endif
  2336.         errno = S_dhcpcLib_TIMER_ERROR;
  2337.         return (ERROR);
  2338.         }
  2339.     semTake (dhcpcMutexSem, WAIT_FOREVER);
  2340.     if (!pLeaseData->leaseGood)
  2341.         result = ERROR;
  2342.     semGive (dhcpcMutexSem);
  2343.     if (result == ERROR)
  2344.         {
  2345.         errno = S_dhcpcLib_NOT_BOUND;
  2346.         return (ERROR);
  2347.         }
  2348.     timer1 = pLeaseData->dhcpcParam->lease_origin + 
  2349.                  pLeaseData->dhcpcParam->dhcp_t1 - current;
  2350.     timer2 = pLeaseData->dhcpcParam->lease_origin + 
  2351.                  pLeaseData->dhcpcParam->dhcp_t2 - current;
  2352.     if (timer1 < 0)
  2353.         timer1 = 0;   
  2354.     if (timer2 < 0)
  2355.         timer2 = 0;
  2356.     *pT1 = timer1 * sysClkRateGet();
  2357.     *pT2 = timer2 * sysClkRateGet();
  2358.     return (OK);
  2359.     }
  2360. /*******************************************************************************
  2361. *
  2362. * dhcpcParamsGet - retrieve current configuration parameters
  2363. *
  2364. * This routine copies the current configuration parameters for the lease
  2365. * specified by the <pCookie> argument to the user-supplied and allocated 
  2366. * 'dhcp_param' structure referenced in <pParamList>.  Within this structure,  
  2367. * defined in 'h/dhcp/dhcpc.h', you should supply buffer pointers for the 
  2368. * parameters that interest you.  Set all other structure members to zero.  
  2369. * When dhcpcParamsGet() returns, the buffers you specified in the submitted 
  2370. * 'dhcpc_param' structure will contain the information you requested.  
  2371. * This assumes that the specified lease is in the bound state and that 
  2372. * DHCP knows that the lease parameters are good.
  2373. *
  2374. * NOTE: The 'temp_sname' and 'temp_file' members of the 'dhcp_param' 
  2375. * structure are for internal use only.  They reference temporary buffers for 
  2376. * options that are passed using the 'sname' and 'file' members.  Do not 
  2377. * request either 'temp_sname' or 'temp_file'.  Instead, request either 
  2378. * 'sname' or 'file' if you want those parameters.  
  2379. *
  2380. * Many of the parameters within the user-supplied structure use one of the 
  2381. * following secondary data types: 'struct in_addrs', 'struct u_shorts', and 
  2382. * 'struct vendor_list'.  Each of those structures accepts a length designation 
  2383. * and a data pointer.  For the first two data types, the 'num' member indicates 
  2384. * the size of the buffer in terms of the number of underlying elements.  For 
  2385. * example, the STATIC_ROUTE option returns one or more IP address pairs.  Thus, 
  2386. * setting the 'num' member to 2 in the 'static_route' entry would indicate that 
  2387. * the corresponding buffer contained 16 bytes.  By contrast, the 'len' member 
  2388. * in the struct 'vendor_list' data type consists of the buffer size, in bytes.
  2389. * See RFC 1533 for specific details on the types of data for each option. 
  2390. * On return, each of the length designators are set to indicate the amount of
  2391. * data returned.  For instance, the 'num' member in the static_route entry could
  2392. * be set to 1 to indicate that only one IP address pair of 8 bytes was 
  2393. * available.
  2394. *
  2395. * RETURNS: OK if in bound state, or ERROR otherwise.
  2396. *
  2397. * ERRNO: S_dhcpcLib_BAD_COOKIE, S_dhcpcLib_NOT_INITIALIZED, S_dhcpcLib_NOT_BOUND
  2398. *
  2399. */
  2400. STATUS dhcpcParamsGet
  2401.     (
  2402.     void *  pCookie,  /* identifier returned by dhcpcInit() */
  2403.     struct dhcp_param * pParamList /* requested parameters */
  2404.     )
  2405.     {
  2406.     int offset;
  2407.     LEASE_DATA *        pLeaseData;
  2408.     STATUS  result = OK;
  2409.     /*
  2410.      * Use the cookie to access the lease-specific data structures.  For now,
  2411.      * just typecast the cookie.  This translation could be replaced with a more
  2412.      * sophisticated lookup at some point.
  2413.      */
  2414.     pLeaseData = (LEASE_DATA *)pCookie;
  2415.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  2416.         if (dhcpcLeaseList [offset] != NULL &&
  2417.                 dhcpcLeaseList [offset] == pLeaseData)
  2418.             break;
  2419.     if (offset == dhcpcMaxLeases)
  2420.         {
  2421.         errno = S_dhcpcLib_BAD_COOKIE;
  2422.         return (ERROR);
  2423.         }
  2424.     if (!dhcpcInitialized || !pLeaseData->initFlag)
  2425.         {
  2426.         errno = S_dhcpcLib_NOT_INITIALIZED;
  2427.         return (ERROR);
  2428.         }
  2429.     semTake (dhcpcMutexSem, WAIT_FOREVER);
  2430.     if (!pLeaseData->leaseGood)
  2431.         result = ERROR;
  2432.     semGive (dhcpcMutexSem);
  2433.     if (result == ERROR)
  2434.         {
  2435.         errno = S_dhcpcLib_NOT_BOUND;
  2436.         return (ERROR);
  2437.         }
  2438.     dhcpcParamsCopy (pLeaseData, pParamList);
  2439.     return (OK);
  2440.     }
  2441. /*******************************************************************************
  2442. *
  2443. * dhcpcState - monitor all DHCP client activity
  2444. *
  2445. * This routine establishes and monitors all runtime DHCP leases. It is not
  2446. * used by the DHCP client when executing at boot time. The routine receives
  2447. * all DHCP event notifications (message arrivals, timeouts, and user requests),
  2448. * and controls the event processing by invoking the appropriate routines.
  2449. * It is the entry point for the monitor task created during the library
  2450. * initialization and should only be called internally.
  2451. *
  2452. * RETURNS: N/A
  2453. *
  2454. * ERRNO: N/A
  2455. *
  2456. * NOMANUAL
  2457. */
  2458. LOCAL void dhcpcState (void)
  2459.     {
  2460.     int offset;
  2461.     EVENT_DATA  newEvent;
  2462.     STATUS      result;
  2463.     FOREVER
  2464.         {
  2465.         /* Wait for an incoming DHCP message, user request, or timeout. */
  2466.         result = dhcpcEventGet (&newEvent);
  2467.         if (result == ERROR)
  2468.             {
  2469.             /* Invalid or missing event - ignore. */
  2470.             continue;
  2471.             }
  2472.         /* Handle dhcpcShutdown() requests. */
  2473.         if (newEvent.source == DHCP_USER_EVENT &&
  2474.                 newEvent.type == DHCP_USER_SHUTDOWN)
  2475.             {
  2476.             /* Release all active leases, free all memory, and exit. */
  2477.             newEvent.type = DHCP_USER_RELEASE;
  2478.             for (offset = 0; offset < dhcpcMaxLeases; offset++)
  2479.                 {
  2480.                 if (dhcpcLeaseList [offset] != NULL)
  2481.                     {
  2482.                     newEvent.leaseId = dhcpcLeaseList [offset];
  2483.                     dhcpcEventHandle (&newEvent);
  2484.                     dhcpcLeaseList [offset] = NULL;
  2485.                     }
  2486.                 }
  2487.             dhcpcCleanup ();
  2488.             break;
  2489.             }
  2490.         /* Process all other events in the context of the target lease. */
  2491.         result = dhcpcEventHandle (&newEvent);
  2492.         if (result == DHCPC_DONE)
  2493.             {
  2494.             /* Set the list entry to NULL when a lease is removed. */
  2495.             for (offset = 0; offset < dhcpcMaxLeases; offset++)
  2496.                 {
  2497.                 if (dhcpcLeaseList [offset] == newEvent.leaseId)
  2498.                     {
  2499.                     dhcpcLeaseList [offset] = NULL;
  2500.                     break;
  2501.                     }
  2502.                 }
  2503.             }
  2504.         }
  2505.     /* The monitor task only returns in response to a dhcpcShutdown() call. */
  2506.     return;
  2507.     }
  2508. /*******************************************************************************
  2509. *
  2510. * dhcpcEventGet - wait for a DHCP event
  2511. *
  2512. * This routine retrieves DHCP events for processing by the monitor task.
  2513. * If the contents of the event descriptor are valid, it is stored in the
  2514. * buffer provided by the <pNewEvent> parameter. Automatic event descriptors
  2515. * are created when a DHCP message arrives or a timeout expires. Manual
  2516. * event descriptors are generated by calls to the dhcpBind(), dhcpVerify(),
  2517. * dhcpRelease() and dhcpShutdown() routines.
  2518. *
  2519. * RETURNS: OK if valid event retrieved, or ERROR otherwise.
  2520. *
  2521. * ERRNO: N/A
  2522. *
  2523. * NOMANUAL
  2524. */
  2525. LOCAL STATUS dhcpcEventGet
  2526.     (
  2527.     EVENT_DATA *        pNewEvent       /* pointer to event descriptor */
  2528.     )
  2529.     {
  2530.     STATUS      result;
  2531.     int         status;
  2532.     int         offset;
  2533.     LEASE_DATA *        pLeaseData;
  2534.     /* Wait for event occurrence. */
  2535.     semTake (dhcpcEventSem, WAIT_FOREVER);
  2536.     /* Retrieve event from message ring. */
  2537.     if (rngIsEmpty (dhcpcEventRing) == TRUE)
  2538.         {
  2539. #ifdef DHCPC_DEBUG
  2540.         logMsg ("dhcpcEventGet: Notification empty.n", 0, 0, 0, 0, 0, 0);
  2541. #endif
  2542.         return (ERROR);
  2543.         }
  2544.     status = rngBufGet (dhcpcEventRing, (char *)pNewEvent, sizeof (EVENT_DATA));
  2545.     if (status != sizeof (EVENT_DATA))
  2546.         {
  2547. #ifdef DHCPC_DEBUG
  2548.         logMsg ("dhcpcEventGet: Notification error.n", 0, 0, 0, 0, 0, 0);
  2549. #endif
  2550.         return (ERROR);
  2551.         }
  2552.     /*
  2553.      * Check event descriptor for valid data. The primary purpose of
  2554.      * this code is to catalog all the possible event descriptors
  2555.      * in one location, since invalid data could only result from a failure
  2556.      * in memory-to-memory copies by the ring buffers, which is extremely
  2557.      * unlikely. Even if that occurred, the DHCP protocol is designed to
  2558.      * handle any errors in message arrival notifications as a byproduct of
  2559.      * UDP processing, but corruption of timeout or user events could result
  2560.      * in unrecoverable errors.
  2561.      */
  2562.     result = OK;
  2563.     switch (pNewEvent->source)
  2564.         {
  2565.         case DHCP_AUTO_EVENT:   /* Validate automatic event types. */
  2566.             if (pNewEvent->type != DHCP_TIMEOUT &&
  2567.                     pNewEvent->type != DHCP_MSG_ARRIVED)
  2568.                 {
  2569.                 result = ERROR;
  2570.                 }
  2571.             break;
  2572.         case DHCP_USER_EVENT:    /* Validate manual event types. */
  2573.             if (pNewEvent->type != DHCP_USER_INFORM &&
  2574.                     pNewEvent->type != DHCP_USER_BIND &&
  2575.                     pNewEvent->type != DHCP_USER_VERIFY &&
  2576.                     pNewEvent->type != DHCP_USER_RELEASE &&
  2577.                     pNewEvent->type != DHCP_USER_SHUTDOWN)
  2578.                 {
  2579.                 result = ERROR;
  2580.                 }
  2581.             break;
  2582.         default:    /* Unknown event class. */
  2583.             result = ERROR;
  2584.             break;
  2585.         }
  2586.     if (result == ERROR)
  2587.         return (ERROR);
  2588.     /* Lease identifiers must be checked for all events except shutdown. */
  2589.     if (pNewEvent->source == DHCP_USER_EVENT &&
  2590.             pNewEvent->type == DHCP_USER_SHUTDOWN)
  2591.         return (OK);
  2592.     /*
  2593.      * Although not likely, a lease could be released between the
  2594.      * arrival of an event and the event processing. In that case,
  2595.      * the recorded lease identifier will be invalid. Ignore those events.
  2596.      */
  2597.     pLeaseData = pNewEvent->leaseId;
  2598.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  2599.         if (dhcpcLeaseList [offset] != NULL &&
  2600.                 dhcpcLeaseList [offset] == pLeaseData)
  2601.             break;
  2602.     if (offset == dhcpcMaxLeases)
  2603.         return (ERROR);
  2604.     return (result);
  2605.     }
  2606. /*******************************************************************************
  2607. *
  2608. * dhcpcEventHandle - process a DHCP event for a particular lease
  2609. *
  2610. * This routine executes a portion of the DHCP client finite state machine
  2611. * until a DHCP message is sent and/or the relevant timeouts are set. It
  2612. * processes all incoming DHCP messages, timeouts, and all user requests
  2613. * except for the dhcpcShutdown() routine. All handled events are processed
  2614. * in the context of the current state of a known lease. It is invoked by the
  2615. * monitor task when the events occur, and should only be called internally.
  2616. *
  2617. * RETURNS: OK if processing completed, or ERROR if it fails.
  2618. *
  2619. * ERRNO: N/A
  2620. *
  2621. * NOMANUAL
  2622. */
  2623. LOCAL STATUS dhcpcEventHandle
  2624.     (
  2625.     EVENT_DATA *        pNewEvent       /* pointer to event descriptor */
  2626.     )
  2627.     {
  2628.     STATUS              result;
  2629.     LEASE_DATA *        pLeaseData;
  2630.     /*
  2631.      * Use the cookie to access the lease-specific data structures. For now,
  2632.      * just typecast the cookie. This translation could be replaced with a more
  2633.      * sophisticated lookup at some point.
  2634.      */
  2635.     pLeaseData = (LEASE_DATA *)pNewEvent->leaseId;
  2636.     /*
  2637.      * For new messages, set the data pointer for the lease to access
  2638.      * the next DHCP message in the data buffer filled by the read task.
  2639.      */
  2640.     if (pNewEvent->source == DHCP_AUTO_EVENT &&
  2641.             pNewEvent->type == DHCP_MSG_ARRIVED)
  2642.         {
  2643.         pLeaseData->msgBuffer = pNewEvent->pMsg;
  2644.         }
  2645.     /*
  2646.      * Execute routines from the state machine until processing is complete.
  2647.      * In general, all processing is performed by a single routine. If
  2648.      * additional routines are needed, the called routine returns DHCPC_MORE,
  2649.      * and the next routine is executed immediately. Processing always stops
  2650.      * once the occurrence of a subsequent timeout or message arrival is
  2651.      * guaranteed. The processing routine returns OK at that point, allowing
  2652.      * the monitor task to handle the next event. If a routine returns
  2653.      * ERROR, the state machine for the lease is reset to the initial state.
  2654.      * Finally, a routine returns DHCPC_DONE after releasing its lease and
  2655.      * removing the data structures.
  2656.      */
  2657.     result = DHCPC_MORE;
  2658.     while (result == DHCPC_MORE)
  2659.         {
  2660.         result = (*fsm [pLeaseData->currState]) (pNewEvent);
  2661.         /*
  2662.          * Reset any lease message pointer to prevent further access to the
  2663.          * data buffer. Mark that buffer available after handling the last
  2664.          * DHCP message.
  2665.          */
  2666.         if (pNewEvent->source == DHCP_AUTO_EVENT &&
  2667.                 pNewEvent->type == DHCP_MSG_ARRIVED)
  2668.             {
  2669.             pLeaseData->msgBuffer = NULL;
  2670.             if (pNewEvent->lastFlag)
  2671.                 dhcpcMessageList [pNewEvent->slot].writeFlag = TRUE;
  2672.             }
  2673.         if (result == ERROR)
  2674.             {
  2675. #ifdef DHCPC_DEBUG
  2676.             logMsg ("Error in finite state machine.n", 0, 0, 0, 0, 0, 0);
  2677. #endif
  2678.             if (pLeaseData->prevState == INFORMING)
  2679.                 {
  2680.                 /*
  2681.                  * Signal the (failed) completion of the message exchange
  2682.                  * if the dhcpcInformGet() routine is executing synchronously.
  2683.                  * No additional parameters are available.
  2684.                  */
  2685.                 if (pLeaseData->waitFlag)
  2686.                     semGive (pLeaseData->leaseSem);
  2687.                 /* Send a failure notification to any event hook routine. */
  2688.                 if (pLeaseData->eventHookRtn != NULL)
  2689.                     result = (* pLeaseData->eventHookRtn) (DHCPC_LEASE_INVALID,
  2690.                                                            pNewEvent->leaseId);
  2691.                 return (ERROR);
  2692.                 }
  2693.             /* Lease negotiation failed - set to execute init() routine. */
  2694.             pLeaseData->prevState = DHCPC_ERROR;
  2695.             pLeaseData->currState = INIT;
  2696.             /* Disable the underlying network interface if necessary. */
  2697.             if (pLeaseData->autoConfig ||
  2698.                     pLeaseData->leaseType == DHCP_AUTOMATIC)
  2699.                 {
  2700.                 down_if (&pLeaseData->ifData);
  2701.                 }
  2702.             /*
  2703.              * Signal the (failed) completion of the negotiation process
  2704.              * if the dhcpcBind() call is executing synchronously.
  2705.              */
  2706.             if (pLeaseData->waitFlag)
  2707.                 semGive (pLeaseData->leaseSem);
  2708.             /* Send a notification of the failure to any event hook routine. */
  2709.             if (pLeaseData->eventHookRtn != NULL)
  2710.                 result = (* pLeaseData->eventHookRtn) (DHCPC_LEASE_INVALID,
  2711.                                                        pNewEvent->leaseId);
  2712.             return (ERROR);
  2713.             }
  2714.         /*
  2715.          * When a lease entry is removed, return an indicator to the monitor
  2716.          * task so that is will reset the corresponding list entry to NULL.
  2717.          */
  2718.         if (result == DHCPC_DONE)
  2719.             return (DHCPC_DONE);
  2720.         if (pLeaseData->currState == BOUND && pLeaseData->prevState != BOUND)
  2721.             {
  2722.             /* Suspend filtering with the BPF device until timers expire. */
  2723.             ioctl (pLeaseData->ifData.bpfDev, BIOCSTOP, 0);
  2724.             /*
  2725.              * Signal the successful completion of the negotiation
  2726.              * process if the dhcpBind() call is executing synchronously.
  2727.              */
  2728.             if (pLeaseData->waitFlag)
  2729.                 semGive (pLeaseData->leaseSem);
  2730.             /* Set the bound routine to exit after starting the timer. */
  2731.             pNewEvent->type = DHCPC_STATE_BEGIN;
  2732.             }
  2733. #ifdef DHCPC_DEBUG
  2734.         logMsg ("Next state= %dn", pLeaseData->currState, 0, 0, 0, 0, 0);
  2735. #endif
  2736.         }
  2737.     return (OK);
  2738.     }
  2739. /******************************************************************************
  2740. *
  2741. * dhcpcLeaseCleanup - remove data structures used by a DHCP lease
  2742. *
  2743. * This routine removes all lease-specific data structures accessed by the
  2744. * <pLeaseData> parameter. It is called internally when a lease is relinquished
  2745. * by the user with the dhcpcRelease() routine and when the DHCP client
  2746. * library is disabled with dhcpcShutdown().
  2747. *
  2748. * RETURNS: N/A
  2749. *
  2750. * ERRNO: N/A
  2751. *
  2752. * NOMANUAL
  2753. */
  2754. void dhcpcLeaseCleanup
  2755.     (
  2756.     LEASE_DATA *        pLeaseData      /* lease-specific status information */
  2757.     )
  2758.     {
  2759.     int offset;
  2760.     wdCancel (pLeaseData->timer);
  2761.     wdDelete (pLeaseData->timer);
  2762.     close (pLeaseData->ifData.bpfDev);
  2763.     semDelete (pLeaseData->leaseSem);
  2764.     if (pLeaseData->leaseReqSpec.clid != NULL)
  2765.         {
  2766.         if (pLeaseData->leaseReqSpec.clid->id != NULL)
  2767.             free (pLeaseData->leaseReqSpec.clid->id);
  2768.         free (pLeaseData->leaseReqSpec.clid);
  2769.         }
  2770.     /* Remove custom options field, if any. */
  2771.     if (pLeaseData->leaseReqSpec.pOptions != NULL)
  2772.         free (pLeaseData->leaseReqSpec.pOptions);
  2773.     clean_param (pLeaseData->dhcpcParam);
  2774.     if (pLeaseData->dhcpcParam != NULL)
  2775.         free (pLeaseData->dhcpcParam);
  2776.     /* Clear the slot in the global list so it can be re-used. */
  2777.     for (offset = 0; offset < dhcpcMaxLeases; offset++)
  2778.         if ( dhcpcLeaseList [offset] == pLeaseData )
  2779.             dhcpcLeaseList [offset] = NULL;
  2780.     free (pLeaseData);
  2781.     return;
  2782.     }
  2783. /******************************************************************************
  2784. *
  2785. * dhcpcCleanup - remove data structures used by DHCP client library
  2786. *
  2787. * This routine removes all data structures used by the dhcp client after
  2788. * all the lease-specific data structures have been removed. It is called
  2789. * in response to a dhcpcShutdown() request just before the client monitor
  2790. * task exits.
  2791. *
  2792. * RETURNS: N/A
  2793. *
  2794. * ERRNO: N/A
  2795. *
  2796. * NOMANUAL
  2797. */
  2798. LOCAL void dhcpcCleanup (void)
  2799.     {
  2800.     int offset;
  2801.     taskDelete (dhcpcReadTaskId);
  2802.     close (dhcpcDataSock);
  2803.     bpfDevDelete ("/bpf/dhcpc");
  2804.     free (dhcpcLeaseList);
  2805.  
  2806.     semDelete (dhcpcMutexSem);
  2807.     semDelete (dhcpcEventSem);
  2808.  
  2809.     rngDelete (dhcpcEventRing);
  2810.     for (offset = 0; offset < 10; offset++)
  2811.          free (dhcpcMessageList [offset].msgBuffer);
  2812.     free (dhcpcMessageList);
  2813.     dhcpcPrivateCleanup();    /* Remove data allocated in other libraries. */
  2814.     offset = bpfDrvRemove ();
  2815. #ifdef DHCPC_DEBUG
  2816.     if (offset == OK)
  2817.         logMsg ("dhcpcCleanup: successfully removed BPF driver.n",
  2818.                 0, 0, 0, 0, 0, 0);
  2819.     else
  2820.         logMsg ("dhcpcCleanup: unable to remove BPF driver (other users?).n",
  2821.                 0, 0, 0, 0, 0, 0);
  2822. #endif
  2823.     dhcpcInitialized = FALSE;
  2824.     return;
  2825.     }