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

VxWorks

开发平台:

C/C++

  1. /* dhcpcBoot.c - DHCP client finite state machine definition (boot time) */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01m,25apr02,wap  transmit DHCPDECLINEs as broadcasts, not unicasts (SPR
  8.                  #75119)
  9. 01l,23apr02,wap  use dhcpTime() instead of time() (SPR #68900) and initialize
  10.                  dhcpcBootStates correctly (SPR #75042)
  11. 01k,12oct01,rae  merge from truestack ver 01q, base 01g
  12.                  SPRs 65264, 70116, 27426, 69731
  13. 01j,26oct00,spm  fixed byte order of transaction identifier; removed reset code
  14. 01i,26oct00,spm  fixed modification history after tor3_x merge
  15. 01h,23oct00,niq  merged from version 01j of tor3_x branch (base version 01f)
  16. 01g,04dec97,spm  added code review modifications
  17. 01f,06oct97,spm  removed reference to deleted endDriver global; replaced with
  18.                  support for dynamic driver type detection
  19. 01e,02sep97,spm  removed name conflicts with runtime DHCP client (SPR #9241)
  20. 01d,26aug97,spm  major overhaul: included version 01h of dhcpcState1.c and
  21.                  version 01i of dhcpc_subr.c to retain single-lease library
  22.                  for boot time use
  23. 01c,06aug97,spm  removed parameters linked list to reduce memory required
  24. 01b,07apr97,spm  rewrote documentation
  25. 01a,29jan97,spm  created by modifying dhcpc.c module
  26. */
  27. /*
  28. DESCRIPTION
  29. This library contains the boot-time DHCP client implementation. The library
  30. contains routines to obtain a set of boot parameters using DHCP. Because the 
  31. bootstrap loader handles all the system configuration, the boot-time client 
  32. will not apply any configuration parameters received to the underlying network
  33. interface.
  34. INTERNAL 
  35. This module contains a modified version of the DHCP client finite state
  36. machine which eliminates all states from BOUND onwards. Provided that the 
  37. obtained lease exceeds the download time for the runtime image, these routines
  38. are not needed by the ROM-resident bootstrap loader. Their removal reduces the 
  39. size of the boot ROM image so that the DHCP client can be used with targets 
  40. like the MV147 which have limited ROM capacity. The code size is further 
  41. reduced by eliminating the routines which change the network interface settings
  42. and maintain the correct routing table entries. Although necessary to prevent 
  43. access to an unconfigured interface during runtime, it is overkill at boot 
  44. time, since the system will not start if an error occurs. Finally, the runtime 
  45. DHCP client supports the retrieval and maintenance of multiple leases and 
  46. allows users to renew or release the corresponding parameters. Those 
  47. capabilities are not necessary at boot time.
  48. INCLUDE_FILES: dhcpcBootLib.h
  49. */
  50. /*
  51.  * WIDE Project DHCP Implementation
  52.  * Copyright (c) 1995 Akihiro Tominaga
  53.  * Copyright (c) 1995 WIDE Project
  54.  * All rights reserved.
  55.  *
  56.  * Permission to use, copy, modify and distribute this software and its
  57.  * documentation is hereby granted, provided only with the following
  58.  * conditions are satisfied:
  59.  *
  60.  * 1. Both the copyright notice and this permission notice appear in
  61.  *    all copies of the software, derivative works or modified versions,
  62.  *    and any portions thereof, and that both notices appear in
  63.  *    supporting documentation.
  64.  * 2. All advertising materials mentioning features or use of this software
  65.  *    must display the following acknowledgement:
  66.  *      This product includes software developed by WIDE Project and
  67.  *      its contributors.
  68.  * 3. Neither the name of WIDE Project nor the names of its contributors
  69.  *    may be used to endorse or promote products derived from this software
  70.  *    without specific prior written permission.
  71.  *
  72.  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND WIDE
  73.  * PROJECT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  74.  * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ALSO, THERE
  75.  * IS NO WARRANTY IMPLIED OR OTHERWISE, NOR IS SUPPORT PROVIDED.
  76.  *
  77.  * Feedback of the results generated from any improvements or
  78.  * extensions made to this software would be much appreciated.
  79.  * Any such feedback should be sent to:
  80.  * 
  81.  *  Akihiro Tominaga
  82.  *  WIDE Project
  83.  *  Keio University, Endo 5322, Kanagawa, Japan
  84.  *  (E-mail: dhcp-dist@wide.ad.jp)
  85.  *
  86.  * WIDE project has the rights to redistribute these changes.
  87.  */
  88. /* includes */
  89. #include "vxWorks.h"
  90. #include "vxLib.h"             /* checksum() declaration. */
  91. #include "netLib.h"
  92. #include "inetLib.h"
  93. #include "taskLib.h"
  94. #include "sysLib.h"
  95. #include "ioLib.h"
  96. #include "sockLib.h"
  97. #include "wdLib.h"
  98. #include "rngLib.h"
  99. #include "logLib.h"
  100. #include "muxLib.h"
  101. #include "stdio.h"
  102. #include "stdlib.h"
  103. #include "sys/ioctl.h"
  104. #include "time.h"
  105. #include "netinet/in.h"
  106. #include "netinet/ip.h"
  107. #include "netinet/udp.h"
  108. #include "dhcpcBootLib.h"
  109. #include "dhcp/dhcpcCommonLib.h"
  110. #include "bpfDrv.h"
  111. /* defines */
  112. #define MAX_BOOT_STATES (INFORMING + 1) /* Function pointers for all states. */
  113. #define SLEEP_RANDOM(timer) ( (timer - 1) + (rand () % 2) )
  114. #define REQUEST_RETRANS   4  /* Number of retries, maximum of 5. (RFC 1541). */
  115.     /* Berkeley Packet Filter instructions for catching ARP messages. */
  116. LOCAL struct bpf_insn arpfilter[] = {
  117.   BPF_STMT(BPF_LD+BPF_TYPE, 0),    /* Save lltype in accumulator */
  118.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_ARP, 0, 9),  /* ARP in frame? */
  119.   /*
  120.    * The remaining statements use the (new) BPF_HLEN alias to avoid
  121.    * any link-layer dependencies.
  122.    */
  123.   BPF_STMT(BPF_LD+BPF_H+BPF_ABS+BPF_HLEN, 6),    /* A <- ARP OP field */
  124.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REPLY, 0, 7),    /* ARP reply ? */
  125.   BPF_STMT(BPF_LDX+BPF_HLEN, 0),           /* X <- frame data offset */
  126.   BPF_STMT(BPF_LD+BPF_B+BPF_IND, 4),       /* A <- hardware size */
  127.   BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),      /* A <- sum of variable offsets */
  128.   BPF_STMT(BPF_MISC+BPF_TAX, 0),           /* X <- sum of variable offsets */
  129.   BPF_STMT(BPF_LD+BPF_W+BPF_IND, 8),       /* A <- sender IP address */
  130.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, -1, 0, 1),   /* -1 replaced with real IP */
  131.   BPF_STMT(BPF_RET+BPF_K, -1),                     /* copy entire frame */
  132.   BPF_STMT(BPF_RET+BPF_K, 0)          /* unrecognized message: ignore frame */
  133.   };
  134. LOCAL struct bpf_program arpread = {
  135.     sizeof (arpfilter) / sizeof (struct bpf_insn),
  136.     arpfilter
  137.     };
  138. LOCAL int bpfArpDev;  /* Gets any replies to ARP probes. */
  139. LOCAL u_short dhcps_port;              /* Server port, in network byte order. */
  140. LOCAL u_short dhcpc_port;              /* Client port, in network byte order. */
  141. IMPORT struct bpf_insn dhcpfilter[];    /* For updating xid test */
  142. IMPORT struct bpf_program dhcpread;
  143. /* globals */
  144. struct dhcp_param *  dhcpcBootParam = NULL; /* Configuration parameters */
  145. IMPORT LEASE_DATA dhcpcBootLeaseData;
  146. IMPORT int  dhcpcBindType;  /* DHCP or BOOTP reply selected? */
  147. /* locals */
  148. LOCAL BOOL  dhcpcOldFlag; /* Use old (padded) messages? */
  149. LOCAL int dhcpcCurrState;   /* Current state */
  150. LOCAL int dhcpcPrevState;   /* Previous state */
  151. LOCAL int  dhcpcMsgLength;   /* Current message size. */
  152. LOCAL struct if_info dhcpcIntface;     /* Network interface */
  153. LOCAL struct buffer sbuf;  /* Buffer for outgoing messages */
  154. LOCAL struct msg  dhcpcMsgIn;  /* Incoming message components */
  155. LOCAL struct msg  dhcpcMsgOut; /* Outgoing message components */
  156. LOCAL unsigned char dhcpCookie [MAGIC_LEN] = RFC1048_MAGIC;
  157. LOCAL struct ps_udph  spudph;
  158. LOCAL int (*dhcpcBootStates [MAX_BOOT_STATES]) ();
  159. LOCAL int handle_ip();
  160. LOCAL int handle_num();
  161. LOCAL int handle_ips();
  162. LOCAL int handle_str();
  163. LOCAL int handle_bool();
  164. LOCAL int handle_ippairs();
  165. LOCAL int handle_nums();
  166. LOCAL int handle_list();
  167. LOCAL int (*handle_param [MAXTAGNUM]) () = 
  168.     {
  169.     NULL,           /* PAD */
  170.     handle_ip,      /* SUBNET_MASK */
  171.     handle_num,     /* TIME_OFFSET */
  172.     handle_ips,     /* ROUTER */
  173.     handle_ips,     /* TIME_SERVER */
  174.     handle_ips,     /* NAME_SERVER */
  175.     handle_ips,     /* DNS_SERVER */
  176.     handle_ips,     /* LOG_SERVER */
  177.     handle_ips,     /* COOKIE_SERVER */
  178.     handle_ips,     /* LPR_SERVER */
  179.     handle_ips,     /* IMPRESS_SERVER */
  180.     handle_ips,     /* RLS_SERVER */
  181.     handle_str,     /* HOSTNAME */
  182.     handle_num,     /* BOOTSIZE */
  183.     handle_str,     /* MERIT_DUMP */
  184.     handle_str,     /* DNS_DOMAIN */
  185.     handle_ip,      /* SWAP_SERVER */
  186.     handle_str,     /* ROOT_PATH */
  187.     handle_str,     /* EXTENSIONS_PATH */
  188.     handle_bool,    /* IP_FORWARD */
  189.     handle_bool,    /* NONLOCAL_SRCROUTE */
  190.     handle_ippairs, /* POLICY_FILTER */
  191.     handle_num,     /* MAX_DGRAM_SIZE */
  192.     handle_num,     /* DEFAULT_IP_TTL */
  193.     handle_num,     /* MTU_AGING_TIMEOUT */
  194.     handle_nums,    /* MTU_PLATEAU_TABLE */
  195.     handle_num,     /* IF_MTU */
  196.     handle_bool,    /* ALL_SUBNET_LOCAL */
  197.     handle_ip,      /* BRDCAST_ADDR */
  198.     handle_bool,    /* MASK_DISCOVER */
  199.     handle_bool,    /* MASK_SUPPLIER */
  200.     handle_bool,    /* ROUTER_DISCOVER */
  201.     handle_ip,      /* ROUTER_SOLICIT */
  202.     handle_ippairs, /* STATIC_ROUTE */
  203.     handle_bool,    /* TRAILER */
  204.     handle_num,     /* ARP_CACHE_TIMEOUT */
  205.     handle_bool,    /* ETHER_ENCAP */
  206.     handle_num,     /* DEFAULT_TCP_TTL */
  207.     handle_num,     /* KEEPALIVE_INTER */
  208.     handle_bool,    /* KEEPALIVE_GARBA */
  209.     handle_str,     /* NIS_DOMAIN */
  210.     handle_ips,     /* NIS_SERVER */
  211.     handle_ips,     /* NTP_SERVER */
  212.     handle_list,    /* VENDOR_SPEC */
  213.     handle_ips,     /* NBN_SERVER */
  214.     handle_ips,     /* NBDD_SERVER */
  215.     handle_num,     /* NB_NODETYPE */
  216.     handle_str,     /* NB_SCOPE */
  217.     handle_ips,     /* XFONT_SERVER */
  218.     handle_ips,     /* XDISPLAY_MANAGER */
  219.     NULL,           /* REQUEST_IPADDR */
  220.     handle_num,     /* LEASE_TIME */
  221.     NULL,           /* OPT_OVERLOAD */
  222.     NULL,           /* DHCP_MSGTYPE */
  223.     handle_ip,      /* SERVER_ID */
  224.     NULL,           /* REQ_LIST */
  225.     handle_str,     /* DHCP_ERRMSG */
  226.     NULL,           /* DHCP_MAXMSGSIZE */
  227.     handle_num,     /* DHCP_T1 */
  228.     handle_num,     /* DHCP_T2  */
  229.     NULL,           /* CLASS_ID */
  230.     NULL,           /* CLIENT_ID */
  231.     NULL,
  232.     NULL,
  233.     handle_str,     /* NISP_DOMAIN */
  234.     handle_ips,     /* NISP_SERVER */
  235.     handle_str,     /* TFTP_SERVERNAME */
  236.     handle_str,     /* BOOTFILE */
  237.     handle_ips,     /* MOBILEIP_HA */
  238.     handle_ips,     /* SMTP_SERVER */
  239.     handle_ips,     /* POP3_SERVER */
  240.     handle_ips,     /* NNTP_SERVER */
  241.     handle_ips,     /* DFLT_WWW_SERVER */
  242.     handle_ips,     /* DFLT_FINGER_SERVER */
  243.     handle_ips,     /* DFLT_IRC_SERVER */
  244.     handle_ips,     /* STREETTALK_SERVER */
  245.     handle_ips      /* STDA_SERVER */
  246.     };
  247. /* forward declarations */
  248. int dhcp_boot_client (struct if_info *, int, int, BOOL);
  249. LOCAL void msgAlign (struct msg *, char *);
  250. LOCAL int arp_check (struct in_addr *, struct if_info *);
  251. LOCAL int initialize (int, int);
  252. LOCAL void set_declinfo (struct dhcp_reqspec *, char *);
  253. LOCAL int make_discover (void);
  254. LOCAL int make_request (struct dhcp_param *, int);
  255. LOCAL int dhcp_decline (struct dhcp_reqspec *);
  256. LOCAL int dhcp_msgtoparam (struct dhcp *, int, struct dhcp_param *);
  257. LOCAL int merge_param (struct dhcp_param *, struct dhcp_param *);
  258. LOCAL long generate_xid ();
  259. LOCAL int clean_param (struct dhcp_param *);
  260. LOCAL int dhcpcBootInitState();
  261. LOCAL int dhcpcBootWaitOffer();
  262. LOCAL int dhcpcBootSelecting();
  263. LOCAL int dhcpcBootRequesting();
  264. LOCAL int dhcpcBootInforming();
  265. #ifdef DHCPC_DEBUG
  266. LOCAL int nvttostr (char *, char *, int);
  267. #endif
  268. /*******************************************************************************
  269. *
  270. * dhcp_boot_client - Exercise client finite state machine
  271. *
  272. * This routine uses the finite state machine to obtain a set of configuration
  273. * parameters. When the ROM-resident bootstrap loader issues a dhcpcBootBind()
  274. * call, this routine executes the state machine up until the BOUND state.
  275. * The states from BOUND onward are omitted to reduce the size of the boot ROM
  276. * images. If an address is already present, the routine executes the isolated
  277. * portion of the state machine which sends a DHCP INFORM message and waits for
  278. * an acknowledgement containing any additional parameters. The <bindFlag>
  279. * argument selects between these alternatives. In the first case, the boot
  280. * file downloaded by the bootstrap loader must spawn a task containing the
  281. * full state machine defined in the DHCP client runtime library to monitor
  282. * the established lease. 
  283. *
  284. * RETURNS: OK if message exchange completed, or value of failed state on error.
  285. *
  286. * ERRNO: N/A
  287. *
  288. * SEE ALSO: dhcpcLib
  289. *
  290. * NOMANUAL
  291. */
  292. int dhcp_boot_client
  293.     (
  294.     struct if_info *ifp,
  295.     int         serverPort,     /* port used by DHCP servers */
  296.     int         clientPort,     /* port used by DHCP clients */
  297.     BOOL  bindFlag  /* establish new lease? */
  298.     )
  299.     {
  300.     int next_state = 0;
  301.     int retval = 0;
  302.     dhcpcBootStates [INIT] = dhcpcBootInitState;
  303.     dhcpcBootStates [WAIT_OFFER] = dhcpcBootWaitOffer;
  304.     dhcpcBootStates [SELECTING] = dhcpcBootSelecting;
  305.     dhcpcBootStates [REQUESTING] = dhcpcBootRequesting;
  306.     dhcpcBootStates [INFORMING] = dhcpcBootInforming;
  307.     dhcpcIntface = *ifp;
  308.     if ( (retval = initialize (serverPort, clientPort)) < 0)
  309.         return (retval);
  310.     if (bindFlag)
  311.         {
  312.         /* 
  313.          * Full lease negotiation process. Use the state machine to
  314.          * obtain configuration parameters, including an address.
  315.          */
  316.         dhcpcPrevState = dhcpcCurrState = INIT; 
  317.         }
  318.     else
  319.         {
  320.         /*
  321.          * Partial message exchange for known (externally assigned) address.
  322.          * Send an INFORM message and wait for an acknowledgement containing
  323.          * additional parameters.
  324.          */
  325.         dhcpcPrevState = dhcpcCurrState = INFORMING;
  326.         }
  327.     while (next_state != BOUND)
  328.         {
  329.         if ( (next_state = (*dhcpcBootStates [dhcpcCurrState]) ()) < 0) 
  330.             {
  331. #ifdef DHCPC_DEBUG
  332.             logMsg ("Error in finite state machine.n", 0, 0, 0, 0, 0, 0);
  333. #endif
  334.             if (dhcpcBootParam != NULL)
  335.                 {
  336.                 clean_param (dhcpcBootParam);
  337.                 free (dhcpcBootParam);
  338.                 dhcpcBootParam = NULL;
  339.                 }
  340.             close (bpfArpDev);
  341.             bpfDevDelete ("/bpf/dhcpc-arp");
  342.             free (sbuf.buf);
  343.             return (ERROR);
  344.             }
  345.        /* If not a full lease negotiation, keep indication of known address. */
  346.         if (dhcpcPrevState != INFORMING)
  347.             dhcpcPrevState = dhcpcCurrState;
  348.         dhcpcCurrState = next_state;
  349. #ifdef DHCPC_DEBUG
  350.         logMsg ("next state= %dn", next_state, 0, 0, 0, 0, 0);
  351. #endif
  352.         }
  353.     close (bpfArpDev);
  354.     bpfDevDelete ("/bpf/dhcpc-arp");
  355.     free (sbuf.buf);
  356.     return (OK);   /* Bind successful. */
  357.     } 
  358. /*******************************************************************************
  359. *
  360. * gen_retransmit - generic retransmission after timeout
  361. *
  362. * This routine retransmits the current DHCP client message (a discover or
  363. * a request message) when the appropriate timeout interval expires.
  364. * It is called from multiple locations in the finite state machine.
  365. *
  366. * RETURNS: 0 if transmission completed, or negative value on error.
  367. *
  368. * ERRNO: N/A
  369. *
  370. * NOMANUAL
  371. */
  372. LOCAL int gen_retransmit
  373.     (
  374.     void
  375.     )
  376.     {
  377.     time_t curr_epoch = 0;
  378.     struct sockaddr_in dest;
  379.     BOOL bcastFlag;
  380.     if (dhcpTime (&curr_epoch) == -1)
  381.         return (-1);
  382.     /* Update the appropriate fields in the current DHCP message. */
  383.     if (dhcpcCurrState != REQUESTING)
  384.         dhcpcMsgOut.dhcp->secs = htons (curr_epoch -
  385.                                         dhcpcBootLeaseData.initEpoch);
  386.     dhcpcMsgOut.udp->uh_sum = 0;
  387.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp, 
  388.                                          ntohs (spudph.ulen));
  389.     /*
  390.      * Retransmit the message. Set the flag to use a link-level broadcast
  391.      * address if needed (prevents ARP messages if using Ethernet devices).
  392.      */
  393.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  394.     dest.sin_len = sizeof (struct sockaddr_in);
  395.     dest.sin_family = AF_INET;
  396.     dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  397.     if (dest.sin_addr.s_addr == 0xffffffff)
  398.         bcastFlag = TRUE;
  399.     else
  400.         bcastFlag = FALSE;
  401.     if (dhcpSend (dhcpcBootLeaseData.ifData.iface, &dest, 
  402.                   sbuf.buf, dhcpcMsgLength, bcastFlag)
  403.            == ERROR)
  404.         return (-2);
  405.     return(0);
  406.     }
  407. /*******************************************************************************
  408. *
  409. * retrans_wait_offer - retransmission in WAIT_OFFER state
  410. *
  411. * This routine retransmits the DHCP discover message when the timeout interval 
  412. * for receiving an initial lease offer expires. It is called in response
  413. * to a watchdog timer at intervals specified by the wait_offer() routine.
  414. *
  415. * RETURNS: N/A
  416. *
  417. * ERRNO: N/A
  418. *
  419. * NOMANUAL
  420. */
  421. LOCAL void retrans_wait_offer
  422.     (
  423.     int unused  /* unused watchdog argument */
  424.     )
  425.     {
  426.     int status;
  427.     if (dhcpcCurrState != WAIT_OFFER)
  428.         return;
  429.     /* Construct and send a timeout message to the finite state machine. */
  430.     status = dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, NULL, TRUE);
  431. #ifdef DHCPC_DEBUG
  432.     if (status == ERROR)
  433.         logMsg ("Can't notify state machinen", 0, 0, 0, 0, 0, 0);
  434. #endif
  435.     return;
  436.     }
  437. /*******************************************************************************
  438. *
  439. * alarm_selecting - signal when collection time expires 
  440. *
  441. * This routine sends a timeout notification to the finite state machine 
  442. * when the interval for collecting additional DHCP offers has expired. It 
  443. * is called in response to a watchdog timer schedule by the selecting()
  444. * routine. The timeout causes the state machine to advance to the REQUESTING
  445. * state.
  446. *
  447. * RETURNS: N/A
  448. *
  449. * ERRNO: N/A
  450. *
  451. * NOMANUAL
  452. */
  453. LOCAL void alarm_selecting
  454.     (
  455.     int unused  /* unused watchdog argument */
  456.     )
  457.     {
  458.     int  status;
  459.     if (dhcpcCurrState == SELECTING) 
  460.         {
  461.         /* Construct and send a timeout message to the finite state machine. */
  462.         status = dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, NULL, TRUE);
  463. #ifdef DHCPC_DEBUG
  464.         if (status == ERROR)
  465.             logMsg ("Can't notify state machinen", 0, 0, 0, 0, 0, 0);
  466. #endif
  467.         }
  468.     return;
  469.     }
  470. /*******************************************************************************
  471. *
  472. * retrans_requesting - retransmission in requesting state
  473. *
  474. * This routine retransmits the DHCP request message when the timeout interval 
  475. * for receiving a server reply expires. It is called in response to a watchdog 
  476. * timer at intervals specified by the requesting() routine.
  477. *
  478. * RETURNS: N/A
  479. *
  480. * ERRNO: N/A
  481. *
  482. * NOMANUAL
  483. */
  484. LOCAL void retrans_requesting
  485.     (
  486.     int unused  /* unused watchdog argument */
  487.     )
  488.     {
  489.     int status;
  490.     if (dhcpcCurrState != REQUESTING)
  491.         return;
  492.     /* Construct and send a timeout message to the finite state machine. */
  493.     status = dhcpcEventAdd (DHCP_AUTO_EVENT, DHCP_TIMEOUT, NULL, TRUE);
  494. #ifdef DHCPC_DEBUG
  495.     if (status == ERROR)
  496.         logMsg ("Can't notify state machinen", 0, 0, 0, 0, 0, 0);
  497. #endif
  498.     return;
  499.     }
  500. /*******************************************************************************
  501. *
  502. * dhcpcBootInforming - external configuration state of boot-time state machine
  503. *
  504. * This routine begins the inform message process, which obtains additional
  505. * parameters for a host configured with an external address. This processing
  506. * is isolated from the normal progression through the state machine. Like the
  507. * DHCP discover message, the inform message is the first transmission.
  508. * However, the only valid response is an acknowledgement by a server. As a
  509. * result, the process is a hybrid between the implementations of the initial 
  510. * state and the requesting state which finalizes the lease establishment.
  511. * This routine implements the initial state of the finite state machine for
  512. * an externally assigned IP address.
  513. *
  514. * RETURNS: Next state of state machine, or -1 if error.
  515. *
  516. * ERRNO: N/A
  517. *
  518. * NOMANUAL
  519. */
  520. LOCAL int dhcpcBootInforming
  521.     (
  522.     void
  523.     )
  524.     {
  525.     struct sockaddr_in  dest;
  526.     bzero (sbuf.buf, sbuf.size);
  527. #ifdef DHCPC_DEBUG
  528.     logMsg("dhcpc: Entered INFORM state.n", 0, 0, 0, 0, 0, 0);
  529. #endif
  530.     /* Create and broadcast DHCP INFORM message. */
  531.     dhcpcMsgLength = make_request (dhcpcBootParam, INFORMING);
  532.     if (dhcpcMsgLength < 0)
  533.         {
  534. #ifdef DHCPC_DEBUG
  535.         logMsg ("Error making DHCP inform message. Can't continue.n",
  536.                 0, 0, 0, 0, 0, 0);
  537. #endif
  538.         return (-1);
  539.         }
  540.     dhcpcMsgOut.dhcp->secs = 0;
  541.     dhcpcMsgOut.udp->uh_sum = 0;
  542.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp, 
  543.                                          ntohs (spudph.ulen));
  544. #ifdef DHCPC_DEBUG
  545.     logMsg ("Sending DHCPINFORMn", 0, 0, 0, 0, 0, 0);
  546. #endif
  547.     /*
  548.      * Retransmit the message using a link-level broadcast address, which
  549.      * prevents ARP messages if using Ethernet devices and allows transmission
  550.      * from interfaces without assigned IP addresses.
  551.      */
  552.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  553.     dest.sin_len = sizeof (struct sockaddr_in);
  554.     dest.sin_family = AF_INET;
  555.     dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  556.     if (dhcpSend (dhcpcIntface.iface, &dest, sbuf.buf, dhcpcMsgLength, TRUE)
  557.            == ERROR)
  558.         {
  559. #ifdef DHCPC_DEBUG
  560.         logMsg("Can't send DHCPINFORMn", 0, 0, 0, 0, 0, 0);
  561. #endif
  562.         return (-1);
  563.         }
  564.     /* Set retransmission timer to randomized exponential backoff. */
  565.     dhcpcBootLeaseData.timeout = FIRSTTIMER;
  566.     dhcpcBootLeaseData.numRetry = 0;
  567.     wdStart (dhcpcBootLeaseData.timer, sysClkRateGet() *
  568.                                   SLEEP_RANDOM (dhcpcBootLeaseData.timeout),
  569.              (FUNCPTR)retrans_requesting, 0);
  570.     return (REQUESTING); /* Next state is REQUESTING */
  571.     }
  572. /*******************************************************************************
  573. *
  574. * dhcpcBootInitState - initial state of boot-time client finite state machine
  575. *
  576. * This routine implements the initial state of the finite state machine. 
  577. * After a random backoff delay, it broadcasts a DHCP discover message. This 
  578. * state may be re-entered after a later state if a recoverable error occurs.
  579. *
  580. * RETURNS: Next state of state machine, or -1 if error.
  581. *
  582. * ERRNO: N/A
  583. *
  584. * NOMANUAL
  585. */
  586. LOCAL int dhcpcBootInitState
  587.     (
  588.     void
  589.     )
  590.     {
  591.     struct sockaddr_in  dest;
  592.     bzero (sbuf.buf, sbuf.size);
  593. #ifdef DHCPC_DEBUG
  594.     logMsg("dhcpc: Entered INIT state.n", 0, 0, 0, 0, 0, 0);
  595. #endif
  596.     /*
  597.      * Set lease to generate newer RFC 2131 messages initially. The client
  598.      * will revert to the older message format if it does not receive a
  599.      * response to the initial set of discover messages. Older servers might
  600.      * ignore messages less than the minimum length obtained with a fixed
  601.      * options field. The older format pads the field to reach that length.
  602.      */
  603.     dhcpcOldFlag = FALSE;
  604.     wdCancel (dhcpcBootLeaseData.timer); /* Reset watchdog timer. */
  605.     dhcpcMsgLength = make_discover ();    /* Create DHCP_DISCOVER message. */
  606.     /* 
  607.      * Random delay from one to ten seconds to avoid startup congestion.
  608.      * (Delay length specified in RFC 1541).
  609.      *
  610.      */
  611.     taskDelay (sysClkRateGet () * (1 + (rand () % INIT_WAITING)) );
  612.     dhcpcMsgOut.dhcp->secs = 0;
  613.     dhcpcMsgOut.udp->uh_sum = 0;
  614.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *)dhcpcMsgOut.udp, 
  615.                                          ntohs (spudph.ulen));
  616. #ifdef DHCPC_DEBUG
  617.     logMsg ("Sending DHCPDISCOVERn", 0, 0, 0, 0, 0, 0);
  618. #endif
  619.     /*
  620.      * Retransmit the message using a link-level broadcast address, which
  621.      * prevents ARP messages if using Ethernet devices and allows transmission
  622.      * from interfaces without assigned IP addresses.
  623.      */
  624.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  625.     dest.sin_len = sizeof (struct sockaddr_in);
  626.     dest.sin_family = AF_INET;
  627.     dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  628.     if (dhcpSend (dhcpcIntface.iface, &dest, sbuf.buf, dhcpcMsgLength, TRUE)
  629.             == ERROR)
  630.         {
  631. #ifdef DHCPC_DEBUG
  632.         logMsg("Can't send DHCPDISCOVERn", 0, 0, 0, 0, 0, 0);
  633. #endif
  634.         return (-1);
  635.         }
  636.     dhcpcBootLeaseData.timeout = FIRSTTIMER;
  637.     dhcpcBootLeaseData.numRetry = 0;
  638.     if (dhcpTime (&dhcpcBootLeaseData.initEpoch) == -1)
  639.         {
  640. #ifdef DHCPC_DEBUG
  641.         logMsg ("time() error setting initEpochn", 0, 0, 0, 0, 0, 0);
  642. #endif
  643.         return (ERROR);
  644.         }
  645.     /* Set timer to randomized exponential backoff before retransmission. */
  646.     wdStart (dhcpcBootLeaseData.timer, sysClkRateGet() *
  647.                                   SLEEP_RANDOM (dhcpcBootLeaseData.timeout),
  648.              (FUNCPTR)retrans_wait_offer, 0);
  649.     return (WAIT_OFFER); /* Next state is WAIT_OFFER */
  650.     }
  651. /*******************************************************************************
  652. *
  653. * dhcpcBootWaitOffer - Initial offering state of client finite state machine
  654. *
  655. * This routine implements the initial part of the second state of the finite 
  656. * state machine. It waits until the current timeout value to receive a lease 
  657. * offer from  a DHCP server. If a timeout occurs, the DHCP offer message is 
  658. * retransmitted.
  659. *
  660. * RETURNS: Next state of state machine, or -1 if error.
  661. *
  662. * ERRNO: N/A
  663. *
  664. * NOMANUAL
  665. */
  666. LOCAL int dhcpcBootWaitOffer
  667.     (
  668.     void
  669.     )
  670.     {
  671.     int arpans = 0;
  672.     char errmsg [255];
  673.     char *  pOption;
  674.     int  timer = 0;
  675.     int  retry = 0;
  676.     struct dhcp_param * pParams = NULL;
  677.     char *  pMsgData;
  678.     int  status;
  679.     EVENT_DATA  msgEvent;
  680.     bzero (errmsg, sizeof (errmsg));
  681. #ifdef DHCPC_DEBUG
  682.     logMsg ("dhcpc: Entered WAIT_OFFER state.n", 0, 0, 0, 0, 0, 0);
  683. #endif
  684.     if (dhcpcPrevState == INIT) 
  685.         {
  686.         /* Clear any previous parameter settings. */
  687.         if (dhcpcBootParam != NULL)
  688.             {
  689.             clean_param (dhcpcBootParam);
  690.             free (dhcpcBootParam);
  691.             dhcpcBootParam = NULL;
  692.             }
  693.         }
  694.     /* Wait for message or retransmission. */
  695.     semTake (dhcpcEventSem, WAIT_FOREVER); 
  696.     status = rngBufGet (dhcpcEventRing, (char *)&msgEvent, sizeof (msgEvent));
  697.     if (status != sizeof (msgEvent))
  698.         {
  699.         /* Expected event missing or incomplete - remain in current state. */
  700. #ifdef DHCPC_DEBUG
  701.         logMsg ("dhcpWaitOffer: Notification error.n", 0, 0, 0, 0, 0, 0);
  702. #endif
  703.         return (WAIT_OFFER);
  704.         }
  705.     if (msgEvent.type == DHCP_TIMEOUT)
  706.         {
  707.         /* Handle timeout - no DHCP offers received yet. */
  708.         retry = dhcpcBootLeaseData.numRetry;
  709.         timer = dhcpcBootLeaseData.timeout;
  710.         retry++;
  711.         if (retry == DISCOVER_RETRANS)
  712.             {
  713. #ifdef DHCPC_DEBUG
  714.             logMsg ("No lease offers received by client.n", 0, 0, 0, 0, 0, 0);
  715. #endif
  716.             /*
  717.              * No response to new DHCP message format, which can be ignored
  718.              * by older DHCP servers as too short. Try the earlier format,
  719.              * which padded the options field to a minimum length. If
  720.              * successful, all subsequent messages will add that padding.
  721.              * The initialization guarantees that the transmit buffer can
  722.              * store the padded message.
  723.              */
  724.             if (!dhcpcOldFlag && dhcpcMsgLength < (DFLTDHCPLEN + UDPHL + IPHL))
  725.                 {
  726.                 dhcpcOldFlag = TRUE;
  727.                 dhcpcMsgLength = make_discover ();
  728.                 timer = FIRSTTIMER / 2;     /* Counteract later doubling. */
  729.                 retry = 0;
  730.                 }
  731.             else
  732.                 return (ERROR);
  733.             }
  734.         /* Retransmission required - return after sending message. */
  735.         switch (gen_retransmit ())
  736.             {
  737.             case 0:         /* Transmission successful. */
  738. #ifdef DHCPC_DEBUG
  739.                 logMsg ("retransmit DHCPDISCOVERn", 0, 0, 0, 0, 0, 0);
  740. #endif
  741.                 break;
  742.             case -1:        /* Couldn't update timing data */
  743. #ifdef DHCPC_DEBUG
  744.                 logMsg ("time() error retransmitting DHCPDISCOVERn",
  745.                          0, 0, 0, 0, 0, 0);
  746. #endif
  747.                 break;
  748.             case -2:        /* Transmission error in output routine */
  749. #ifdef DHCPC_DEBUG
  750.                 logMsg ("Can't retransmit DHCPDISCOVERn",
  751.                             0, 0, 0, 0, 0, 0);
  752. #endif
  753.                 break;
  754.             }
  755.         if (timer < MAXTIMER)
  756.             {
  757.             /* Double retransmission delay with each attempt. (RFC 1541). */
  758.             timer *= 2;
  759.             }
  760.         /* Set retransmission timer to randomized exponential backoff. */
  761.         wdStart (dhcpcBootLeaseData.timer, sysClkRateGet() *
  762.                                       SLEEP_RANDOM (timer),
  763.                  (FUNCPTR)retrans_wait_offer, 0);
  764.         dhcpcBootLeaseData.timeout = timer;
  765.         dhcpcBootLeaseData.numRetry = retry;
  766.         }
  767.     else
  768.         {
  769.         /*
  770.          * Process DHCP message stored in receive buffer by monitor task.
  771.          * The 4-byte alignment of the IP header needed by Sun BSP's is
  772.          * guaranteed by the Berkeley Packet Filter during input.
  773.          */
  774.         pMsgData = msgEvent.pMsg;
  775.         msgAlign (&dhcpcMsgIn, pMsgData);
  776.         /* Examine type of message. Accept DHCP offers or BOOTP replies. */
  777.         pOption = (char *)pickup_opt (dhcpcMsgIn.dhcp,
  778.                                       DHCPLEN (dhcpcMsgIn.udp),
  779.                                       _DHCP_MSGTYPE_TAG);
  780.         if (pOption == NULL)
  781.             {
  782.             /* 
  783.              * Message type not found - check message length. Ignore
  784.              * untyped DHCP messages, but accept (shorter) BOOTP replies.
  785.              * This test might still treat (illegal) untyped DHCP messages
  786.              * like BOOTP messages if they are short enough, but that case
  787.              * can't be avoided. Mark the message buffer available after
  788.              * handling the last DHCP message.
  789.              */
  790.             if (DHCPLEN (dhcpcMsgIn.udp) > DFLTBOOTPLEN)
  791.                 {
  792.                 if (msgEvent.lastFlag)
  793.                     dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  794.                 return (WAIT_OFFER);
  795.                 }
  796.             }
  797.         else
  798.             {
  799.             if (*OPTBODY (pOption) != DHCPOFFER)
  800.                 {
  801.                 /*
  802.                  * Ignore messages with unexpected types. Mark the message
  803.                  * buffer available after handling the last DHCP message.
  804.                  */
  805.                 if (msgEvent.lastFlag)
  806.                     dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  807.                 return (WAIT_OFFER);
  808.                 }
  809.             }
  810.         /* Allocate memory for configuration parameters. */
  811.         pParams = (struct dhcp_param *)calloc (1, sizeof (struct dhcp_param));
  812.         if (pParams == NULL)
  813.             {
  814.             /*
  815.              * Memory for configuration parameters is unavailable. Remain
  816.              * in current state. Mark the message buffer available after
  817.              * handling the last DHCP message.
  818.              */
  819.             if (msgEvent.lastFlag)
  820.                 dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  821.             return (WAIT_OFFER);
  822.             }
  823.         /* Fill in host requirements defaults. */
  824.         dhcpcDefaultsSet (pParams);
  825.         /* Check offered parameters. Copy to parameter list if acceptable. */
  826.         if (dhcp_msgtoparam (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  827.                                  pParams) == OK) 
  828.             {
  829.             /*
  830.              * Accept static BOOTP address or verify that the
  831.              * address offered by the DHCP server is available
  832.              * and check offered lease length against minimum value.
  833.              */
  834.             if ( (pParams->msgtype == DHCP_BOOTP ||
  835.                  pParams->server_id.s_addr != 0) &&
  836.                 (arpans = arp_check (&pParams->yiaddr, &dhcpcIntface)) == OK && 
  837.                 pParams->lease_duration >= dhcpcMinLease) 
  838.                 {
  839.                 /*
  840.                  * Initial offer accepted. Set client session
  841.                  * to execute next routine and start timer.
  842.                  */
  843.                 pParams->lease_origin = dhcpcBootLeaseData.initEpoch;
  844.                 dhcpcBootParam = pParams;
  845.                 /*
  846.                  * Reset timer from retransmission interval
  847.                  * to limit for collecting replies.
  848.                  */
  849.                 wdCancel (dhcpcBootLeaseData.timer);
  850.                 wdStart (dhcpcBootLeaseData.timer, sysClkRateGet() *
  851.                                     dhcpcBootLeaseData.leaseReqSpec.waitsecs,
  852.                          (FUNCPTR)alarm_selecting, 0);
  853.                 /*
  854.                  * Mark the message buffer available after handling the
  855.                  * last DHCP message.
  856.                  */
  857.                 if (msgEvent.lastFlag)
  858.                     dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  859.                 return (SELECTING); /* Next state is SELECTING */
  860.                 }
  861.     else 
  862.                 {
  863.                 /*
  864.                  * Offer is insufficient. Remove stored parameters
  865.                  * and remain in current state.
  866.                  */
  867.         clean_param (pParams);
  868.         free (pParams);
  869.                 }
  870.             }
  871.         else
  872.             {
  873.             /* Conversion unsuccessful - remove any stored parameters. */
  874.             clean_param (pParams);
  875.             free (pParams);
  876.             }
  877.         }
  878.     /*
  879.      * No valid offer received yet. Next state is (still) WAIT_OFFER. Mark
  880.      * the message buffer available after handling the last DHCP message.
  881.      */
  882.     if (msgEvent.type == DHCP_MSG_ARRIVED && msgEvent.lastFlag)
  883.         dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  884.     return (WAIT_OFFER);
  885.     }
  886. /*******************************************************************************
  887. *
  888. * dhcpcBootSelecting - Second offering state of client finite state machine
  889. *
  890. * This routine continues the second state of the finite state machine. 
  891. * It compares additional offers received from DHCP servers to the current
  892. * offer, and selects the offer which provides the lognest lease. When
  893. * the time limit specified by the DHCPC_OFFER_TIMEOUT definition passes, 
  894. * processing of the selected DHCP offer will continue with the requesting() 
  895. * routine. If no DHCP offers were received, the BOOTP reply selected by the 
  896. * wait_offer() routine will be used by the bootstrap loader.
  897. *
  898. * RETURNS: Next state of state machine, or -1 if error.
  899. *
  900. * ERRNO: N/A
  901. *
  902. * NOMANUAL
  903. */
  904. LOCAL int dhcpcBootSelecting
  905.     (
  906.     void
  907.     )
  908.     {
  909.     int  arpans = 0;
  910.     struct dhcp_param *  pParams = NULL; 
  911.     char *  pMsgData;
  912.     char *  pOption;
  913.     EVENT_DATA  msgEvent;
  914.     int  status;
  915.     struct sockaddr_in  dest;
  916. #ifdef DHCPC_DEBUG
  917.     logMsg ("dhcp: Entered SELECTING state.n", 0, 0, 0, 0, 0, 0);
  918. #endif
  919.     /* Wait for message or timer expiration. */
  920.     semTake (dhcpcEventSem, WAIT_FOREVER); 
  921.     status = rngBufGet (dhcpcEventRing, (char *) &msgEvent, 
  922.                         sizeof (msgEvent));
  923.     if (status != sizeof (msgEvent))
  924.         {
  925.         /* Expected event missing or incomplete - remain in current state. */
  926.         return (SELECTING);
  927.         }
  928.     if (msgEvent.type == DHCP_TIMEOUT)  
  929.         {
  930.         /*
  931.          * Collection time expired -
  932.          *     parameters structure holds chosen offer.
  933.          */
  934.         /* No response is needed if a BOOTP reply is chosen. */
  935.         if (dhcpcBootParam->msgtype == DHCP_BOOTP)
  936.             {
  937.             dhcpcBindType = DHCP_BOOTP;
  938.             return (BOUND);
  939.             }
  940.         dhcpcMsgLength = make_request (dhcpcBootParam, REQUESTING);
  941.         if (dhcpcMsgLength < 0)
  942.             {
  943. #ifdef DHCPC_DEBUG
  944.             logMsg ("Error making DHCP request. Entering INIT state.n",
  945.                     0, 0, 0, 0, 0, 0);
  946. #endif
  947.             return (INIT);
  948.             }
  949.         dhcpcMsgOut.udp->uh_sum = 0;
  950.         dhcpcMsgOut.udp->uh_sum = udp_cksum (&spudph, (char *) dhcpcMsgOut.udp,
  951.                                              ntohs (spudph.ulen));
  952.         /*
  953.          * Retransmit the message using a link-level broadcast address,
  954.          * which prevents ARP messages if using Ethernet devices and allows
  955.          * transmission from interfaces without assigned IP addresses.
  956.          */
  957.         bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  958.         dest.sin_len = sizeof (struct sockaddr_in);
  959.         dest.sin_family = AF_INET;
  960.         dest.sin_addr.s_addr = dhcpcMsgOut.ip->ip_dst.s_addr;
  961.         if (dhcpSend (dhcpcIntface.iface, &dest, sbuf.buf,
  962.                       dhcpcMsgLength, TRUE) == ERROR)
  963.             {
  964. #ifdef DHCPC_DEBUG
  965.             logMsg ("Can't send DHCPREQUESTn", 0, 0, 0, 0, 0, 0);
  966. #endif
  967.             return (INIT);
  968.             }
  969.         /*
  970.          * DHCP request sent. Set client session to execute next state and
  971.          * start the retransmission timer.
  972.          */
  973.         dhcpcBootLeaseData.timeout = FIRSTTIMER;
  974.         dhcpcBootLeaseData.numRetry = 0;
  975.         wdStart (dhcpcBootLeaseData.timer, sysClkRateGet() *
  976.                                     SLEEP_RANDOM (dhcpcBootLeaseData.timeout),
  977.                  (FUNCPTR)retrans_requesting, 0);
  978.         return (REQUESTING);
  979.         }
  980.     else
  981.         {
  982.         /*
  983.          * Process DHCP message stored in receive buffer by monitor task. 
  984.          * The 4-byte alignment of the IP header needed by Sun BSP's is
  985.          * guaranteed by the Berkeley Packet Filter during input.
  986.          */
  987.         pMsgData = msgEvent.pMsg;
  988.         msgAlign (&dhcpcMsgIn, pMsgData);
  989.         /* Examine type of message. Only accept DHCP offers. */
  990.         pOption = (char *)pickup_opt (dhcpcMsgIn.dhcp,
  991.                                       DHCPLEN (dhcpcMsgIn.udp),
  992.                                      _DHCP_MSGTYPE_TAG);
  993.         if (pOption == NULL)
  994.             {
  995.             /*
  996.              * Message type not found - discard untyped DHCP messages, and
  997.              * any BOOTP replies. Mark the message buffer available after
  998.              * handling the last DHCP message.
  999.              */
  1000.             if (msgEvent.lastFlag)
  1001.                 dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  1002.             return (SELECTING);
  1003.             }
  1004.         else
  1005.             {
  1006.             if (*OPTBODY (pOption) != DHCPOFFER)
  1007.                 {
  1008.                 /*
  1009.                  * Ignore messages with unexpected types. Mark the message
  1010.                  * buffer available after handling the last DHCP message.
  1011.                  */
  1012.                 if (msgEvent.lastFlag)
  1013.                     dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  1014.                 return (SELECTING);
  1015.                 }
  1016.             }
  1017.         /* Allocate memory for configuration parameters. */
  1018.         pParams = (struct dhcp_param *)calloc (1, sizeof (struct dhcp_param));
  1019.         if (pParams == NULL) 
  1020.             {
  1021.             /*
  1022.              * Memory for configuration parameters is unavailable. Remain
  1023.              * in current state. Mark the message buffer available after
  1024.              * handling the last DHCP message.
  1025.              */
  1026.             if (msgEvent.lastFlag)
  1027.                 dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  1028.             return (SELECTING);
  1029.             }
  1030.         /* Fill in host requirements defaults. */
  1031.         dhcpcDefaultsSet (pParams);
  1032.         
  1033.         /* Switch to offered parameters if they provide a longer DHCP lease. */
  1034.         if (dhcp_msgtoparam (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp),
  1035.                                  pParams) == OK) 
  1036.             {
  1037.             if (pParams->server_id.s_addr != 0 &&
  1038.                 (arpans = arp_check (&pParams->yiaddr, &dhcpcIntface)) == OK && 
  1039.                 pParams->lease_duration >= dhcpcMinLease)
  1040.                 {
  1041.                 /* Take any DHCP message over BOOTP, or take a longer lease. */
  1042.                 if (dhcpcBootParam->msgtype == DHCP_BOOTP ||
  1043.                      pParams->lease_duration > dhcpcBootParam->lease_duration)
  1044.                     { 
  1045.                     pParams->lease_origin = dhcpcBootLeaseData.initEpoch;
  1046.                     clean_param (dhcpcBootParam);
  1047.                     free (dhcpcBootParam);
  1048.                     dhcpcBootParam = pParams;
  1049.                     }
  1050.                 }
  1051.             else 
  1052.                 {
  1053.                 /*
  1054.                  * Offer is insufficient. Remove stored parameters
  1055.                  * and remain in current state.
  1056.                  */
  1057.                 clean_param (pParams);
  1058.                 free (pParams);
  1059.         }
  1060.     }
  1061.         else
  1062.             {
  1063.             /* Conversion unsuccessful - remove any stored parameters. */
  1064.             clean_param (pParams);
  1065.             free (pParams);
  1066.             }
  1067.         }
  1068.     /*
  1069.      * Processed new offer before timer expired. Next state is (still)
  1070.      * SELECTING. Mark the message buffer available after handling the
  1071.      * last DHCP message.
  1072.      */
  1073.     if (msgEvent.lastFlag)
  1074.         dhcpcMessageList [msgEvent.slot].writeFlag = TRUE;
  1075.     return (SELECTING);
  1076.     }
  1077. /*******************************************************************************
  1078. *
  1079. * dhcpcBootRequesting - Lease request state of client finite state machine
  1080. *
  1081. * This routine implements the third state of the client finite state machine.
  1082. * It sends a lease request to the DHCP server whose offer was selected,
  1083. * and waits up to the current timeout value to receive a reply from that
  1084. * server. If a timeout occurs, the DHCP request message is retransmitted.
  1085. * If the request is refused or the retransmission limit is reached, the lease
  1086. * negotiation process will restart or the inform process will exit. If the
  1087. * request is acknowledged, the corresponding parameters will be used by the
  1088. * bootstrap loader to configure the boot device and fetch the runtime image.
  1089. *
  1090. * RETURNS: Next state of state machine, or -1 if error.
  1091. *
  1092. * ERRNO: N/A
  1093. *
  1094. * NOMANUAL
  1095. */
  1096. LOCAL int dhcpcBootRequesting
  1097.     (
  1098.     void
  1099.     )
  1100.     {
  1101.     STATUS result = OK;
  1102.     char *pOption = NULL;
  1103.     char errmsg[255];
  1104.     int timer = 0;
  1105.     int retry = 0;
  1106.     struct dhcp_param tmpparam;
  1107.     struct dhcp_reqspec tmp_reqspec;
  1108.     EVENT_DATA  newEvent;
  1109.     char * pMsgData;
  1110.     int status;
  1111.     int msgtype;
  1112. #ifdef DHCPC_DEBUG
  1113.     char newAddr [INET_ADDR_LEN];
  1114.     logMsg ("dhcpc: Entering requesting state.n", 0, 0, 0, 0, 0, 0);
  1115. #endif 
  1116.     bzero (errmsg, sizeof (errmsg));
  1117.     bzero ( (char *)&tmp_reqspec, sizeof (tmp_reqspec));
  1118.     /* Wait for message or retransmission. */
  1119.     semTake (dhcpcEventSem, WAIT_FOREVER);
  1120.     status = rngBufGet (dhcpcEventRing, (char *)&newEvent, sizeof (newEvent));
  1121.     if (status != sizeof (newEvent))
  1122.         {
  1123.         /* Expected event missing or incomplete - remain in current state. */
  1124.         return (REQUESTING);
  1125.         }
  1126.     if (newEvent.type == DHCP_TIMEOUT)
  1127.         {
  1128.         /* Handle timeout - no DHCP reply received yet. */
  1129.         retry = dhcpcBootLeaseData.numRetry;
  1130.         timer = dhcpcBootLeaseData.timeout;
  1131.         retry++;
  1132.         if (retry > REQUEST_RETRANS) 
  1133.             {
  1134. #ifdef DHCPC_DEBUG
  1135.             logMsg ("Client can't get ACK/NAK reply from servern", 
  1136.                      0, 0, 0, 0, 0, 0);
  1137. #endif
  1138.           /* Exit if unable to get additional parameters for known address. */
  1139.             if (dhcpcPrevState == INFORMING)
  1140.                 return (BOUND);
  1141.             return (INIT);           /* Next state is INIT */
  1142.             }
  1143.         /* Retransmission required - return after sending message. */
  1144.         switch (gen_retransmit ())
  1145.             {
  1146.             case 0:         /* Transmission successful. */
  1147. #ifdef DHCPC_DEBUG
  1148.                 logMsg ("retransmit DHCPREQUESTn", 0, 0, 0, 0, 0, 0);
  1149. #endif
  1150.                 break;
  1151.             case -1:        /* Couldn't update timing data */
  1152. #ifdef DHCPC_DEBUG
  1153.                 logMsg ("time() error retransmitting DHCPREQUESTn",
  1154.                          0, 0, 0, 0, 0, 0);
  1155. #endif
  1156.                 break;
  1157.             case -2:        /* Transmission error in output routine */
  1158. #ifdef DHCPC_DEBUG
  1159.                 logMsg ("Can't retransmit DHCPREQUESTn",
  1160.                         0, 0, 0, 0, 0, 0);
  1161. #endif
  1162.                 break;
  1163.             }
  1164.         if (timer < MAXTIMER) 
  1165.             {
  1166.             /* Double retransmission delay with each attempt. (RFC 1541). */
  1167.             timer *= 2;
  1168.             }
  1169.         /* Set retransmission timer to randomized exponential backoff. */
  1170.         wdStart (dhcpcBootLeaseData.timer, sysClkRateGet() *
  1171.                                       SLEEP_RANDOM (timer),
  1172.                  (FUNCPTR)retrans_requesting, 0);
  1173.         dhcpcBootLeaseData.timeout = timer;
  1174.         dhcpcBootLeaseData.numRetry = retry;
  1175.         }
  1176.     else
  1177.         {
  1178.         bzero ( (char *)&tmpparam, sizeof (tmpparam));
  1179.         /*
  1180.          * Process DHCP message stored in receive buffer by monitor task. 
  1181.          * The 4-byte alignment of the IP header needed by Sun BSP's is
  1182.          * guaranteed by the Berkeley Packet Filter during input.
  1183.          */
  1184.         pMsgData = newEvent.pMsg;
  1185.         msgAlign (&dhcpcMsgIn, pMsgData);
  1186.         pOption = (char *) pickup_opt (dhcpcMsgIn.dhcp,
  1187.                                        DHCPLEN (dhcpcMsgIn.udp),
  1188.                                        _DHCP_MSGTYPE_TAG);
  1189.         if (pOption != NULL) 
  1190.             {
  1191.             msgtype =*OPTBODY (pOption);
  1192.             /*
  1193.              * Ignore unknown message types. If the client does not receive
  1194.              * a valid response within the expected interval, it will
  1195.              * timeout and retransmit the request - RFC 2131, section 3.1.5.
  1196.              */
  1197.             if (msgtype != DHCPACK && msgtype != DHCPNAK)
  1198.                 {
  1199.                 /*
  1200.                  * Mark the message buffer available after
  1201.                  * handling the last DHCP message.
  1202.                  */
  1203.                 if (newEvent.lastFlag)
  1204.                     dhcpcMessageList [newEvent.slot].writeFlag = TRUE;
  1205.                 return (REQUESTING);
  1206.                 }
  1207.     if (msgtype == DHCPNAK) 
  1208.                 {
  1209. #ifdef DHCPC_DEBUG
  1210.         logMsg ("Got DHCPNAK from servern", 0, 0, 0, 0, 0, 0);
  1211.                 pOption = (char *)pickup_opt (dhcpcMsgIn.dhcp, 
  1212.                                               DHCPLEN(dhcpcMsgIn.udp), 
  1213.                                               _DHCP_ERRMSG_TAG);
  1214.                 if (pOption != NULL &&
  1215.                     nvttostr (OPTBODY (pOption), errmsg, 
  1216.                               (int)DHCPOPTLEN (pOption)) == 0)
  1217.             logMsg ("DHCPNAK contains the error message "%s"n", 
  1218.                              (int)errmsg, 0, 0, 0, 0, 0);
  1219. #endif
  1220.                 /*
  1221.                  * Mark the message buffer available after handling the
  1222.                  * last DHCP message.
  1223.                  */
  1224.                 if (newEvent.lastFlag)
  1225.                     dhcpcMessageList [newEvent.slot].writeFlag = TRUE;
  1226.                 /* Ignore invalid responses to DHCP inform message. */
  1227.                 if (dhcpcPrevState == INFORMING)
  1228.                     return (REQUESTING);
  1229.                 clean_param (dhcpcBootParam);
  1230.                 free (dhcpcBootParam);
  1231.                 dhcpcBootParam = NULL;
  1232.                 return (INIT);               /* Next state is INIT */
  1233.         }
  1234.             /*
  1235.              * Got acknowledgement: fill in host requirements defaults and
  1236.              * add any parameters from message options.
  1237.              */
  1238.             dhcpcDefaultsSet (&tmpparam);   
  1239.             result = dhcp_msgtoparam (dhcpcMsgIn.dhcp,
  1240.                                       DHCPLEN (dhcpcMsgIn.udp), &tmpparam);
  1241.             /*
  1242.              * Mark the message buffer available after
  1243.              * handling the last DHCP message.
  1244.              */
  1245.             if (newEvent.lastFlag)
  1246.                 dhcpcMessageList [newEvent.slot].writeFlag = TRUE;
  1247.             if (result == OK) 
  1248.                 {
  1249.                 /* Options parsed successfully - test as needed. */
  1250.                 if (dhcpcPrevState == INFORMING)
  1251.                     dhcpcBindType = DHCP_MANUAL;     /* Not a lease. */
  1252.                 else
  1253.                     {
  1254.                     /* Full lease negotiation - send ARP probe. */
  1255.                     result = arp_check (&tmpparam.yiaddr, &dhcpcIntface);
  1256.                     if (result == OK)
  1257.                         { 
  1258. #ifdef DHCPC_DEBUG
  1259.                         inet_ntoa_b (dhcpcBootParam->yiaddr, newAddr);
  1260.                         logMsg ("Got DHCPACK (IP = %s, duration = %d secs)n",
  1261.                                 (int)newAddr, dhcpcBootParam->lease_duration, 
  1262.                                 0, 0, 0, 0);
  1263. #endif
  1264.                         dhcpcBindType = DHCP_NATIVE;
  1265.                         }
  1266.                     }
  1267.                 /* Save additional parameters if address is available. */
  1268.                 if (result == OK)
  1269.                     {
  1270.                     merge_param (dhcpcBootParam, &tmpparam);
  1271.                     *dhcpcBootParam = tmpparam;
  1272.                     if (dhcpcBindType == DHCP_NATIVE)
  1273.                         {
  1274.                         /* Save the lease start time. */
  1275.                         dhcpcBootParam->lease_origin =
  1276.                                                 dhcpcBootLeaseData.initEpoch;
  1277.                         }
  1278.                     return (BOUND);    /* Address is available. */
  1279.                     }
  1280.                 }
  1281.             /*
  1282.              * Invalid parameters or (for a full lease negotiation) a
  1283.              * failed ARP probe (address in use). For the full lease
  1284.              * negotiation, send the DHCPDECLINE message which is now
  1285.              * required when an ARP probe fails: RFC 2131, section 3.1.5.
  1286.              */
  1287.             if (dhcpcPrevState != INFORMING)
  1288.                 {
  1289.                 set_declinfo (&tmp_reqspec, errmsg);
  1290.                 dhcp_decline (&tmp_reqspec);
  1291.                 clean_param (dhcpcBootParam);
  1292.                 free (dhcpcBootParam);
  1293.                 dhcpcBootParam = NULL;
  1294. #ifdef DHCPC_DEBUG
  1295.                 logMsg ("Received unacceptable ACK. Entering INIT state.n",
  1296.                         0, 0, 0, 0, 0, 0);
  1297. #endif
  1298.                 return (INIT);
  1299.                 }
  1300.             /* Ignore invalid parameters for DHCP inform messages. */
  1301.             return (REQUESTING);
  1302.             }
  1303.         /*
  1304.          * Message type unavailable - remain in current state. Mark
  1305.          * the message buffer available after handling the last DHCP
  1306.          * message.
  1307.          */
  1308.         if (newEvent.lastFlag)
  1309.             dhcpcMessageList [newEvent.slot].writeFlag = TRUE;
  1310.         }
  1311.     /* Timeout occurred - remain in current state. */
  1312.     return (REQUESTING);
  1313.     }
  1314. /*******************************************************************************
  1315. *
  1316. * generate_xid - generate a transaction identifier 
  1317. *
  1318. * This routine forms a transaction identifier for outgoing messages from the
  1319. * DHCP client. It is called from multiple locations after the initialization 
  1320. * routines have retrieved the network interface hardware address.
  1321. *
  1322. * RETURNS: 32-bit transaction identifier in host byte order. 
  1323. *
  1324. * ERRNO: N/A
  1325. *
  1326. * NOMANUAL
  1327. */
  1328. LOCAL long generate_xid
  1329.     (
  1330.     void
  1331.     )
  1332.     {
  1333.     time_t current = 0;
  1334.     u_short result1 = 0;
  1335.     u_short result2 = 0;
  1336.     u_short tmp[6]; 
  1337.     bcopy (dhcpcIntface.haddr.haddr, (char *)tmp, 6);
  1338.     dhcpTime (&current);
  1339.     result1 = checksum (tmp, 6);
  1340.     result2 = checksum ( (u_short *)&current, 2);
  1341.     return ( (result1 << 16) + result2);
  1342.     }
  1343. /*******************************************************************************
  1344. *
  1345. * msgAlign - set the buffer pointers to access message components
  1346. *
  1347. * This routine sets the pointers in the given message descriptor
  1348. * structure to access the various components of a received DHCP
  1349. * message. It is used internally by the state machine routines.
  1350. *
  1351. * RETURNS: N/A
  1352. *
  1353. * ERRNO:   N/A
  1354. *
  1355. * NOMANUAL
  1356. */
  1357. LOCAL void msgAlign
  1358.     (
  1359.     struct msg *rmsg,  /* Components of received message */
  1360.     char *rbuf  /* Received Ethernet packet */
  1361.     )
  1362.     {
  1363.     rmsg->ip = (struct ip *) rbuf;
  1364.     if ( (ntohs (rmsg->ip->ip_off) & 0x1fff) == 0 &&
  1365.         ntohs (rmsg->ip->ip_len) >= (DFLTDHCPLEN - DFLTOPTLEN + 4) + 
  1366.     UDPHL + IPHL)
  1367.         {
  1368. #if BSD<44
  1369.         rmsg->udp = (struct udphdr *)&rbuf [(rmsg->ip->ip_v_hl & 0xf) * WORD];
  1370.         rmsg->dhcp = (struct dhcp *)&rbuf [(rmsg->ip->ip_v_hl & 0xf) * WORD +
  1371.                                            UDPHL];
  1372. #else
  1373.         rmsg->udp = (struct udphdr *) &rbuf [rmsg->ip->ip_hl * WORD];
  1374.         rmsg->dhcp = (struct dhcp *) &rbuf [rmsg->ip->ip_hl * WORD +
  1375.                                             UDPHL];
  1376. #endif
  1377.         }
  1378.     else
  1379.         {
  1380.         rmsg->udp = NULL;
  1381.         rmsg->dhcp = NULL;
  1382.         }
  1383.     return;
  1384.     }
  1385. /*******************************************************************************
  1386. *
  1387. * arp_check - use ARP to check if given address is in use
  1388. *
  1389. * This routine broadcasts an ARP request and waits for a reply to determine if
  1390. * an IP address offered by a DHCP server is already in use.
  1391. *
  1392. * RETURNS: ERROR if ARP indicates client in use, or OK otherwise.
  1393. *
  1394. * ERRNO: N/A
  1395. *
  1396. * NOMANUAL
  1397. */
  1398. int arp_check
  1399.     (
  1400.     struct in_addr *target,
  1401.     struct if_info *pIfData     /* interface used by lease */
  1402.     )
  1403.     {
  1404.     int i = 0;
  1405.     int tmp;
  1406.     char inbuf [MAX_ARPLEN];
  1407.     char *pField1;
  1408.     char *pField2;
  1409.     struct arphdr * pArpHdr = NULL;
  1410.     struct ifreq ifr;
  1411.     struct timeval timeout;
  1412.     fd_set  readFds;
  1413.     bzero (inbuf, MAX_ARPLEN);
  1414.     pArpHdr = (struct arphdr *) inbuf;
  1415.     pArpHdr->ar_hrd = htons (pIfData->haddr.htype);
  1416.     pArpHdr->ar_pro = htons (ETHERTYPE_IP);
  1417.     pArpHdr->ar_hln = pIfData->haddr.hlen;
  1418.     pArpHdr->ar_pln = 4;
  1419.     pArpHdr->ar_op = htons (ARPOP_REQUEST);
  1420.     /* Set sender H/W address to your address for ARP requests. (RFC 1541). */
  1421.     pField1 = &inbuf [ARPHL];                   /* Source hardware address. */
  1422.     pField2 = pField1 + pArpHdr->ar_hln + 4;    /* Target hardware address. */
  1423.     for (i = 0; i < pIfData->haddr.hlen; i++)
  1424.         {
  1425.         pField1[i] = pIfData->haddr.haddr[i];
  1426.         pField2[i] = 0;
  1427.         }
  1428.     /* Set sender IP address to 0 for ARP requests as per RFC 1541. */
  1429.     pField1 += pArpHdr->ar_hln;     /* Source IP address. */
  1430.     pField2 += pArpHdr->ar_hln;     /* Target IP address. */
  1431.     tmp = 0;
  1432.     bcopy ( (char *)&tmp, pField1, pArpHdr->ar_pln);
  1433.     bcopy ( (char *)&target->s_addr, pField2, pArpHdr->ar_pln);
  1434.     /* Update BPF filter to check for ARP reply from target IP address. */
  1435.     arpfilter [9].k = htonl (target->s_addr);
  1436.     if (ioctl (bpfArpDev, BIOCSETF, (int)&arpread) != 0)
  1437.         return (OK);     /* Ignore errors (permits use of IP address). */
  1438.     tmp = ARPHL + 2 * (pArpHdr->ar_hln + 4);    /* Size of ARP message. */
  1439.     dhcpcArpSend (pIfData->iface, inbuf, tmp);
  1440.     /* Set BPF to monitor interface for reply. */
  1441.     bzero ( (char *)&ifr, sizeof (struct ifreq));
  1442.     sprintf (ifr.ifr_name, "%s%d", pIfData->iface->if_name,
  1443.                                    pIfData->iface->if_unit);
  1444.     if (ioctl (bpfArpDev, BIOCSETIF, (int)&ifr) != 0)
  1445.         return (OK);     /* Ignore errors (permits use of IP address). */
  1446.     /* Wait one-half second for (unexpected) reply from target IP address. */
  1447.     timeout.tv_sec = 0;
  1448.     timeout.tv_usec = 500000;
  1449.     FD_ZERO (&readFds);
  1450.     FD_SET (bpfArpDev, &readFds);
  1451.     tmp = select (bpfArpDev + 1, &readFds, NULL, NULL, &timeout);
  1452.     /* Disconnect BPF device from input stream until next ARP probe. */
  1453.     ioctl (bpfArpDev, BIOCSTOP, 0); 
  1454.     if (tmp)    /* ARP reply received? Duplicate IP address. */
  1455.         return (ERROR);
  1456.     else        /* Timeout occurred - no ARP reply. Probe succeeded. */
  1457.         return (OK);
  1458.     }
  1459. #ifdef DHCPC_DEBUG
  1460. /*******************************************************************************
  1461. *
  1462. * nvttostr - convert NVT ASCII to strings
  1463. *
  1464. * This routine implements a limited NVT conversion which removes any embedded
  1465. * NULL characters from the input string.
  1466. *
  1467. * RETURNS: N/A
  1468. *
  1469. * ERRNO: N/A
  1470. *
  1471. * NOMANUAL
  1472. */
  1473. LOCAL int nvttostr
  1474.     (
  1475.     char * nvt, 
  1476.     char * str,
  1477.     int  length
  1478.     )
  1479.     {
  1480.     FAST int i = 0;
  1481.     FAST char *tmp = NULL;
  1482.     tmp = str;
  1483.     for (i = 0; i < length; i++) 
  1484.         {
  1485.         if (nvt[i] != '') 
  1486.             {
  1487.             *tmp = nvt[i];
  1488.             tmp++;
  1489.             }
  1490.         }
  1491.     str [length] = '';
  1492.     return (0);
  1493.     }
  1494. #endif
  1495. /*******************************************************************************
  1496. *
  1497. * dhcp_msgtoparam - expand DHCP message into data structure
  1498. *
  1499. * This routine converts a DHCP message from the transmission format into the
  1500. * dhcp_param structure. It copies the core fields directly and multiplexes
  1501. * the options to the appropriate handle_* functions.
  1502. *
  1503. * RETURNS: 0 if conversion successful, or -1 otherwise
  1504. *
  1505. * ERRNO: N/A
  1506. *
  1507. * INTERNAL
  1508. *
  1509. * When calculating the values for the lease timers, floating-point calculations
  1510. * can't be used because some boards (notably the SPARC architectures) disable 
  1511. * software floating point by default to speed up context switching. These 
  1512. * boards abort with an exception when floating point operations are 
  1513. * encountered. The error introduced by the integer approximations is not
  1514. * significant.
  1515. *
  1516. * NOMANUAL
  1517. */
  1518. LOCAL int dhcp_msgtoparam
  1519.     (
  1520.     struct dhcp *msg,
  1521.     int msglen,
  1522.     struct dhcp_param *parameter
  1523.     )
  1524.     {
  1525.     FAST char *optp = NULL;
  1526.     char tag = 0;
  1527.     BOOL sname_is_opt = FALSE;
  1528.     BOOL file_is_opt = FALSE;
  1529.     int err = 0;
  1530.     char *endofopt;
  1531.     endofopt = &msg->options [msglen - DFLTDHCPLEN + DFLTOPTLEN];
  1532.     bzero (parameter->got_option, OPTMASKSIZE);
  1533.     for (optp = &msg->options [MAGIC_LEN]; optp <= endofopt; optp++) 
  1534.         {
  1535.         tag = *optp;
  1536.         /* skip the PAD option */
  1537.         if (tag == _DHCP_PAD_TAG)
  1538.             continue;
  1539.         /* stop processing when the END option is encountered */
  1540.         if (tag == _DHCP_END_TAG) 
  1541.             break;
  1542.         /* handle the "Option Overload" */
  1543.         if (tag == _DHCP_OPT_OVERLOAD_TAG) 
  1544.             {
  1545.             optp += 2;
  1546.             switch (*optp) 
  1547.                 {
  1548.                 case FILE_ISOPT:
  1549.                     file_is_opt = TRUE;
  1550.             break;
  1551.                 case SNAME_ISOPT:
  1552.                     sname_is_opt = TRUE;
  1553.                     break;
  1554.                 case BOTH_AREOPT:
  1555.                     file_is_opt = sname_is_opt = TRUE;
  1556.                     break;
  1557.                 default:
  1558.                     break;
  1559.                 }
  1560.             continue;
  1561.             }
  1562.         if ((tag > 0) && (tag < MAXTAGNUM) && (handle_param [(int)tag] != NULL))
  1563.             {
  1564.             if ( (err = (*handle_param [ (int)tag]) (optp, parameter)) != 0) 
  1565.                 return (err);
  1566.             else 
  1567.                 SETBIT (parameter->got_option, tag);
  1568.             }
  1569.         /* Set the message type tag to distinguish DHCP and BOOTP messages. */
  1570.         else if (tag == _DHCP_MSGTYPE_TAG)
  1571.             SETBIT (parameter->got_option, tag);
  1572.         optp++;
  1573.         optp += *optp;
  1574.         }
  1575.     if (file_is_opt) 
  1576.         {
  1577.         endofopt = &msg->file [MAX_FILE];
  1578.         for (optp = msg->file; optp <= endofopt; optp++) 
  1579.             {
  1580.             tag = *optp;
  1581.             /* skip the PAD option */
  1582.             if (tag == _DHCP_PAD_TAG) 
  1583.                 continue;
  1584.             /* stop processing when the END option is reached */
  1585.             if (tag == _DHCP_END_TAG)
  1586.                 break;
  1587.             if (handle_param [ (int)tag] != NULL) 
  1588.                 {
  1589.                 if ( (err = (*handle_param [ (int)tag]) (optp, parameter)) != 0)
  1590.                     return (err);
  1591.                 else 
  1592.                     SETBIT(parameter->got_option, tag);
  1593.                 }
  1594.             /* Set the message type to distinguish DHCP and BOOTP messages. */
  1595.             else if (tag == _DHCP_MSGTYPE_TAG)
  1596.                 SETBIT (parameter->got_option, tag);
  1597.             optp++;
  1598.             optp += *optp;
  1599.             }
  1600.         } 
  1601.     else 
  1602.         {
  1603.         if ( (parameter->file = calloc (1, strlen (msg->file) + 1)) == NULL) 
  1604.             return (-1);
  1605.         strcpy (parameter->file, msg->file);
  1606.         }
  1607.     if (sname_is_opt) 
  1608.         {
  1609.         endofopt = &msg->sname [MAX_SNAME];
  1610.         for (optp = msg->sname; optp <= endofopt; optp++) 
  1611.             {
  1612.             tag = *optp;
  1613.             /* skip the PAD option */
  1614.             if (tag == _DHCP_PAD_TAG)
  1615.                 continue;
  1616.             /* stop processing when the END option is reached */ 
  1617.             if (tag == _DHCP_END_TAG)
  1618.         break;
  1619.             if (handle_param [ (int)tag] != NULL) 
  1620.                 {
  1621.         if ( (err = (*handle_param [ (int)tag]) (optp, parameter)) != 0)
  1622.             return(err);
  1623.                 else
  1624.             SETBIT (parameter->got_option, tag);
  1625.                 }
  1626.             /* Set the message type to distinguish DHCP and BOOTP messages. */
  1627.             else if (tag == _DHCP_MSGTYPE_TAG)
  1628.                 SETBIT (parameter->got_option, tag);
  1629.             optp++;
  1630.             optp += *optp;
  1631.             }
  1632.         } 
  1633.     else 
  1634.         {
  1635.         if ( (parameter->sname = calloc (1, strlen (msg->sname) + 1)) == NULL) 
  1636.             return (-1);
  1637.         strcpy(parameter->sname, msg->sname);
  1638.         }
  1639.     parameter->ciaddr.s_addr = msg->ciaddr.s_addr;
  1640.     parameter->yiaddr.s_addr = msg->yiaddr.s_addr;
  1641.     parameter->siaddr.s_addr = msg->siaddr.s_addr;
  1642.     parameter->giaddr.s_addr = msg->giaddr.s_addr;
  1643.     if (ISSET (parameter->got_option, _DHCP_MSGTYPE_TAG))
  1644.         parameter->msgtype = DHCP_NATIVE;
  1645.     else
  1646.         parameter->msgtype = DHCP_BOOTP;
  1647.     /* Set lease duration to infinite for BOOTP replies. */
  1648.     if (parameter->msgtype == DHCP_BOOTP)
  1649.         {
  1650.         parameter->lease_duration = ~0;
  1651.         return (0);
  1652.         }
  1653.     /* Assign any server name provided if 'sname' used for options. */
  1654.   
  1655.     if (sname_is_opt)
  1656.         {
  1657.         parameter->sname = parameter->temp_sname;
  1658.         parameter->temp_sname = NULL;
  1659.         }
  1660.     /* Assign any bootfile provided if 'file' used for options. */
  1661.     if (file_is_opt)
  1662.         {
  1663.         if (ISSET (parameter->got_option, _DHCP_BOOTFILE_TAG))
  1664.             {
  1665.             parameter->file = parameter->temp_file;
  1666.             parameter->temp_file = NULL;
  1667.             }
  1668.         }
  1669.   
  1670.     if (parameter->dhcp_t1 == 0)
  1671.         {
  1672.         /* Timer t1 is half the lease duration - but don't divide. */
  1673.         parameter->dhcp_t1 = (parameter->lease_duration) >> 1;
  1674.         SETBIT (parameter->got_option, _DHCP_T1_TAG);
  1675.         }
  1676.     if (parameter->dhcp_t2 == 0)
  1677.         {
  1678.         /* Timer T2 is .875 of the lease - but don't use floating point. */
  1679.         int tmp = (parameter->lease_duration * 7) >> 3;
  1680.         parameter->dhcp_t2 = (unsigned long) tmp;
  1681.         SETBIT(parameter->got_option, _DHCP_T2_TAG);
  1682.         }
  1683.     return(0);
  1684.     }
  1685. /*******************************************************************************
  1686. *
  1687. * clean_param - clean the parameters data structure
  1688. *
  1689. * This routine frees all the memory allocated for the storage of parameters
  1690. * received from a DHCP server. It is called to remove the unselected offers
  1691. * or if an error occurs in the state machine after offers have been received.
  1692. *
  1693. * RETURNS: 0, always.
  1694. *
  1695. * ERRNO: N/A
  1696. *
  1697. * NOMANUAL
  1698. */
  1699. LOCAL int clean_param
  1700.     (
  1701.     struct dhcp_param *param
  1702.     )
  1703.     {
  1704.     if (param == NULL)
  1705.         return(0);
  1706.     if (param->sname != NULL) 
  1707.         free (param->sname);
  1708.     if (param->temp_sname != NULL) 
  1709.         free (param->temp_sname);
  1710.     if (param->file != NULL) 
  1711.         free (param->file);
  1712.     if (param->temp_file != NULL) 
  1713.         free (param->temp_file);
  1714.     if (param->hostname != NULL) 
  1715.         free (param->hostname);
  1716.     if (param->merit_dump != NULL) 
  1717.         free (param->merit_dump);
  1718.     if (param->dns_domain != NULL) 
  1719.         free (param->dns_domain);
  1720.     if (param->root_path != NULL) 
  1721.         free (param->root_path);
  1722.     if (param->extensions_path != NULL) 
  1723.         free (param->extensions_path);
  1724.     if (param->nis_domain != NULL) 
  1725.         free (param->nis_domain);
  1726.     if (param->nb_scope != NULL) 
  1727.         free (param->nb_scope);
  1728.     if (param->errmsg != NULL) 
  1729.         free (param->errmsg);
  1730.     if (param->nisp_domain != NULL) 
  1731.         free (param->nisp_domain);
  1732.     if (param->mtu_plateau_table != NULL) 
  1733.         {
  1734.         if (param->mtu_plateau_table->shortnum != NULL)
  1735.             free (param->mtu_plateau_table->shortnum);
  1736.         free (param->mtu_plateau_table);
  1737.         }
  1738.     if (param->subnet_mask != NULL) 
  1739.         free (param->subnet_mask);
  1740.     if (param->swap_server != NULL) 
  1741.         free (param->swap_server);
  1742.     if (param->brdcast_addr != NULL) 
  1743.         free (param->brdcast_addr);
  1744.     if (param->router != NULL) 
  1745.         {
  1746.         if (param->router->addr != NULL)
  1747.             free (param->router->addr);
  1748.         free (param->router);
  1749.         }
  1750.     if (param->time_server != NULL) 
  1751.         {
  1752.         if (param->time_server->addr != NULL)
  1753.             free (param->time_server->addr);
  1754.         free (param->time_server);
  1755.         }
  1756.     if (param->name_server != NULL) 
  1757.         {
  1758.         if (param->name_server->addr != NULL)
  1759.             free (param->name_server->addr);
  1760.         free (param->name_server);
  1761.         }
  1762.     if (param->dns_server != NULL) 
  1763.         {
  1764.         if (param->dns_server->addr != NULL)
  1765.             free (param->dns_server->addr);
  1766.         free (param->dns_server);
  1767.         }
  1768.     if (param->log_server != NULL) 
  1769.         {
  1770.         if (param->log_server->addr != NULL)
  1771.             free (param->log_server->addr);
  1772.         free (param->log_server);
  1773.         }
  1774.     if (param->cookie_server != NULL) 
  1775.         {
  1776.         if (param->cookie_server->addr != NULL)
  1777.             free (param->cookie_server->addr);
  1778.         free (param->cookie_server);
  1779.         }
  1780.     if (param->lpr_server != NULL)
  1781.         {
  1782.         if (param->lpr_server->addr != NULL)
  1783.             free (param->lpr_server->addr);
  1784.         free (param->lpr_server);
  1785.         }
  1786.     if (param->impress_server != NULL) 
  1787.         {
  1788.         if (param->impress_server->addr != NULL)
  1789.             free (param->impress_server->addr);
  1790.         free (param->impress_server);
  1791.         }
  1792.     if (param->rls_server != NULL) 
  1793.         {
  1794.         if (param->rls_server->addr != NULL)
  1795.             free (param->rls_server->addr);
  1796.         free (param->rls_server);
  1797.         }
  1798.     if (param->policy_filter != NULL) 
  1799.         {
  1800.         if (param->policy_filter->addr != NULL)
  1801.             free (param->policy_filter->addr);
  1802.         free (param->policy_filter);
  1803.         }
  1804.     if (param->static_route != NULL) 
  1805.         {
  1806.         if (param->static_route->addr != NULL)
  1807.             free (param->static_route->addr);
  1808.         free (param->static_route);
  1809.         }
  1810.     if (param->nis_server != NULL) 
  1811.         {
  1812.         if (param->nis_server->addr != NULL)
  1813.             free (param->nis_server->addr);
  1814.         free (param->nis_server);
  1815.         }
  1816.     if (param->ntp_server != NULL) 
  1817.         {
  1818.         if (param->ntp_server->addr != NULL)
  1819.             free (param->ntp_server->addr);
  1820.         free (param->ntp_server);
  1821.         }
  1822.     if (param->nbn_server != NULL) 
  1823.         {
  1824.         if (param->nbn_server->addr != NULL)
  1825.             free (param->nbn_server->addr);
  1826.         free (param->nbn_server);
  1827.         }
  1828.     if (param->nbdd_server != NULL) 
  1829.         {
  1830.         if (param->nbdd_server->addr != NULL)
  1831.             free (param->nbdd_server->addr);
  1832.         free (param->nbdd_server);
  1833.         }
  1834.     if (param->xfont_server != NULL) 
  1835.         {
  1836.         if (param->xfont_server->addr != NULL)
  1837.             free (param->xfont_server->addr);
  1838.         free (param->xfont_server);
  1839.         }
  1840.     if (param->xdisplay_manager != NULL) 
  1841.         {
  1842.         if (param->xdisplay_manager->addr != NULL)
  1843.             free (param->xdisplay_manager->addr);
  1844.         free (param->xdisplay_manager);
  1845.         }
  1846.     if (param->nisp_server != NULL) 
  1847.         {
  1848.         if (param->nisp_server->addr != NULL)
  1849.             free (param->nisp_server->addr);
  1850.         free (param->nisp_server);
  1851.         }
  1852.     if (param->mobileip_ha != NULL) 
  1853.         {
  1854.         if (param->mobileip_ha->addr != NULL)
  1855.             free (param->mobileip_ha->addr);
  1856.         free (param->mobileip_ha);
  1857.         }
  1858.     if (param->smtp_server != NULL) 
  1859.         {
  1860.         if (param->smtp_server->addr != NULL)
  1861.             free (param->smtp_server->addr);
  1862.         free (param->smtp_server);
  1863.         }
  1864.     if (param->pop3_server != NULL) 
  1865.         {
  1866.         if (param->pop3_server->addr != NULL)
  1867.             free (param->pop3_server->addr);
  1868.         free (param->pop3_server);
  1869.         }
  1870.     if (param->nntp_server != NULL) 
  1871.         {
  1872.         if (param->nntp_server->addr != NULL)
  1873.             free (param->nntp_server->addr);
  1874.         free (param->nntp_server);
  1875.         }
  1876.     if (param->dflt_www_server != NULL) 
  1877.         {
  1878.         if (param->dflt_www_server->addr != NULL)
  1879.             free (param->dflt_www_server->addr);
  1880.         free (param->dflt_www_server);
  1881.         }
  1882.     if (param->dflt_finger_server != NULL) 
  1883.         {
  1884.         if (param->dflt_finger_server->addr != NULL)
  1885.             free (param->dflt_finger_server->addr);
  1886.         free (param->dflt_finger_server);
  1887.         }
  1888.     if (param->dflt_irc_server != NULL) 
  1889.         {
  1890.         if (param->dflt_irc_server->addr != NULL)
  1891.             free (param->dflt_irc_server->addr);
  1892.         free (param->dflt_irc_server);
  1893.         }
  1894.     if (param->streettalk_server != NULL) 
  1895.         {
  1896.         if (param->streettalk_server->addr != NULL)
  1897.             free (param->streettalk_server->addr);
  1898.         free (param->streettalk_server);
  1899.         }
  1900.     if (param->stda_server != NULL) 
  1901.         {
  1902.         if (param->stda_server->addr != NULL)
  1903.             free (param->stda_server->addr);
  1904.         free (param->stda_server);
  1905.         }
  1906.     if (param->vendlist != NULL)
  1907.         free (param->vendlist);
  1908.     bzero ( (char *)param, sizeof (struct dhcp_param));
  1909.     return (0);
  1910.     }
  1911. /*******************************************************************************
  1912. *
  1913. * merge_param - combine the parameters from DHCP server responses
  1914. *
  1915. * This routine copies any parameters from an initial lease offer which were not
  1916. * supplied in the later acknowledgement from the server. If the acknowledgement
  1917. * from the server duplicates parameters from the offer, then the memory       
  1918. * allocated for those parameters in the offer is released.
  1919. *
  1920. * RETURNS: 0, always.
  1921. *
  1922. * ERRNO: N/A
  1923. *
  1924. * NOMANUAL
  1925. */
  1926. /*
  1927.  * if there is no information in newp but oldp, copy it to newp
  1928.  * else free the appropriate memory of oldp
  1929.  */
  1930. LOCAL int merge_param
  1931.     (
  1932.     struct dhcp_param *oldp,     /* Parameters from lease offer. */
  1933.     struct dhcp_param *newp      /* Parameters from lease acknowledgement. */
  1934.     )
  1935.     {
  1936.     if (oldp == NULL || newp == NULL)
  1937.         return (0);
  1938.     if (newp->sname == NULL && oldp->sname != NULL)
  1939.         newp->sname = oldp->sname;
  1940.     else if (oldp->sname != NULL)
  1941.         free (oldp->sname);
  1942.     if (newp->file == NULL && oldp->file != NULL)
  1943.         newp->file = oldp->file;
  1944.     else if (oldp->file != NULL) 
  1945.         free (oldp->file);
  1946.  
  1947.     if (newp->hostname == NULL && oldp->hostname != NULL)
  1948.         newp->hostname = oldp->hostname;
  1949.     else if (oldp->hostname != NULL)
  1950.         free (oldp->hostname);
  1951.     if (newp->merit_dump == NULL && oldp->merit_dump != NULL)
  1952.         newp->merit_dump = oldp->merit_dump;
  1953.     else if (oldp->merit_dump != NULL)
  1954.         free (oldp->merit_dump);
  1955.     if (newp->dns_domain == NULL && oldp->dns_domain != NULL)
  1956.         newp->dns_domain = oldp->dns_domain;
  1957.     else if (oldp->dns_domain != NULL) 
  1958.         free (oldp->dns_domain);
  1959.     if (newp->root_path == NULL && oldp->root_path != NULL)
  1960.         newp->root_path = oldp->root_path;
  1961.     else if (oldp->root_path != NULL) 
  1962.         free (oldp->root_path);
  1963.     if (newp->extensions_path == NULL && oldp->extensions_path != NULL)
  1964.         newp->extensions_path = oldp->extensions_path;
  1965.     else if (oldp->extensions_path != NULL) 
  1966.         free (oldp->extensions_path);
  1967.     if (newp->nis_domain == NULL && oldp->nis_domain != NULL)
  1968.         newp->nis_domain = oldp->nis_domain;
  1969.     else if (oldp->nis_domain != NULL) 
  1970.         free (oldp->nis_domain);
  1971.     if (newp->nb_scope == NULL && oldp->nb_scope != NULL)
  1972.         newp->nb_scope = oldp->nb_scope;
  1973.     else if (oldp->nb_scope != NULL) 
  1974.         free (oldp->nb_scope);
  1975.     if (newp->errmsg == NULL && oldp->errmsg != NULL)
  1976.         newp->errmsg = oldp->errmsg;
  1977.     else if (oldp->errmsg != NULL) 
  1978.         free (oldp->errmsg);
  1979.     if (newp->nisp_domain == NULL && oldp->nisp_domain != NULL)
  1980.         newp->nisp_domain = oldp->nisp_domain;
  1981.     else if (oldp->nisp_domain != NULL) 
  1982.         free (oldp->nisp_domain);
  1983.     if (newp->mtu_plateau_table == NULL && oldp->mtu_plateau_table != NULL) 
  1984.         newp->mtu_plateau_table = oldp->mtu_plateau_table;
  1985.     else 
  1986.         {
  1987.         if (oldp->mtu_plateau_table != NULL)
  1988.             {
  1989.             if (oldp->mtu_plateau_table->shortnum != NULL)
  1990.                 free (oldp->mtu_plateau_table->shortnum);
  1991.             free (oldp->mtu_plateau_table);
  1992.             }
  1993.         }
  1994.     if (newp->subnet_mask == NULL && oldp->subnet_mask != NULL)
  1995.         newp->subnet_mask = oldp->subnet_mask;
  1996.     else if (oldp->subnet_mask != NULL) 
  1997.         free (oldp->subnet_mask);
  1998.     if (newp->swap_server == NULL && oldp->swap_server != NULL)
  1999.         newp->swap_server = oldp->swap_server;
  2000.     else if (oldp->swap_server != NULL) 
  2001.         free (oldp->swap_server);
  2002.     if (newp->brdcast_addr == NULL && oldp->brdcast_addr != NULL)
  2003.         newp->brdcast_addr = oldp->brdcast_addr;
  2004.     else if (oldp->brdcast_addr != NULL) 
  2005.         free (oldp->brdcast_addr);
  2006.     if (newp->router_solicit.s_addr == 0 && oldp->router_solicit.s_addr != 0)
  2007.         bcopy ( (char *)&oldp->router_solicit, 
  2008.                (char *)&newp->router_solicit, sizeof (u_long));
  2009.     if (newp->router == NULL && oldp->router != NULL) 
  2010.       newp->router = oldp->router;
  2011.     else 
  2012.         {
  2013.         if (oldp->router != NULL && oldp->router->addr != NULL) 
  2014.             free (oldp->router->addr);
  2015.         if (oldp->router != NULL)
  2016.             free (oldp->router);
  2017.         }
  2018.     if (newp->time_server == NULL && oldp->time_server != NULL)
  2019.         newp->time_server = oldp->time_server;
  2020.     else 
  2021.         { 
  2022.         if (oldp->time_server != NULL && oldp->time_server->addr != NULL) 
  2023.             free (oldp->time_server->addr);
  2024.         if (oldp->time_server != NULL)
  2025.             free (oldp->time_server);
  2026.         }
  2027.     if (newp->name_server == NULL && oldp->name_server != NULL) 
  2028.         newp->name_server = oldp->name_server;
  2029.     else 
  2030.         {
  2031.         if (oldp->name_server != NULL && oldp->name_server->addr != NULL) 
  2032.             free (oldp->name_server->addr);
  2033.         if (oldp->name_server != NULL)
  2034.             free (oldp->name_server);
  2035.         }
  2036.     if (newp->dns_server == NULL && oldp->dns_server != NULL) 
  2037.         newp->dns_server = oldp->dns_server;
  2038.     else 
  2039.         {
  2040.         if (oldp->dns_server != NULL && oldp->dns_server->addr != NULL) 
  2041.             free (oldp->dns_server->addr);
  2042.         if (oldp->dns_server != NULL)
  2043.             free (oldp->dns_server);
  2044.         }
  2045.     if (newp->log_server == NULL && oldp->log_server != NULL) 
  2046.         newp->log_server = oldp->log_server;
  2047.     else 
  2048.         {
  2049.         if (oldp->log_server != NULL && oldp->log_server->addr != NULL) 
  2050.             free (oldp->log_server->addr);
  2051.         if (oldp->log_server != NULL)
  2052.             free (oldp->log_server);
  2053.         }
  2054.     if (newp->cookie_server == NULL && oldp->cookie_server != NULL) 
  2055.         newp->cookie_server = oldp->cookie_server;
  2056.     else 
  2057.         {
  2058.         if (oldp->cookie_server != NULL && oldp->cookie_server->addr != NULL) 
  2059.             free (oldp->cookie_server->addr);
  2060.         if (oldp->cookie_server != NULL)
  2061.             free (oldp->cookie_server);
  2062.         }
  2063.     if (newp->lpr_server == NULL && oldp->lpr_server != NULL) 
  2064.         newp->lpr_server = oldp->lpr_server;
  2065.     else 
  2066.         {
  2067.         if (oldp->lpr_server != NULL && oldp->lpr_server->addr != NULL) 
  2068.             free (oldp->lpr_server->addr);
  2069.         if (oldp->lpr_server != NULL)
  2070.             free (oldp->lpr_server);
  2071.         }
  2072.     if (newp->impress_server == NULL && oldp->impress_server != NULL) 
  2073.         newp->impress_server = oldp->impress_server;
  2074.     else 
  2075.         {
  2076.         if (oldp->impress_server != NULL && oldp->impress_server->addr != NULL)
  2077.             free (oldp->impress_server->addr);
  2078.         if (oldp->impress_server != NULL)
  2079.             free (oldp->impress_server);
  2080.         }
  2081.     if (newp->rls_server == NULL && oldp->rls_server != NULL) 
  2082.         newp->rls_server = oldp->rls_server;
  2083.     else 
  2084.         {
  2085.         if (oldp->rls_server != NULL && oldp->rls_server->addr != NULL) 
  2086.             free (oldp->rls_server->addr);
  2087.         if (oldp->rls_server != NULL)
  2088.             free (oldp->rls_server);
  2089.         }
  2090.     if (newp->policy_filter == NULL && oldp->policy_filter != NULL) 
  2091.         newp->policy_filter = oldp->policy_filter;
  2092.     else 
  2093.         {
  2094.         if (oldp->policy_filter != NULL && oldp->policy_filter->addr != NULL) 
  2095.             free (oldp->policy_filter->addr);
  2096.         if (oldp->policy_filter != NULL)
  2097.             free (oldp->policy_filter);
  2098.         }
  2099.     if (newp->static_route == NULL && oldp->static_route != NULL) 
  2100.         newp->static_route = oldp->static_route;
  2101.     else 
  2102.         {
  2103.         if (oldp->static_route != NULL && oldp->static_route->addr != NULL) 
  2104.             free (oldp->static_route->addr);
  2105.         if (oldp->static_route != NULL)
  2106.             free (oldp->static_route);
  2107.         }
  2108.     if (newp->nis_server == NULL && oldp->nis_server != NULL) 
  2109.         newp->nis_server = oldp->nis_server;
  2110.     else 
  2111.         {
  2112.         if (oldp->nis_server != NULL && oldp->nis_server->addr != NULL) 
  2113.             free (oldp->nis_server->addr);
  2114.         if (oldp->nis_server != NULL)
  2115.             free (oldp->nis_server);
  2116.         }
  2117.     if (newp->ntp_server == NULL && oldp->ntp_server != NULL) 
  2118.         newp->ntp_server = oldp->ntp_server;
  2119.     else 
  2120.         {
  2121.         if (oldp->ntp_server != NULL && oldp->ntp_server->addr != NULL) 
  2122.             free (oldp->ntp_server->addr);
  2123.         if (oldp->ntp_server != NULL)
  2124.             free (oldp->ntp_server);
  2125.         }
  2126.     if (newp->nbn_server == NULL && oldp->nbn_server != NULL) 
  2127.         newp->nbn_server = oldp->nbn_server;
  2128.     else 
  2129.         {
  2130.         if (oldp->nbn_server != NULL && oldp->nbn_server->addr != NULL) 
  2131.             free (oldp->nbn_server->addr);
  2132.         if (oldp->nbn_server != NULL)
  2133.             free (oldp->nbn_server);
  2134.         }
  2135.     if (newp->nbdd_server == NULL && oldp->nbdd_server != NULL) 
  2136.         newp->nbdd_server = oldp->nbdd_server;
  2137.     else 
  2138.         {
  2139.         if (oldp->nbdd_server != NULL && oldp->nbdd_server->addr != NULL) 
  2140.             free (oldp->nbdd_server->addr);
  2141.         if (oldp->nbdd_server != NULL)
  2142.             free (oldp->nbdd_server);
  2143.         }
  2144.     if (newp->xfont_server == NULL && oldp->xfont_server != NULL) 
  2145.         newp->xfont_server = oldp->xfont_server;
  2146.     else 
  2147.         {
  2148.         if (oldp->xfont_server != NULL && oldp->xfont_server->addr != NULL) 
  2149.             free (oldp->xfont_server->addr);
  2150.         if (oldp->xfont_server != NULL)
  2151.             free (oldp->xfont_server);
  2152.         }
  2153.     if (newp->xdisplay_manager == NULL && oldp->xdisplay_manager != NULL) 
  2154.         newp->xdisplay_manager = oldp->xdisplay_manager;
  2155.     else 
  2156.         {
  2157.         if (oldp->xdisplay_manager != NULL && 
  2158.             oldp->xdisplay_manager->addr != NULL) 
  2159.             free (oldp->xdisplay_manager->addr);
  2160.         if (oldp->xdisplay_manager != NULL)
  2161.             free (oldp->xdisplay_manager);
  2162.         }
  2163.     if (newp->nisp_server == NULL && oldp->nisp_server != NULL) 
  2164.         newp->nisp_server = oldp->nisp_server;
  2165.     else 
  2166.         {
  2167.         if (oldp->nisp_server != NULL && oldp->nisp_server->addr != NULL) 
  2168.             free (oldp->nisp_server->addr);
  2169.         if (oldp->nisp_server != NULL)
  2170.             free (oldp->nisp_server);
  2171.         }
  2172.     if (newp->mobileip_ha == NULL && oldp->mobileip_ha != NULL) 
  2173.         newp->mobileip_ha = oldp->mobileip_ha;
  2174.     else 
  2175.         { 
  2176.         if (oldp->mobileip_ha != NULL && oldp->mobileip_ha->addr != NULL) 
  2177.             free (oldp->mobileip_ha->addr);
  2178.         if (oldp->mobileip_ha != NULL)
  2179.             free (oldp->mobileip_ha);
  2180.         }
  2181.     if (newp->smtp_server == NULL && oldp->smtp_server != NULL) 
  2182.         newp->smtp_server = oldp->smtp_server;
  2183.     else 
  2184.         {
  2185.         if (oldp->smtp_server != NULL && oldp->smtp_server->addr != NULL) 
  2186.             free (oldp->smtp_server->addr);
  2187.         if (oldp->smtp_server != NULL)
  2188.             free (oldp->smtp_server);
  2189.         }
  2190.     if (newp->pop3_server == NULL && oldp->pop3_server != NULL) 
  2191.         newp->pop3_server = oldp->pop3_server;
  2192.     else 
  2193.         {
  2194.         if (oldp->pop3_server != NULL && oldp->pop3_server->addr != NULL) 
  2195.             free (oldp->pop3_server->addr);
  2196.         if (oldp->pop3_server != NULL)
  2197.             free (oldp->pop3_server);
  2198.         }
  2199.     if (newp->nntp_server == NULL && oldp->nntp_server != NULL) 
  2200.         newp->nntp_server = oldp->nntp_server;
  2201.     else 
  2202.         {
  2203.         if (oldp->nntp_server != NULL && oldp->nntp_server->addr != NULL) 
  2204.             free (oldp->nntp_server->addr);
  2205.         if (oldp->nntp_server != NULL)
  2206.             free (oldp->nntp_server);
  2207.         }
  2208.     if (newp->dflt_www_server == NULL && oldp->dflt_www_server != NULL) 
  2209.         newp->dflt_www_server = oldp->dflt_www_server;
  2210.     else 
  2211.         {
  2212.         if (oldp->dflt_www_server != NULL && 
  2213.             oldp->dflt_www_server->addr != NULL) 
  2214.             free (oldp->dflt_www_server->addr);
  2215.         if (oldp->dflt_www_server != NULL)
  2216.             free (oldp->dflt_www_server);
  2217.         }
  2218.     if (newp->dflt_finger_server == NULL && oldp->dflt_finger_server != NULL)
  2219.         newp->dflt_finger_server = oldp->dflt_finger_server;
  2220.     else 
  2221.         {
  2222.         if (oldp->dflt_finger_server != NULL && 
  2223.             oldp->dflt_finger_server->addr != NULL) 
  2224.             free (oldp->dflt_finger_server->addr);
  2225.         if (oldp->dflt_finger_server != NULL)
  2226.             free (oldp->dflt_finger_server);
  2227.         }
  2228.     if (newp->dflt_irc_server == NULL && oldp->dflt_irc_server != NULL) 
  2229.         newp->dflt_irc_server = oldp->dflt_irc_server;
  2230.     else 
  2231.         {
  2232.         if (oldp->dflt_irc_server != NULL && 
  2233.             oldp->dflt_irc_server->addr != NULL) 
  2234.             free (oldp->dflt_irc_server->addr);
  2235.         if (oldp->dflt_irc_server != NULL)
  2236.             free (oldp->dflt_irc_server);
  2237.         }
  2238.     if (newp->streettalk_server == NULL && oldp->streettalk_server != NULL) 
  2239.         newp->streettalk_server = oldp->streettalk_server;
  2240.     else 
  2241.         {
  2242.         if (oldp->streettalk_server != NULL && 
  2243.             oldp->streettalk_server->addr != NULL) 
  2244.             free (oldp->streettalk_server->addr);
  2245.         if (oldp->streettalk_server != NULL)
  2246.             free (oldp->streettalk_server);
  2247.         }
  2248.     if (newp->stda_server == NULL && oldp->stda_server != NULL) 
  2249.         newp->stda_server = oldp->stda_server;
  2250.     else 
  2251.         {
  2252.         if (oldp->stda_server != NULL && oldp->stda_server->addr != NULL) 
  2253.             free (oldp->stda_server->addr);
  2254.         if (oldp->stda_server != NULL)
  2255.             free (oldp->stda_server);
  2256.         }
  2257.     /* Remove any vendor-specific information from an earlier response. */
  2258.     if (oldp->vendlist != NULL)
  2259.         free (oldp->vendlist);
  2260.  
  2261.     return (0);
  2262.     }
  2263. /*******************************************************************************
  2264. *
  2265. * initialize - perform general DHCP client initialization
  2266. *
  2267. * This routine sets the DHCP ports, resets the network interface, and allocates
  2268. * storage for incoming messages. It is called from dhcp_boot_client before the
  2269. * finite state machine is executed.
  2270. *
  2271. * RETURNS: 0 if initialization successful, or -1 otherwise. 
  2272. *
  2273. * ERRNO: N/A
  2274. *
  2275. * NOMANUAL
  2276. */
  2277. LOCAL int initialize
  2278.     (
  2279.     int  serverPort,  /* port used by DHCP servers */
  2280.     int  clientPort  /* port used by DHCP clients */
  2281.     )
  2282.     {
  2283.     char *  sbufp;
  2284.     int  arpSize;  /* Maximum size for ARP reply. */
  2285.     int         result;
  2286.     /*
  2287.      * Create BPF device for performing ARP probes. The buffer size
  2288.      * for the device is equal to the maximum link header (determined
  2289.      * from the provided DHCP buffer size) plus the largest possible
  2290.      * ARP payload for IP addresses.
  2291.      */
  2292.  
  2293.     arpSize = dhcpcBootLeaseData.ifData.bufSize - DFLTDHCPLEN - UDPHL - IPHL;
  2294.     arpSize += MAX_ARPLEN + sizeof (struct bpf_hdr);
  2295.     if (bpfDevCreate ("/bpf/dhcpc-arp", 1, arpSize) == ERROR)
  2296.         {
  2297.         return (-1);
  2298.         }
  2299.     bpfArpDev = open ("/bpf/dhcpc-arp0", 0, 0);
  2300.     if (bpfArpDev < 0)
  2301.         {
  2302.         bpfDevDelete ("/bpf/dhcpc-arp0");
  2303.         return (-1);
  2304.         }
  2305.     /* Enable immediate mode for reading messages */
  2306.     result = 1;
  2307.     result = ioctl (bpfArpDev, BIOCIMMEDIATE, (int)&result);
  2308.     if (result != 0)
  2309. {
  2310. close (bpfArpDev);
  2311. bpfDevDelete ("/bpf/dhcpc-arp0");
  2312.         return (-1);
  2313. }
  2314.     /*
  2315.      * Set filter to accept ARP replies when the arp_check() routine
  2316.      * attaches the BPF device to a network interface.
  2317.      */
  2318.     if (ioctl (bpfArpDev, BIOCSETF, (int)&arpread) != 0)
  2319.         {
  2320.         close (bpfArpDev);
  2321.         bpfDevDelete ("/bpf/dhcpc-arp0");
  2322.         return (-1);
  2323.         }
  2324.     /* Reseed random number generator. */
  2325.     srand (generate_xid ());
  2326.     /* Always use default ports for client and server. */
  2327.     dhcps_port = htons (serverPort);
  2328.     dhcpc_port = htons (clientPort);
  2329.     /* Allocate transmit buffer equal to max. message size from user. */
  2330.     sbuf.size = dhcpcBootLeaseData.ifData.bufSize;
  2331.     if ( (sbuf.buf = (char *)memalign (4, sbuf.size)) == NULL) 
  2332.         {
  2333. #ifdef DHCPC_DEBUG
  2334.         logMsg ("allocation error for sbuf in initializen", 0, 0, 0, 0, 0, 0);
  2335. #endif
  2336.         close (bpfArpDev);
  2337.         bpfDevDelete ("/bpf/dhcpc-arp0");
  2338.         return(-1);
  2339.         } 
  2340.     bzero (sbuf.buf, sbuf.size);
  2341.     sbufp = sbuf.buf;
  2342.     dhcpcMsgOut.ip = (struct ip *)sbufp;
  2343.     dhcpcMsgOut.udp = (struct udphdr *)&sbufp [IPHL];
  2344.     dhcpcMsgOut.dhcp = (struct dhcp *)&sbufp [IPHL + UDPHL];
  2345.     return (0);
  2346.     }
  2347. /*******************************************************************************
  2348. *
  2349. * make_decline - construct a DHCP decline message
  2350. *
  2351. * This routine constructs an outgoing UDP/IP message containing the values
  2352. * required to decline an offered IP address.
  2353. *
  2354. * RETURNS: Size of decline message, in bytes, or 0 on error.
  2355. *
  2356. * ERRNO: N/A
  2357. *
  2358. * NOMANUAL
  2359. */
  2360. LOCAL int make_decline
  2361.     (
  2362.     struct dhcp_reqspec *pDhcpcReqSpec
  2363.     )
  2364.     {
  2365.     int offopt = 0;  /* offset in options field */
  2366.     int msgsize;  /* total size of DHCP message */
  2367.     u_long tmpul = 0;
  2368.     struct ps_udph pudph;
  2369.     bzero ( (char *)&pudph, sizeof (pudph));
  2370.     /* construct dhcp part */
  2371.     bzero (sbuf.buf, sbuf.size);
  2372.     dhcpcMsgOut.dhcp->op = BOOTREQUEST;
  2373.     dhcpcMsgOut.dhcp->htype = dhcpcIntface.haddr.htype;
  2374.     dhcpcMsgOut.dhcp->hlen = dhcpcIntface.haddr.hlen;
  2375.     dhcpcMsgOut.dhcp->xid = htonl (generate_xid ());
  2376.     dhcpcMsgOut.dhcp->giaddr = dhcpcMsgIn.dhcp->giaddr;
  2377.     bcopy (dhcpcIntface.haddr.haddr, dhcpcMsgOut.dhcp->chaddr,
  2378.            dhcpcMsgOut.dhcp->hlen);
  2379.     /* insert magic cookie */
  2380.     bcopy ( (char *)dhcpCookie, dhcpcMsgOut.dhcp->options, MAGIC_LEN);
  2381.     offopt = MAGIC_LEN;
  2382.     /* insert message type */
  2383.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MSGTYPE_TAG;
  2384.     dhcpcMsgOut.dhcp->options [offopt++] = 1;
  2385.     dhcpcMsgOut.dhcp->options [offopt++] = DHCPDECLINE;
  2386.     /* insert requested IP */
  2387.     if (pDhcpcReqSpec->ipaddr.s_addr == 0) 
  2388.         return (0);
  2389.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_REQUEST_IPADDR_TAG;
  2390.     dhcpcMsgOut.dhcp->options [offopt++] = 4;
  2391.     bcopy ( (char *)&pDhcpcReqSpec->ipaddr,
  2392.            &dhcpcMsgOut.dhcp->options [offopt], 4);
  2393.     offopt += 4;
  2394.     /* insert client identifier */
  2395.     if (pDhcpcReqSpec->clid != NULL)
  2396.         {
  2397.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_CLIENT_ID_TAG;
  2398.         dhcpcMsgOut.dhcp->options [offopt++] = pDhcpcReqSpec->clid->len;
  2399.         bcopy (pDhcpcReqSpec->clid->id, &dhcpcMsgOut.dhcp->options [offopt], 
  2400.                pDhcpcReqSpec->clid->len);
  2401.         offopt += pDhcpcReqSpec->clid->len;
  2402.         }
  2403.     /* insert server identifier */
  2404.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_SERVER_ID_TAG;
  2405.     dhcpcMsgOut.dhcp->options [offopt++] = 4;
  2406.     bcopy ( (char *)&dhcpcBootParam->server_id,
  2407.            &dhcpcMsgOut.dhcp->options [offopt], 4);
  2408.    offopt += 4;
  2409.     /* Insert error message, if available. */
  2410.     if (pDhcpcReqSpec->dhcp_errmsg != NULL)
  2411.         {
  2412.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_ERRMSG_TAG;
  2413.         dhcpcMsgOut.dhcp->options [offopt++] = 
  2414.                                          strlen (pDhcpcReqSpec->dhcp_errmsg);
  2415.         bcopy (pDhcpcReqSpec->dhcp_errmsg, &dhcpcMsgOut.dhcp->options [offopt],
  2416.                strlen (pDhcpcReqSpec->dhcp_errmsg));
  2417.         offopt += strlen (pDhcpcReqSpec->dhcp_errmsg);
  2418.         }
  2419.     dhcpcMsgOut.dhcp->options [offopt] = _DHCP_END_TAG;
  2420.     /*
  2421.      * For backward compatibility with earlier DHCP servers, set the
  2422.      * reported message size to be at least as large as a BOOTP message.
  2423.      */
  2424.     msgsize = (DFLTDHCPLEN - DFLTOPTLEN) + offopt + 1;
  2425.     if (msgsize < DFLTBOOTPLEN)
  2426.         msgsize = DFLTBOOTPLEN;
  2427.     /* construct udp part */
  2428.     dhcpcMsgOut.udp->uh_sport = dhcpc_port;
  2429.     dhcpcMsgOut.udp->uh_dport = dhcps_port;
  2430.     dhcpcMsgOut.udp->uh_ulen = htons (msgsize + UDPHL);
  2431.     dhcpcMsgOut.udp->uh_sum = 0;
  2432.     /* fill pseudo udp header */
  2433.     pudph.srcip.s_addr = 0;
  2434.     pudph.dstip.s_addr = dhcpcBootParam->server_id.s_addr;
  2435.     pudph.zero = 0;
  2436.     pudph.prto = IPPROTO_UDP;
  2437.     pudph.ulen = dhcpcMsgOut.udp->uh_ulen;
  2438.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&pudph, (char *) dhcpcMsgOut.udp,
  2439.                                          ntohs (pudph.ulen));
  2440.     /* construct ip part */
  2441. #if BSD<44
  2442.     dhcpcMsgOut.ip->ip_v_hl = 0;
  2443.     dhcpcMsgOut.ip->ip_v_hl = IPVERSION << 4;
  2444.     dhcpcMsgOut.ip->ip_v_hl |= IPHL >> 2;
  2445. #else
  2446.     dhcpcMsgOut.ip->ip_v = IPVERSION;
  2447.     dhcpcMsgOut.ip->ip_hl = IPHL >> 2;
  2448. #endif
  2449.     dhcpcMsgOut.ip->ip_tos = 0;
  2450.     dhcpcMsgOut.ip->ip_len = htons (msgsize + UDPHL + IPHL);
  2451.     tmpul = generate_xid ();
  2452.     tmpul += (tmpul >> 16);
  2453.     dhcpcMsgOut.ip->ip_id = (u_short) (~tmpul);
  2454.     dhcpcMsgOut.ip->ip_off = htons(IP_DF);                         /* XXX */
  2455.     dhcpcMsgOut.ip->ip_ttl = 0x20;                                 /* XXX */
  2456.     dhcpcMsgOut.ip->ip_p = IPPROTO_UDP;
  2457.     msgsize += UDPHL + IPHL;
  2458.     dhcpcMsgOut.ip->ip_src.s_addr = 0;
  2459.     dhcpcMsgOut.ip->ip_dst.s_addr = INADDR_BROADCAST;
  2460.     dhcpcMsgOut.ip->ip_sum = 0;
  2461. #if BSD<44
  2462.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip,
  2463.                                         (dhcpcMsgOut.ip->ip_v_hl & 0xf) << 2);
  2464. #else
  2465.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip,
  2466.                                         dhcpcMsgOut.ip->ip_hl << 2);
  2467. #endif
  2468.     return (msgsize);
  2469.     }
  2470. /*******************************************************************************
  2471. *
  2472. * dhcp_decline - send a DHCP decline message
  2473. *
  2474. * This routine constructs a message declining an offered IP address and sends
  2475. * it directly to the responding server. It is called when an ARP request 
  2476. * detects that the offered address is already in use.
  2477. *
  2478. * RETURNS: 0 if message sent, or -1 on error.
  2479. *
  2480. * ERRNO: N/A
  2481. *
  2482. * NOMANUAL
  2483. */
  2484. LOCAL int dhcp_decline
  2485.     (
  2486.     struct dhcp_reqspec *pDhcpcReqSpec
  2487.     )
  2488.     {
  2489.     struct sockaddr_in  dest;  /* Server's destination address */
  2490.     struct ifnet *  pIf;  /* Transmit device */
  2491.     int  length;  /* Amount of data in message */
  2492. #ifdef DHCPC_DEBUG
  2493.     char output [INET_ADDR_LEN];
  2494. #endif
  2495.     if (dhcpcBootParam->server_id.s_addr == 0)
  2496.         return (-1);
  2497.     length = make_decline (pDhcpcReqSpec);
  2498.     if (length == 0)
  2499.         return (-1);
  2500.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  2501.     dest.sin_len = sizeof (struct sockaddr_in);
  2502.     dest.sin_family = AF_INET;
  2503.     dest.sin_addr.s_addr = INADDR_BROADCAST;
  2504.     pIf = dhcpcIntface.iface;
  2505.     if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  2506.         {
  2507. #ifdef DHCPC_DEBUG
  2508.         logMsg ("Can't send DHCPDECLINE.n", 0, 0, 0, 0, 0, 0);
  2509. #endif
  2510.         return (-1);
  2511.         }
  2512. #ifdef DHCPC_DEBUG
  2513.     inet_ntoa_b (pDhcpcReqSpec->ipaddr, output);
  2514.     logMsg ("send DHCPDECLINE(%s)n", (int)output, 0, 0, 0, 0, 0);
  2515. #endif
  2516.     return (0);
  2517.     }
  2518. /*******************************************************************************
  2519. *
  2520. * set_declinfo - initialize request specification for decline message
  2521. *
  2522. * This routine assigns the fields in the request specifier used to construct
  2523. * messages to the appropriate values for a DHCP decline message according to
  2524. * the parameters of the currently active lease.
  2525. *
  2526. * RETURNS: N/A
  2527. *
  2528. * ERRNO: N/A
  2529. *
  2530. * NOMANUAL
  2531. */
  2532. LOCAL void set_declinfo
  2533.     (
  2534.     struct dhcp_reqspec *pDhcpcReqSpec,
  2535.     char *errmsg
  2536.     )
  2537.     {
  2538.     char output [INET_ADDR_LEN];
  2539.     pDhcpcReqSpec->ipaddr = dhcpcBootParam->yiaddr;
  2540.     if (dhcpcBootLeaseData.leaseReqSpec.clid != NULL)
  2541.         pDhcpcReqSpec->clid = dhcpcBootLeaseData.leaseReqSpec.clid;
  2542.     else
  2543.         pDhcpcReqSpec->clid = NULL;
  2544.     if (errmsg[0] == 0) 
  2545.         {
  2546.         inet_ntoa_b (dhcpcBootParam->yiaddr, output);
  2547.         sprintf (errmsg, "Unable to use offer with IP address %s.", output);
  2548.         }
  2549.     pDhcpcReqSpec->dhcp_errmsg = errmsg;
  2550.     return;
  2551.     }
  2552. /*******************************************************************************
  2553. *
  2554. * make_discover - construct a DHCP discover message
  2555. *
  2556. * This routine constructs an outgoing UDP/IP message containing the values
  2557. * required to broadcast a lease request.
  2558. *
  2559. * RETURNS: Size of discover message, in bytes
  2560. *
  2561. * ERRNO: N/A
  2562. *
  2563. * NOMANUAL
  2564. */
  2565. LOCAL int make_discover (void)
  2566.     {
  2567.     int offopt = 0;  /* offset in options field */
  2568.     int msgsize;  /* total size of DHCP message */
  2569.     u_long tmpul = 0;
  2570.     u_short tmpus = 0;
  2571.     /* construct dhcp part */
  2572.     bzero (sbuf.buf, sbuf.size);
  2573.     dhcpcMsgOut.dhcp->op = BOOTREQUEST;
  2574.     dhcpcMsgOut.dhcp->htype = dhcpcIntface.haddr.htype;
  2575.     dhcpcMsgOut.dhcp->hlen = dhcpcIntface.haddr.hlen;
  2576.     tmpul = generate_xid ();
  2577.     dhcpcMsgOut.dhcp->xid = htonl (tmpul);
  2578.     /* Update BPF filter to check for new transaction ID. */
  2579.     dhcpfilter [20].k = tmpul;
  2580.     ioctl (dhcpcIntface.bpfDev, BIOCSETF,  (u_int)&dhcpread);
  2581.     bcopy (dhcpcIntface.haddr.haddr, dhcpcMsgOut.dhcp->chaddr, 
  2582.            dhcpcMsgOut.dhcp->hlen);
  2583.     /* insert magic cookie */
  2584.     bcopy ( (char *)dhcpCookie, dhcpcMsgOut.dhcp->options, MAGIC_LEN);
  2585.     offopt = MAGIC_LEN;
  2586.     /* insert message type */
  2587.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MSGTYPE_TAG;
  2588.     dhcpcMsgOut.dhcp->options [offopt++] = 1;
  2589.     dhcpcMsgOut.dhcp->options [offopt++] = DHCPDISCOVER;
  2590.     /* Insert requested IP address, if any. */
  2591.     if (dhcpcBootLeaseData.leaseReqSpec.ipaddr.s_addr != 0)
  2592.         {
  2593.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_REQUEST_IPADDR_TAG;
  2594.         dhcpcMsgOut.dhcp->options [offopt++] = 4;
  2595.         bcopy ( (char *)&dhcpcBootLeaseData.leaseReqSpec.ipaddr.s_addr,
  2596.                 &dhcpcMsgOut.dhcp->options [offopt], 4);
  2597.         offopt += 4;
  2598.         }
  2599.     /* insert Maximum DHCP message size */
  2600.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MAXMSGSIZE_TAG;
  2601.     dhcpcMsgOut.dhcp->options [offopt++] = 2;
  2602.     tmpus = htons (dhcpcBootLeaseData.leaseReqSpec.maxlen);
  2603.     bcopy ( (char *)&tmpus, &dhcpcMsgOut.dhcp->options [offopt], 2);
  2604.     offopt += 2;
  2605.     /* Insert request list, if any. */
  2606.     if (dhcpcBootLeaseData.leaseReqSpec.reqlist.len != 0)
  2607.         {
  2608.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_REQ_LIST_TAG;
  2609.         dhcpcMsgOut.dhcp->options [offopt++] =
  2610.                                 dhcpcBootLeaseData.leaseReqSpec.reqlist.len;
  2611.         bcopy (dhcpcBootLeaseData.leaseReqSpec.reqlist.list,
  2612.                &dhcpcMsgOut.dhcp->options [offopt],
  2613.                dhcpcBootLeaseData.leaseReqSpec.reqlist.len);
  2614.         offopt += dhcpcBootLeaseData.leaseReqSpec.reqlist.len;
  2615.         }
  2616.     /* Insert all other entries from custom options field, if any. */
  2617.     if (dhcpcBootLeaseData.leaseReqSpec.pOptions != NULL)
  2618.         {
  2619.         bcopy (dhcpcBootLeaseData.leaseReqSpec.pOptions,
  2620.                &dhcpcMsgOut.dhcp->options [offopt], 
  2621.                dhcpcBootLeaseData.leaseReqSpec.optlen);
  2622.         offopt += dhcpcBootLeaseData.leaseReqSpec.optlen;
  2623.         }
  2624.     dhcpcMsgOut.dhcp->options[offopt] = _DHCP_END_TAG;
  2625.     msgsize = (DFLTDHCPLEN - DFLTOPTLEN) + offopt + 1;
  2626.     if (dhcpcOldFlag)
  2627.         {
  2628.         /*
  2629.          * This flag indicates that the client did not receive a response
  2630.          * to the initial set of discover messages. Older servers might
  2631.          * ignore messages less than the minimum length obtained with a
  2632.          * fixed options field, so pad the message to reach that length.
  2633.          * The initialize guarantees that the transmit buffer can store
  2634.          * the padded message.
  2635.          */
  2636.         if (msgsize < DFLTDHCPLEN)
  2637.             msgsize = DFLTDHCPLEN;
  2638.         }
  2639.     /* make udp part */
  2640.     /* fill udp header */
  2641.     dhcpcMsgOut.udp->uh_sport = dhcpc_port;
  2642.     dhcpcMsgOut.udp->uh_dport = dhcps_port;
  2643.     dhcpcMsgOut.udp->uh_ulen = htons (msgsize + UDPHL);
  2644.     /* fill pseudo udp header */
  2645.     spudph.srcip.s_addr = 0;
  2646.     spudph.dstip.s_addr = 0xffffffff;
  2647.     spudph.zero = 0;
  2648.     spudph.prto = IPPROTO_UDP;
  2649.     spudph.ulen = dhcpcMsgOut.udp->uh_ulen;
  2650.     /* make ip part */
  2651.     /* fill ip header */
  2652. #if BSD<44
  2653.     dhcpcMsgOut.ip->ip_v_hl = 0;
  2654.     dhcpcMsgOut.ip->ip_v_hl = IPVERSION << 4;
  2655.     dhcpcMsgOut.ip->ip_v_hl |= IPHL >> 2;
  2656. #else
  2657.     dhcpcMsgOut.ip->ip_v = IPVERSION;
  2658.     dhcpcMsgOut.ip->ip_hl = IPHL >> 2;
  2659. #endif
  2660.     dhcpcMsgOut.ip->ip_tos = 0;
  2661.     dhcpcMsgOut.ip->ip_len = htons (msgsize + UDPHL + IPHL);
  2662.     tmpul = generate_xid ();
  2663.     tmpul += (tmpul >> 16);
  2664.     dhcpcMsgOut.ip->ip_id = (u_short) (~tmpul);
  2665.     dhcpcMsgOut.ip->ip_off = htons (IP_DF);                        /* XXX */
  2666.     dhcpcMsgOut.ip->ip_ttl = 0x20;                                 /* XXX */
  2667.     dhcpcMsgOut.ip->ip_p = IPPROTO_UDP;
  2668.     dhcpcMsgOut.ip->ip_src.s_addr = 0;
  2669.     dhcpcMsgOut.ip->ip_dst.s_addr = 0xffffffff;
  2670.     dhcpcMsgOut.ip->ip_sum = 0;
  2671.     msgsize += UDPHL + IPHL;
  2672. #if BSD<44
  2673.   dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip, 
  2674.                                       (dhcpcMsgOut.ip->ip_v_hl & 0xf) << 2);
  2675. #else
  2676.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip, 
  2677.                                         dhcpcMsgOut.ip->ip_hl << 2);
  2678. #endif
  2679.     return (msgsize);
  2680.     }
  2681. /*******************************************************************************
  2682. *
  2683. * make_request - construct a DHCP request message
  2684. *
  2685. * This routine constructs an outgoing UDP/IP message containing the values
  2686. * required to request a lease (<type> argument of REQUESTING) or to obtain
  2687. * additional configuration parameters for an externally configured address
  2688. * (<type> argument of INFORMING).
  2689. *
  2690. * RETURNS: 0 if constructed succesfully, or -1 on error.
  2691. *
  2692. * ERRNO: N/A
  2693. *
  2694. * NOMANUAL
  2695. */
  2696. LOCAL int make_request
  2697.     (
  2698.     struct dhcp_param *paramp,
  2699.     int type
  2700.     )
  2701.     {
  2702.     int offopt = 0;  /* offset in options field */
  2703.     int msgsize;  /* total size of DHCP message */
  2704.     u_long tmpul = 0;
  2705.     u_short tmpus = 0;
  2706.     /* construct dhcp part */
  2707.     tmpus = dhcpcMsgOut.dhcp->secs;
  2708.     bzero (sbuf.buf, sbuf.size);
  2709.     dhcpcMsgOut.dhcp->op = BOOTREQUEST;
  2710.     dhcpcMsgOut.dhcp->htype = dhcpcIntface.haddr.htype;
  2711.     dhcpcMsgOut.dhcp->hlen = dhcpcIntface.haddr.hlen;
  2712.     tmpul = generate_xid ();
  2713.     dhcpcMsgOut.dhcp->xid = htonl (tmpul);
  2714.     /* Update BPF filter to check for new transaction ID. */
  2715.     dhcpfilter [20].k = tmpul;
  2716.     ioctl (dhcpcIntface.bpfDev, BIOCSETF,  (u_int)&dhcpread);
  2717.     dhcpcMsgOut.dhcp->secs = tmpus;
  2718.     if (type == INFORMING)
  2719.         {
  2720.         /* Set externally assigned IP address. */
  2721.         dhcpcMsgOut.dhcp->ciaddr.s_addr = 
  2722.                               dhcpcBootLeaseData.leaseReqSpec.ipaddr.s_addr;
  2723.         }
  2724.     else
  2725.         dhcpcMsgOut.dhcp->ciaddr.s_addr = 0;
  2726.     bcopy (dhcpcIntface.haddr.haddr, dhcpcMsgOut.dhcp->chaddr, 
  2727.            dhcpcMsgOut.dhcp->hlen);
  2728.     /* insert magic cookie */
  2729.     bcopy ( (char *)dhcpCookie, dhcpcMsgOut.dhcp->options, MAGIC_LEN);
  2730.     offopt = MAGIC_LEN;
  2731.     /* insert message type */
  2732.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MSGTYPE_TAG;
  2733.     dhcpcMsgOut.dhcp->options [offopt++] = 1;
  2734.     if (type == INFORMING)
  2735.         dhcpcMsgOut.dhcp->options [offopt++] = DHCPINFORM;
  2736.     else
  2737.         dhcpcMsgOut.dhcp->options [offopt++] = DHCPREQUEST;
  2738.     /* Insert requesting IP address when required. Omit when forbidden. */
  2739.     if (type == REQUESTING)
  2740.         {
  2741.         if (paramp->yiaddr.s_addr != 0)
  2742.             {
  2743.             dhcpcMsgOut.dhcp->options[offopt++] = _DHCP_REQUEST_IPADDR_TAG;
  2744.             dhcpcMsgOut.dhcp->options[offopt++] = 4;
  2745.             bcopy ( (char *)&paramp->yiaddr.s_addr,
  2746.                    &dhcpcMsgOut.dhcp->options [offopt], 4);
  2747.             offopt += 4;
  2748.             }
  2749.         else
  2750.             return (-1);
  2751.         }
  2752.     /* Insert server identifier when required. Omit if forbidden. */
  2753.     if (type == REQUESTING)
  2754.         {
  2755.         if (paramp->server_id.s_addr == 0)
  2756.             {
  2757.             return(-1);
  2758.             }
  2759.         dhcpcMsgOut.dhcp->options[offopt++] = _DHCP_SERVER_ID_TAG;
  2760.         dhcpcMsgOut.dhcp->options[offopt++] = 4;
  2761.         bcopy ( (char *)&paramp->server_id.s_addr,
  2762.                &dhcpcMsgOut.dhcp->options [offopt], 4);
  2763.         offopt += 4;
  2764.         }
  2765.     /* insert Maximum DHCP message size */
  2766.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MAXMSGSIZE_TAG;
  2767.     dhcpcMsgOut.dhcp->options [offopt++] = 2;
  2768.     tmpus = htons (dhcpcBootLeaseData.leaseReqSpec.maxlen);
  2769.     bcopy ( (char *)&tmpus, &dhcpcMsgOut.dhcp->options [offopt], 2);
  2770.     offopt += 2;
  2771.     /* Insert request list, if any. */
  2772.     if (dhcpcBootLeaseData.leaseReqSpec.reqlist.len != 0)
  2773.         {
  2774.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_REQ_LIST_TAG;
  2775.         dhcpcMsgOut.dhcp->options [offopt++] =
  2776.                                 dhcpcBootLeaseData.leaseReqSpec.reqlist.len;
  2777.         bcopy (dhcpcBootLeaseData.leaseReqSpec.reqlist.list,
  2778.                &dhcpcMsgOut.dhcp->options [offopt],
  2779.                dhcpcBootLeaseData.leaseReqSpec.reqlist.len);
  2780.         offopt += dhcpcBootLeaseData.leaseReqSpec.reqlist.len;
  2781.         }
  2782.     /* Insert all other entries from custom options field, if any. */
  2783.     if (dhcpcBootLeaseData.leaseReqSpec.pOptions != NULL)
  2784.         {
  2785.         bcopy (dhcpcBootLeaseData.leaseReqSpec.pOptions,
  2786.                &dhcpcMsgOut.dhcp->options [offopt],
  2787.                dhcpcBootLeaseData.leaseReqSpec.optlen);
  2788.         offopt += dhcpcBootLeaseData.leaseReqSpec.optlen;
  2789.         }
  2790.     dhcpcMsgOut.dhcp->options[offopt] = _DHCP_END_TAG;
  2791.     msgsize = (DFLTDHCPLEN - DFLTOPTLEN) + offopt + 1;
  2792.     if (dhcpcOldFlag)
  2793.         {
  2794.         /*
  2795.          * This flag indicates that the client did not receive a response
  2796.          * to the initial set of discover messages but did receive one
  2797.          * using the older message format. The (older) responding server
  2798.          * ignores messages less than the minimum length obtained with a
  2799.          * fixed options field, so pad the message to reach that length.
  2800.          * The initialize guarantees that the transmit buffer can store
  2801.          * the padded message.
  2802.          */
  2803.         if (msgsize < DFLTDHCPLEN)
  2804.             msgsize = DFLTDHCPLEN;
  2805.         }
  2806.     /* make udp part */
  2807.     /* fill udp header */
  2808.     dhcpcMsgOut.udp->uh_sport = dhcpc_port;
  2809.     dhcpcMsgOut.udp->uh_dport = dhcps_port;
  2810.     dhcpcMsgOut.udp->uh_ulen = htons (msgsize + UDPHL);
  2811.     /* fill pseudo udp header */
  2812.     spudph.zero = 0;
  2813.     spudph.prto = IPPROTO_UDP;
  2814.     spudph.ulen = dhcpcMsgOut.udp->uh_ulen;
  2815.     /* make ip part */
  2816.     /* fill ip header */
  2817. #if BSD<44
  2818.     dhcpcMsgOut.ip->ip_v_hl = 0;
  2819.     dhcpcMsgOut.ip->ip_v_hl = IPVERSION << 4;
  2820.     dhcpcMsgOut.ip->ip_v_hl |= IPHL >> 2;
  2821. #else
  2822.     dhcpcMsgOut.ip->ip_v = IPVERSION;
  2823.     dhcpcMsgOut.ip->ip_hl = IPHL >> 2;
  2824. #endif
  2825.     dhcpcMsgOut.ip->ip_tos = 0;
  2826.     dhcpcMsgOut.ip->ip_len = htons (msgsize + UDPHL + IPHL);
  2827.     tmpul = generate_xid ();
  2828.     tmpul += (tmpul >> 16);
  2829.     dhcpcMsgOut.ip->ip_id = (u_short) (~tmpul);
  2830.     dhcpcMsgOut.ip->ip_off = htons(IP_DF);                         /* XXX */
  2831.     dhcpcMsgOut.ip->ip_ttl = 0x20;                                 /* XXX */
  2832.     dhcpcMsgOut.ip->ip_p = IPPROTO_UDP;
  2833.     msgsize += UDPHL + IPHL;
  2834.     if (type == INFORMING)
  2835.         dhcpcMsgOut.ip->ip_src.s_addr = spudph.srcip.s_addr =
  2836.                                dhcpcBootLeaseData.leaseReqSpec.ipaddr.s_addr;
  2837.     else
  2838.         dhcpcMsgOut.ip->ip_src.s_addr = spudph.srcip.s_addr = 0;
  2839.     dhcpcMsgOut.ip->ip_dst.s_addr = spudph.dstip.s_addr = 0xffffffff;
  2840.     dhcpcMsgOut.ip->ip_sum = 0;
  2841. #if BSD<44
  2842.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip, 
  2843.                                         (dhcpcMsgOut.ip->ip_v_hl & 0xf) << 2);
  2844. #else
  2845.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip, 
  2846.                                         dhcpcMsgOut.ip->ip_hl << 2);
  2847. #endif
  2848.     return (msgsize);
  2849.     }
  2850. /*******************************************************************************
  2851. *
  2852. * handle_ip - process DHCP options containing a single IP address
  2853. *
  2854. * This routine extracts the IP address from the given option body and 
  2855. * copies it to the appropriate field in the parameters structure. It is
  2856. * called by the dhcp_msgtoparam() conversion routine when specified by
  2857. * the handle_param[] global array.
  2858. *
  2859. * RETURNS: 0 if extraction successful, or -1 on error.
  2860. *
  2861. * ERRNO: N/A
  2862. *
  2863. * NOMANUAL
  2864. */
  2865. LOCAL int handle_ip
  2866.     (
  2867.     char *buf,
  2868.     struct dhcp_param *param
  2869.     )
  2870.     {
  2871.     struct in_addr *addr = NULL;
  2872.     char option;
  2873.     option = *buf;
  2874.     /* Set the appropriate pointers to access allocated memory. */
  2875.     if (option == _DHCP_SERVER_ID_TAG) 
  2876.         {
  2877.         addr = &param->server_id;
  2878.         } 
  2879.     else if (option == _DHCP_ROUTER_SOLICIT_TAG)
  2880.         addr = &param->router_solicit;
  2881.     else 
  2882.         {
  2883.         addr = (struct in_addr *)calloc (1, sizeof (struct in_addr));
  2884.         if (addr == NULL) 
  2885.             return (-1);
  2886.         switch (option) 
  2887.             {
  2888.             case _DHCP_SUBNET_MASK_TAG:
  2889.                 if (param->subnet_mask != NULL) 
  2890.                     free (param->subnet_mask);
  2891.                 param->subnet_mask = addr;
  2892.                 break;
  2893.             case _DHCP_SWAP_SERVER_TAG:
  2894.                 if (param->swap_server != NULL) 
  2895.                     free (param->swap_server);
  2896.                 param->swap_server = addr;
  2897.                 break;
  2898.             case _DHCP_BRDCAST_ADDR_TAG:
  2899.                 if (param->brdcast_addr != NULL) 
  2900.                     free (param->brdcast_addr);
  2901.                 param->brdcast_addr = addr;
  2902.                 break;
  2903.             default:
  2904.                 free (addr);
  2905.                 return (EINVAL);
  2906.             }
  2907.         }
  2908.     bcopy (OPTBODY (buf), (char *)addr, DHCPOPTLEN (buf));
  2909.     return (0);
  2910.     }
  2911. /*******************************************************************************
  2912. *
  2913. * handle_num - process DHCP options containing a single numeric value
  2914. *
  2915. * This routine extracts the numeric value from the given option body and 
  2916. * stores it in the appropriate field in the parameters structure. It is
  2917. * called by the dhcp_msgtoparam() conversion routine when specified by
  2918. * the handle_param[] global array.
  2919. *
  2920. * RETURNS: 0 if extraction successful, or -1 on error.
  2921. *
  2922. * ERRNO: N/A
  2923. *
  2924. * NOMANUAL
  2925. */
  2926. LOCAL int handle_num
  2927.     (
  2928.     char *buf,
  2929.     struct dhcp_param *param
  2930.     )
  2931.     {
  2932.     char   charnum = 0;
  2933.     short  shortnum = 0;
  2934.     long   longnum = 0;
  2935.     switch (DHCPOPTLEN (buf)) 
  2936.         {
  2937.         case 1:
  2938.             charnum = *OPTBODY (buf);
  2939.             break;
  2940.         case 2:
  2941.             shortnum = GETHS (OPTBODY (buf));
  2942.             break;
  2943.         case 4:
  2944.             longnum = GETHL (OPTBODY (buf));
  2945.             break;
  2946.         default:
  2947.             return (-1);
  2948.         }
  2949.     switch (*buf) 
  2950.         {
  2951.         case _DHCP_TIME_OFFSET_TAG:
  2952.             param->time_offset = longnum;
  2953.             break;
  2954.         case _DHCP_BOOTSIZE_TAG:
  2955.             param->bootsize = (unsigned short)shortnum;
  2956.             break;
  2957.         case _DHCP_MAX_DGRAM_SIZE_TAG:
  2958.             param->max_dgram_size = (unsigned short)shortnum;
  2959.             break;
  2960.         case _DHCP_DEFAULT_IP_TTL_TAG:
  2961.             param->default_ip_ttl = (unsigned char)charnum;
  2962.             break;
  2963.         case _DHCP_MTU_AGING_TIMEOUT_TAG:
  2964.             param->mtu_aging_timeout = (unsigned long)longnum;
  2965.             break;
  2966.         case _DHCP_IF_MTU_TAG:
  2967.             param->intf_mtu = (unsigned short)shortnum;
  2968.             break;
  2969.         case _DHCP_ARP_CACHE_TIMEOUT_TAG:
  2970.             param->arp_cache_timeout = (unsigned long)longnum;
  2971.             break;
  2972.         case _DHCP_DEFAULT_TCP_TTL_TAG:
  2973.             param->default_tcp_ttl = (unsigned char)charnum;
  2974.             break;
  2975.         case _DHCP_KEEPALIVE_INTERVAL_TAG:
  2976.             param->keepalive_inter = (unsigned long)longnum;
  2977.             break;
  2978.         case _DHCP_NB_NODETYPE_TAG:
  2979.             param->nb_nodetype = (unsigned)charnum;
  2980.             break;
  2981.         case _DHCP_LEASE_TIME_TAG:
  2982.             param->lease_duration = (unsigned long)longnum;
  2983.             break;
  2984.         case _DHCP_T1_TAG:
  2985.             param->dhcp_t1 = (unsigned long)longnum;
  2986.             break;
  2987.         case _DHCP_T2_TAG:
  2988.             param->dhcp_t2 = (unsigned long)longnum;
  2989.             break;
  2990.         default:
  2991.             return (EINVAL);
  2992.         }
  2993.     return(0);
  2994.     }
  2995. /*******************************************************************************
  2996. *
  2997. * handle_ips - process DHCP options containing multiple IP addresses
  2998. *
  2999. * This routine extracts the IP addresses from the given option body and 
  3000. * copies them to the appropriate field in the parameters structure. It is
  3001. * called by the dhcp_msgtoparam() conversion routine when specified by
  3002. * the handle_param[] global array.
  3003. *
  3004. * RETURNS: 0 if extraction successful, or -1 on error.
  3005. *
  3006. * ERRNO: N/A
  3007. *
  3008. * NOMANUAL
  3009. */
  3010. LOCAL int handle_ips
  3011.     (
  3012.     char *buf,
  3013.     struct dhcp_param *param
  3014.     )
  3015.     {
  3016.     struct in_addr  *addr = NULL;
  3017.     struct in_addrs *addrs = NULL;
  3018.     unsigned char  num = 0;
  3019.     num = DHCPOPTLEN (buf) / 4;
  3020.     addr = (struct in_addr *)calloc ( (int)num, sizeof (struct in_addr));
  3021.     if (addr  == NULL)
  3022.         return(-1);
  3023.     addrs = (struct in_addrs *)calloc (1, sizeof(struct in_addrs));
  3024.     if (addrs  == NULL) 
  3025.         {
  3026.         free (addr);
  3027.         return (-1);
  3028.         }
  3029.     switch (*buf) 
  3030.         {
  3031.         case _DHCP_ROUTER_TAG:
  3032.             if (param->router != NULL) 
  3033.                 {
  3034.                 if (param->router->addr != NULL) 
  3035.                     free (param->router->addr);
  3036.                 free (param->router);
  3037.                 }
  3038.             param->router = addrs;
  3039.             param->router->num = num;
  3040.             param->router->addr = addr;
  3041.             break;
  3042.         case _DHCP_TIME_SERVER_TAG:
  3043.             if (param->time_server != NULL) 
  3044.                 {
  3045.                 if (param->time_server->addr != NULL) 
  3046.                     free (param->time_server->addr);
  3047.                 free (param->time_server);
  3048.                 }
  3049.             param->time_server = addrs;
  3050.             param->time_server->num = num;
  3051.             param->time_server->addr = addr;
  3052.             break;
  3053.         case _DHCP_NAME_SERVER_TAG:
  3054.             if (param->name_server != NULL) 
  3055.                 {
  3056.                 if (param->name_server->addr != NULL) 
  3057.                     free (param->name_server->addr);
  3058.                 free (param->name_server);
  3059.                 }
  3060.             param->name_server = addrs;
  3061.             param->name_server->num = num;
  3062.             param->name_server->addr = addr;
  3063.             break;
  3064.         case _DHCP_DNS_SERVER_TAG:
  3065.             if (param->dns_server != NULL) 
  3066.                 {
  3067.                 if (param->dns_server->addr != NULL) 
  3068.                     free (param->dns_server->addr);
  3069.                 free (param->dns_server);
  3070.                 }
  3071.             param->dns_server = addrs;
  3072.             param->dns_server->num = num;
  3073.             param->dns_server->addr = addr;
  3074.             break;
  3075.         case _DHCP_LOG_SERVER_TAG:
  3076.             if (param->log_server != NULL) 
  3077.                 {
  3078.                 if (param->log_server->addr != NULL) 
  3079.                     free (param->log_server->addr);
  3080.                 free (param->log_server);
  3081.                 }
  3082.             param->log_server = addrs;
  3083.             param->log_server->num = num;
  3084.             param->log_server->addr = addr;
  3085.             break;
  3086.         case _DHCP_COOKIE_SERVER_TAG:
  3087.             if (param->cookie_server != NULL) 
  3088.                 {
  3089.                 if (param->cookie_server->addr != NULL) 
  3090.                     free (param->cookie_server->addr);
  3091.                 free (param->cookie_server);
  3092.                 }
  3093.             param->cookie_server = addrs;
  3094.             param->cookie_server->num = num;
  3095.             param->cookie_server->addr = addr;
  3096.             break;
  3097.         case _DHCP_LPR_SERVER_TAG:
  3098.             if (param->lpr_server != NULL) 
  3099.                 {
  3100.                 if (param->lpr_server->addr != NULL) 
  3101.                     free (param->lpr_server->addr);
  3102.                 free (param->lpr_server);
  3103.                 }
  3104.             param->lpr_server = addrs;
  3105.             param->lpr_server->num = num;
  3106.             param->lpr_server->addr = addr;
  3107.             break;
  3108.         case _DHCP_IMPRESS_SERVER_TAG:
  3109.             if (param->impress_server != NULL) 
  3110.                 {
  3111.                 if (param->impress_server->addr != NULL) 
  3112.                     free (param->impress_server->addr);
  3113.                 free (param->impress_server);
  3114.                 }
  3115.             param->impress_server = addrs;
  3116.             param->impress_server->num = num;
  3117.             param->impress_server->addr = addr;
  3118.             break;
  3119.         case _DHCP_RLS_SERVER_TAG:
  3120.             if (param->rls_server != NULL) 
  3121.                 {
  3122.                 if (param->rls_server->addr != NULL) 
  3123.                     free (param->rls_server->addr);
  3124.                 free (param->rls_server);
  3125.                 }
  3126.             param->rls_server = addrs;
  3127.             param->rls_server->num = num;
  3128.             param->rls_server->addr = addr;
  3129.             break;
  3130.         case _DHCP_NIS_SERVER_TAG:
  3131.             if (param->nis_server != NULL) 
  3132.                 {
  3133.                 if (param->nis_server->addr != NULL) 
  3134.                     free (param->nis_server->addr);
  3135.                 free (param->nis_server);
  3136.                 }
  3137.             param->nis_server = addrs;
  3138.             param->nis_server->num = num;
  3139.             param->nis_server->addr = addr;
  3140.             break;
  3141.         case _DHCP_NTP_SERVER_TAG:
  3142.             if (param->ntp_server != NULL)
  3143.                 {
  3144.                 if (param->ntp_server->addr != NULL) 
  3145.                     free (param->ntp_server->addr);
  3146.                 free (param->ntp_server);
  3147.                 }
  3148.             param->ntp_server = addrs;
  3149.             param->ntp_server->num = num;
  3150.             param->ntp_server->addr = addr;
  3151.             break;
  3152.         case _DHCP_NBN_SERVER_TAG:
  3153.             if (param->nbn_server != NULL) 
  3154.                 {
  3155.                 if (param->nbn_server->addr != NULL) 
  3156.                     free (param->nbn_server->addr);
  3157.                 free (param->nbn_server);
  3158.                 }
  3159.             param->nbn_server = addrs;
  3160.             param->nbn_server->num = num;
  3161.             param->nbn_server->addr = addr;
  3162.             break;
  3163.         case _DHCP_NBDD_SERVER_TAG:
  3164.             if (param->nbdd_server != NULL) 
  3165.                 {
  3166.                 if (param->nbdd_server->addr != NULL) 
  3167.                     free (param->nbdd_server->addr);
  3168.                 free (param->nbdd_server);
  3169.                 }
  3170.             param->nbdd_server = addrs;
  3171.             param->nbdd_server->num = num;
  3172.             param->nbdd_server->addr = addr;
  3173.             break;
  3174.         case _DHCP_XFONT_SERVER_TAG:
  3175.             if (param->xfont_server != NULL)
  3176.                 {
  3177.                 if (param->xfont_server->addr != NULL) 
  3178.                     free (param->xfont_server->addr);
  3179.                 free (param->xfont_server);
  3180.                 }
  3181.             param->xfont_server = addrs;
  3182.             param->xfont_server->num = num;
  3183.             param->xfont_server->addr = addr;
  3184.             break;
  3185.         case _DHCP_XDISPLAY_MANAGER_TAG:
  3186.             if (param->xdisplay_manager != NULL) 
  3187.                 {
  3188.                 if (param->xdisplay_manager->addr != NULL) 
  3189.                     free (param->xdisplay_manager->addr);
  3190.                 free (param->xdisplay_manager);
  3191.                 }
  3192.             param->xdisplay_manager = addrs;
  3193.             param->xdisplay_manager->num = num;
  3194.             param->xdisplay_manager->addr = addr;
  3195.             break;
  3196.         case _DHCP_NISP_SERVER_TAG:
  3197.             if (param->nisp_server != NULL) 
  3198.                 {
  3199.                 if (param->nisp_server->addr != NULL) 
  3200.                     free (param->nisp_server->addr);
  3201.                 free (param->nisp_server);
  3202.                 }
  3203.             param->nisp_server = addrs;
  3204.             param->nisp_server->num = num;
  3205.             param->nisp_server->addr = addr;
  3206.             break;
  3207.         case _DHCP_MOBILEIP_HA_TAG:
  3208.             if (param->mobileip_ha != NULL) 
  3209.                 {
  3210.                 if (param->mobileip_ha->addr != NULL) 
  3211.                     free (param->mobileip_ha->addr);
  3212.                 free (param->mobileip_ha);
  3213.                 }
  3214.             param->mobileip_ha = addrs;
  3215.             param->mobileip_ha->num = num;
  3216.             param->mobileip_ha->addr = addr;
  3217.             break;
  3218.         case _DHCP_SMTP_SERVER_TAG:
  3219.             if (param->smtp_server != NULL) 
  3220.                 {
  3221.                 if (param->smtp_server->addr != NULL) 
  3222.                     free (param->smtp_server->addr);
  3223.                 free (param->smtp_server);
  3224.                 }
  3225.             param->smtp_server = addrs;
  3226.             param->smtp_server->num = num;
  3227.             param->smtp_server->addr = addr;
  3228.             break;
  3229.         case _DHCP_POP3_SERVER_TAG:
  3230.             if (param->pop3_server != NULL) 
  3231.                 {
  3232.                 if (param->pop3_server->addr != NULL) 
  3233.                     free (param->pop3_server->addr);
  3234.                 free (param->pop3_server);
  3235.                 }
  3236.             param->pop3_server = addrs;
  3237.             param->pop3_server->num = num;
  3238.             param->pop3_server->addr = addr;
  3239.             break;
  3240.         case _DHCP_NNTP_SERVER_TAG:
  3241.             if (param->nntp_server != NULL) 
  3242.                 {
  3243.                 if (param->nntp_server->addr != NULL) 
  3244.                     free (param->nntp_server->addr);
  3245.                 free (param->nntp_server);
  3246.                 }
  3247.             param->nntp_server = addrs;
  3248.             param->nntp_server->num = num;
  3249.             param->nntp_server->addr = addr;
  3250.             break;
  3251.         case _DHCP_DFLT_WWW_SERVER_TAG:
  3252.             if (param->dflt_www_server != NULL) 
  3253.                 {
  3254.                 if (param->dflt_www_server->addr != NULL) 
  3255.                     free (param->dflt_www_server->addr);
  3256.                 free (param->dflt_www_server);
  3257.                 }
  3258.             param->dflt_www_server = addrs;
  3259.             param->dflt_www_server->num = num;
  3260.             param->dflt_www_server->addr = addr;
  3261.             break;
  3262.         case _DHCP_DFLT_FINGER_SERVER_TAG:
  3263.             if (param->dflt_finger_server != NULL) 
  3264.                 {
  3265.                 if (param->dflt_finger_server->addr != NULL)
  3266.             free (param->dflt_finger_server->addr);
  3267.                 free (param->dflt_finger_server);
  3268.                 }
  3269.             param->dflt_finger_server = addrs;
  3270.             param->dflt_finger_server->num = num;
  3271.             param->dflt_finger_server->addr = addr;
  3272.             break;
  3273.         case _DHCP_DFLT_IRC_SERVER_TAG:
  3274.             if (param->dflt_irc_server != NULL) 
  3275.                 {
  3276.                 if (param->dflt_irc_server->addr != NULL) 
  3277.                     free (param->dflt_irc_server->addr);
  3278.                 free (param->dflt_irc_server);
  3279.                 }
  3280.             param->dflt_irc_server = addrs;
  3281.             param->dflt_irc_server->num = num;
  3282.             param->dflt_irc_server->addr = addr;
  3283.             break;
  3284.         case _DHCP_STREETTALK_SERVER_TAG:
  3285.             if (param->streettalk_server != NULL) 
  3286.                 {
  3287.                 if (param->streettalk_server->addr != NULL) 
  3288.                     free (param->streettalk_server->addr);
  3289.                 free (param->streettalk_server);
  3290.                 }
  3291.             param->streettalk_server = addrs;
  3292.             param->streettalk_server->num = num;
  3293.             param->streettalk_server->addr = addr;
  3294.             break;
  3295.         case _DHCP_STDA_SERVER_TAG:
  3296.             if (param->stda_server != NULL) 
  3297.                 {
  3298.                 if (param->stda_server->addr != NULL) 
  3299.                     free (param->stda_server->addr);
  3300.                 free (param->stda_server);
  3301.                 }
  3302.             param->stda_server = addrs;
  3303.             param->stda_server->num = num;
  3304.             param->stda_server->addr = addr;
  3305.             break;
  3306.         default:
  3307.             free (addr);
  3308.             free (addrs);
  3309.             return (EINVAL);
  3310.         } 
  3311.     bcopy (OPTBODY (buf), (char *)addr, DHCPOPTLEN (buf));
  3312.     return (0);
  3313.     }
  3314. /*******************************************************************************
  3315. *
  3316. * handle_str - process DHCP options containing NVT ASCII strings
  3317. *
  3318. * This routine extracts the NVT ASCII string from the given option body and 
  3319. * copies it to the appropriate field in the parameters structure. It is
  3320. * called by the dhcp_msgtoparam() conversion routine when specified by
  3321. * the handle_param[] global array.
  3322. *
  3323. * RETURNS: 0 if extraction successful, or -1 on error.
  3324. *
  3325. * ERRNO: N/A
  3326. *
  3327. * NOMANUAL
  3328. */
  3329. LOCAL int handle_str
  3330.     (
  3331.     char *buf,
  3332.     struct dhcp_param *param
  3333.     )
  3334.     {
  3335.     char *str = NULL;
  3336.     str = calloc (1, (DHCPOPTLEN (buf) + 1));  /* +1 for null terminator. */
  3337.     if (str == NULL)
  3338.         return (-1);
  3339.     switch (*buf) 
  3340.         {
  3341.         case _DHCP_HOSTNAME_TAG:
  3342.             if (param->hostname != NULL) 
  3343.                 free (param->hostname);
  3344.             param->hostname = str;
  3345.             break;
  3346.         case _DHCP_MERIT_DUMP_TAG:
  3347.             if (param->merit_dump != NULL) 
  3348.                 free (param->merit_dump);
  3349.             param->merit_dump = str;
  3350.             break;
  3351.         case _DHCP_DNS_DOMAIN_TAG:
  3352.             if (param->dns_domain != NULL) 
  3353.                 free (param->dns_domain);
  3354.             param->dns_domain = str;
  3355.             break;
  3356.         case _DHCP_ROOT_PATH_TAG:
  3357.             if (param->root_path != NULL) 
  3358.                 free (param->root_path);
  3359.             param->root_path = str;
  3360.             break;
  3361.         case _DHCP_EXTENSIONS_PATH_TAG:
  3362.             if (param->extensions_path != NULL)
  3363.                 free (param->extensions_path);
  3364.             param->extensions_path = str;
  3365.             break;
  3366.         case _DHCP_NIS_DOMAIN_TAG:
  3367.             if (param->nis_domain != NULL) 
  3368.                 free (param->nis_domain);
  3369.             param->nis_domain = str;
  3370.             break;
  3371.         case _DHCP_NB_SCOPE_TAG:
  3372.             if (param->nb_scope != NULL) 
  3373.                 free (param->nb_scope);
  3374.             param->nb_scope = str;
  3375.             break;
  3376.         case _DHCP_ERRMSG_TAG:
  3377.             if (param->errmsg != NULL) 
  3378.                 free (param->errmsg);
  3379.             param->errmsg = str;
  3380.             break;
  3381.         case _DHCP_NISP_DOMAIN_TAG:
  3382.             if (param->nisp_domain != NULL) 
  3383.                 free (param->nisp_domain);
  3384.             param->nisp_domain = str;
  3385.             break;
  3386.         case _DHCP_TFTP_SERVERNAME_TAG:
  3387.             if (param->temp_sname != NULL) 
  3388.                 free (param->temp_sname);
  3389.             param->temp_sname = str;
  3390.             break;
  3391.         case _DHCP_BOOTFILE_TAG:
  3392.             if (param->temp_file != NULL) 
  3393.                 free (param->temp_file);
  3394.             param->temp_file = str;
  3395.             break; 
  3396.         default:
  3397.             free (str);
  3398.             return (EINVAL);
  3399.         }
  3400.     bcopy (OPTBODY (buf), str, DHCPOPTLEN (buf));
  3401.     str [DHCPOPTLEN (buf)] = '';
  3402.     return (0);
  3403.     }
  3404. /*******************************************************************************
  3405. *
  3406. * handle_bool - process DHCP options containing boolean values
  3407. *
  3408. * This routine extracts the boolean value from the given option body and 
  3409. * stores it in the appropriate field in the parameters structure. It is
  3410. * called by the dhcp_msgtoparam() conversion routine when specified by
  3411. * the handle_param[] global array.
  3412. *
  3413. * RETURNS: 0 if extraction successful, or -1 on error.
  3414. *
  3415. * ERRNO: N/A
  3416. *
  3417. * NOMANUAL
  3418. */
  3419. LOCAL int handle_bool
  3420.     (
  3421.     char *buf,
  3422.     struct dhcp_param *param
  3423.     )
  3424.     {
  3425.     switch (*buf) 
  3426.         {
  3427.         case _DHCP_IP_FORWARD_TAG:
  3428.             param->ip_forward = *OPTBODY (buf);
  3429.             break;
  3430.         case _DHCP_NONLOCAL_SRCROUTE_TAG:
  3431.             param->nonlocal_srcroute = *OPTBODY (buf);
  3432.             break;
  3433.         case _DHCP_ALL_SUBNET_LOCAL_TAG:
  3434.             param->all_subnet_local = *OPTBODY (buf);
  3435.             break;
  3436.         case _DHCP_MASK_DISCOVER_TAG:
  3437.             param->mask_discover = *OPTBODY (buf);
  3438.             break;
  3439.         case _DHCP_MASK_SUPPLIER_TAG:
  3440.             param->mask_supplier = *OPTBODY (buf);
  3441.             break;
  3442.         case _DHCP_ROUTER_DISCOVER_TAG:
  3443.             param->router_discover = *OPTBODY (buf);
  3444.             break;
  3445.         case _DHCP_TRAILER_TAG:
  3446.             param->trailer = *OPTBODY (buf);
  3447.             break;
  3448.         case _DHCP_ETHER_ENCAP_TAG:
  3449.             param->ether_encap = *OPTBODY (buf);
  3450.             break;
  3451.         case _DHCP_KEEPALIVE_GARBAGE_TAG:
  3452.             param->keepalive_garba = *OPTBODY (buf);
  3453.             break;
  3454.         default:
  3455.             return (EINVAL);
  3456.         }
  3457.     return (0);
  3458.     }
  3459. /*******************************************************************************
  3460. *
  3461. * handle_ippairs - process DHCP options containing multiple IP value pairs
  3462. *
  3463. * This routine extracts the IP pairs from the given option body and 
  3464. * stores them in the appropriate field in the parameters structure. It is
  3465. * called by the dhcp_msgtoparam() conversion routine when specified by
  3466. * the handle_param[] global array.
  3467. *
  3468. * RETURNS: 0 if extraction successful, or -1 on error.
  3469. *
  3470. * ERRNO: N/A
  3471. *
  3472. * NOMANUAL
  3473. */
  3474. LOCAL int handle_ippairs
  3475.     (
  3476.     char *buf,
  3477.     struct dhcp_param *param
  3478.     )
  3479.     {
  3480.     struct in_addr  *addr = NULL;
  3481.     struct in_addrs *addrs = NULL;
  3482.     unsigned char   num = 0;
  3483.     num = DHCPOPTLEN(buf) / 4;
  3484.     addr = (struct in_addr *)calloc ( (int) num, sizeof (struct in_addr)); 
  3485.     if (addr == NULL)
  3486.         return(-1);
  3487.     addrs = (struct in_addrs *)calloc (1, sizeof (struct in_addrs));
  3488.     if (addrs == NULL)
  3489.         { 
  3490.         free (addr);
  3491.         return (-1);
  3492.         }
  3493.     switch (*buf) 
  3494.         {
  3495.         case _DHCP_POLICY_FILTER_TAG: /* IP address followed by subnet mask. */
  3496.             if (param->policy_filter != NULL) 
  3497.                 {
  3498.                 if (param->policy_filter->addr != NULL) 
  3499.                     free (param->policy_filter->addr);
  3500.                 free (param->policy_filter);
  3501.                 }
  3502.             param->policy_filter = addrs;
  3503.             param->policy_filter->num = num / 2;
  3504.             param->policy_filter->addr = addr;
  3505.             break;
  3506.         case _DHCP_STATIC_ROUTE_TAG:   /* Destination IP followed by router. */
  3507.             if (param->static_route != NULL) 
  3508.                 {
  3509.                 if (param->static_route->addr != NULL) 
  3510.                     free (param->static_route->addr);
  3511.                 free (param->static_route);
  3512.                 }
  3513.             param->static_route = addrs;
  3514.             param->static_route->num = num / 2;
  3515.             param->static_route->addr = addr;
  3516.             break;
  3517.         default:
  3518.             free (addr);
  3519.             free (addrs);
  3520.             return (EINVAL);
  3521.         }
  3522.     bcopy (OPTBODY (buf), (char *)addr, DHCPOPTLEN (buf));
  3523.     return (0);
  3524.     }
  3525. /*******************************************************************************
  3526. *
  3527. * handle_nums - process DHCP options containing multiple numeric values
  3528. *
  3529. * This routine extracts the numbers from the given option body and 
  3530. * stores them in the appropriate field in the parameters structure. It is
  3531. * called by the dhcp_msgtoparam() conversion routine when specified by
  3532. * the handle_param[] global array.
  3533. *
  3534. * RETURNS: 0 if extraction successful, or -1 on error.
  3535. *
  3536. * ERRNO: N/A
  3537. *
  3538. * NOMANUAL
  3539. */
  3540. LOCAL int handle_nums
  3541.     (
  3542.     char *buf,
  3543.     struct dhcp_param *param
  3544.     )
  3545.     {
  3546.     int i = 0;
  3547.     int max = 0;
  3548.     if (*buf != _DHCP_MTU_PLATEAU_TABLE_TAG) 
  3549.         return (EINVAL);
  3550.     else 
  3551.         {
  3552.         if (param->mtu_plateau_table != NULL) 
  3553.             {
  3554.             if (param->mtu_plateau_table->shortnum != NULL)
  3555.         free (param->mtu_plateau_table->shortnum);
  3556.             free (param->mtu_plateau_table);
  3557.             }
  3558.         param->mtu_plateau_table = 
  3559.                        (struct u_shorts *)calloc(1, sizeof (struct u_shorts));
  3560.         if (param->mtu_plateau_table == NULL) 
  3561.             return(-1);
  3562.         max = param->mtu_plateau_table->num = DHCPOPTLEN (buf) / 2;
  3563.         param->mtu_plateau_table->shortnum =
  3564.                             (u_short *)calloc (max, sizeof (unsigned short));
  3565.         if (param->mtu_plateau_table->shortnum == NULL) 
  3566.             {
  3567.             free (param->mtu_plateau_table);
  3568.             return(-1);
  3569.             }
  3570.         for (i = 0; i < max; i++) 
  3571.             param->mtu_plateau_table->shortnum[i] = GETHS (&buf [i * 2 + 2]);
  3572.         }
  3573.     return (0);
  3574.     }
  3575. /*******************************************************************************
  3576. *
  3577. * handle_list - process the DHCP option containing vendor specific data 
  3578. *
  3579. * This routine extracts the list of vendor-specific information from the 
  3580. * given option body and stores it in the appropriate field in the parameters 
  3581. * structure. It is called by the dhcp_msgtoparam() conversion routine when 
  3582. * specified by the handle_param[] global array.
  3583. *
  3584. * RETURNS: 0 if extraction successful, or -1 on error.
  3585. *
  3586. * ERRNO: N/A
  3587. *
  3588. * NOMANUAL
  3589. */
  3590. LOCAL int handle_list
  3591.     (
  3592.     char *buf,
  3593.     struct dhcp_param *param
  3594.     )
  3595.     {
  3596.     if (*buf != _DHCP_VENDOR_SPEC_TAG)
  3597.         return (EINVAL);
  3598.    
  3599.     if (param->vendlist != NULL)
  3600.         free (param->vendlist);
  3601.     param->vendlist = calloc (1, sizeof (struct vendor_list));
  3602.     if (param->vendlist == NULL)
  3603.         return (-1);
  3604.     bcopy (OPTBODY (buf), param->vendlist->list, DHCPOPTLEN (buf));
  3605.     param->vendlist->len = DHCPOPTLEN (buf);
  3606.     return (0);
  3607.     }