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

VxWorks

开发平台:

C/C++

  1. /* dhcpc_subr.c - DHCP client general subroutines */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01u,25apr02,wap  transmit DHCPDECLINEs as broadcasts, not unicasts (SPR
  8.                  #75119)
  9. 01t,23apr02,wap  use dhcpTime() instead of time() (SPR #68900)
  10. 01s,06dec01,vvv  fixed arp_check again (SPR #69731)
  11. 01r,12oct01,rae  merge from truestack ver 01x, base 01n
  12.                  SPRs 65352, 65264, 70116, 69731, 27426
  13. 01q,26oct00,spm  fixed byte order of transaction identifier
  14. 01p,26oct00,spm  fixed modification history after tor3_x merge
  15. 01o,23oct00,niq  merged from version 01q of tor3_x branch (base version 01n);
  16.                  upgrade to BPF replaces tagged frame support
  17. 01n,01mar99,spm  eliminated creation of invalid route (SPR #24266)
  18. 01m,04dec97,spm  added code review modifications
  19. 01l,04dec97,spm  replaced muxDevExists call with test of predefined flag;
  20.                  enabled ARP test of intended IP address
  21. 01k,06oct97,spm  removed reference to deleted endDriver global; replaced with
  22.                  support for dynamic driver type detection
  23. 01j,26aug97,spm  major overhaul: reorganized code and changed user interface
  24.                  to support multiple leases at runtime
  25. 01i,06aug97,spm  renamed class field of dhcp_reqspec structure to prevent C++
  26.                  compilation errors (SPR #9079)
  27. 01h,15jul97,spm  set sa_len and reordered ioctl calls in configuration routine,
  28.                  changed to raw sockets to avoid memPartFree error (SPR #8650);
  29.                  replaced floating point to prevent ss5 exception (SPR #8738)
  30. 01g,10jun97,spm  corrected load exception (SPR #8724) and memalign() parameter;
  31.                  isolated incoming messages in state machine from input hooks
  32. 01f,02jun97,spm  changed DHCP option tags to prevent name conflicts (SPR #8667)
  33.                  and updated man pages
  34. 01e,09may97,spm  changed memory access to align IP header on four byte boundary
  35. 01d,18apr97,spm  added conditional include DHCPC_DEBUG for displayed output,
  36.                  shut down interface when changing address/netmask
  37. 01c,07apr97,spm  corrected bugs extracting options, added safety checks and
  38.                  memory cleanup code, rewrote documentation
  39. 01b,27jan97,spm  added little-endian support and modified to coding standards 
  40. 01a,03oct96,spm  created by modifying WIDE Project DHCP Implementation
  41. */
  42. /*
  43. DESCRIPTION
  44. This library contains subroutines which implement several utilities for the 
  45. Wide project DHCP client, modified for vxWorks compatibility.
  46. INTERNAL
  47. The routines in this module are called by both portions of the runtime state 
  48. machine, in the dhcpcState1 and dhcpcState2 modules, which execute before and 
  49. after a lease is established.
  50. INCLUDE_FILES: dhcpcLib.h
  51. */
  52. /*
  53.  * WIDE Project DHCP Implementation
  54.  * Copyright (c) 1995 Akihiro Tominaga
  55.  * Copyright (c) 1995 WIDE Project
  56.  * All rights reserved.
  57.  *
  58.  * Permission to use, copy, modify and distribute this software and its
  59.  * documentation is hereby granted, provided only with the following
  60.  * conditions are satisfied:
  61.  *
  62.  * 1. Both the copyright notice and this permission notice appear in
  63.  *    all copies of the software, derivative works or modified versions,
  64.  *    and any portions thereof, and that both notices appear in
  65.  *    supporting documentation.
  66.  * 2. All advertising materials mentioning features or use of this software
  67.  *    must display the following acknowledgement:
  68.  *      This product includes software developed by WIDE Project and
  69.  *      its contributors.
  70.  * 3. Neither the name of WIDE Project nor the names of its contributors
  71.  *    may be used to endorse or promote products derived from this software
  72.  *    without specific prior written permission.
  73.  *
  74.  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND WIDE
  75.  * PROJECT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  76.  * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ALSO, THERE
  77.  * IS NO WARRANTY IMPLIED OR OTHERWISE, NOR IS SUPPORT PROVIDED.
  78.  *
  79.  * Feedback of the results generated from any improvements or
  80.  * extensions made to this software would be much appreciated.
  81.  * Any such feedback should be sent to:
  82.  * 
  83.  *  Akihiro Tominaga
  84.  *  WIDE Project
  85.  *  Keio University, Endo 5322, Kanagawa, Japan
  86.  *  (E-mail: dhcp-dist@wide.ad.jp)
  87.  *
  88.  * WIDE project has the rights to redistribute these changes.
  89.  */
  90. /* includes */
  91. #include <stdio.h>
  92. #include <stdlib.h>
  93. #include <unistd.h>
  94. #include <string.h>
  95. #include <fcntl.h>
  96. #include <sys/types.h>
  97. #include <time.h>
  98. #include <sys/socket.h>
  99. #include <sys/ioctl.h>
  100. #include <net/if.h>
  101. #include <net/route.h>
  102. #include <netinet/in.h>
  103. #include <netinet/in_systm.h>
  104. #include <netinet/if_ether.h>
  105. #include <netinet/ip.h>
  106. #include <netinet/udp.h>
  107. #include <arpa/inet.h>
  108. #include <inetLib.h>
  109. #include <sysLib.h>
  110. #include <logLib.h>
  111. #include <sockLib.h>
  112. #include <ioLib.h>
  113. #include <semLib.h>
  114. #include <vxLib.h>
  115. #include "muxLib.h"
  116. #include "dhcp/dhcp.h"
  117. #include "dhcp/dhcpcStateLib.h"
  118. #include "dhcp/dhcpcCommonLib.h"
  119. #include "dhcp/dhcpcInternal.h"
  120. #include "bpfDrv.h"
  121. /* globals */
  122.     /* Berkeley Packet Filter instructions for catching ARP messages. */
  123. LOCAL struct bpf_insn arpfilter[] = {
  124.   BPF_STMT(BPF_LD+BPF_TYPE, 0),    /* Save lltype in accumulator */
  125.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_ARP, 0, 9),  /* ARP in frame? */
  126.   /*
  127.    * The remaining statements use the (new) BPF_HLEN alias to avoid
  128.    * any link-layer dependencies.
  129.    */
  130.   BPF_STMT(BPF_LD+BPF_H+BPF_ABS+BPF_HLEN, 6),    /* A <- ARP OP field */
  131.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REPLY, 0, 7),    /* ARP reply ? */
  132.   BPF_STMT(BPF_LDX+BPF_HLEN, 0),           /* X <- frame data offset */
  133.   BPF_STMT(BPF_LD+BPF_B+BPF_IND, 4),       /* A <- hardware size */
  134.   BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),      /* A <- sum of variable offsets */
  135.   BPF_STMT(BPF_MISC+BPF_TAX, 0),           /* X <- sum of variable offsets */
  136.   BPF_STMT(BPF_LD+BPF_W+BPF_IND, 8),       /* A <- sender IP address */
  137.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, -1, 0, 1),   /* -1 replaced with real IP */
  138.   BPF_STMT(BPF_RET+BPF_K, -1),                     /* copy entire frame */
  139.   BPF_STMT(BPF_RET+BPF_K, 0)          /* unrecognized message: ignore frame */
  140.   };
  141. LOCAL struct bpf_program arpread = {
  142.     sizeof (arpfilter) / sizeof (struct bpf_insn),
  143.     arpfilter
  144.     };
  145. IMPORT struct bpf_insn dhcpfilter[];    /* For updating xid test */
  146. IMPORT struct bpf_program dhcpread;
  147. IMPORT int dhcpcDataSock;  /* For sending release and renewal messages */
  148. IMPORT int flushroutes (void);
  149. struct msg dhcpcMsgOut;
  150. struct msg dhcpcMsgIn;
  151. struct ps_udph spudph;
  152. /* locals */
  153. LOCAL int bpfArpDev;  /* Gets any replies to ARP probes. */
  154. LOCAL u_short dhcps_port;               /* Server port, in network byte order. */
  155. LOCAL u_short dhcpc_port;               /* Client port, in network byte order. */
  156. /* forward declarations */
  157. int config_if();
  158. void set_route();
  159. int make_decline (struct dhcp_reqspec *, struct if_info *);
  160. int make_release (struct dhcp_reqspec *, struct if_info *, BOOL);
  161. long generate_xid (struct if_info *);
  162. /*******************************************************************************
  163. *
  164. * generate_xid - generate a transaction identifier 
  165. *
  166. * This routine forms a transaction identifier which is used by the lease 
  167. * for transmissions over the interface described by <pIfData>. The routine 
  168. * is called from multiple locations after the initialization routines have 
  169. * retrieved the network interface hardware address.
  170. *
  171. * RETURNS: 32-bit transaction identifier in host byte order. 
  172. *
  173. * ERRNO: N/A
  174. *
  175. * NOMANUAL
  176. */
  177. long generate_xid
  178.     (
  179.     struct if_info *  pIfData  /* interface used by lease */
  180.     )
  181.     {
  182.     time_t current = 0;
  183.     u_short result1 = 0;
  184.     u_short result2 = 0;
  185.     u_short result3 = 0;
  186.     u_short tmp[6]; 
  187.     bcopy (pIfData->haddr.haddr, (char *)tmp, 6);
  188.     dhcpTime (&current);
  189.     result1 = checksum (tmp, 6);
  190.     result2 = checksum ( (u_short *)&current, 2);
  191.     /*
  192.      * Although unlikely, it is possible that separate leases which are using
  193.      * the same network interface calculate a checksum at the same time. To
  194.      * guarantee uniqueness, include the value of the lease-specific pointer
  195.      * to the interface descriptor.
  196.      */
  197.     tmp [0] = ((long)pIfData) >> 16;
  198.     tmp [1] = ((long)pIfData) & 0xffff;
  199.     result3 = checksum (tmp, 4);
  200.     return ( (result1 << 16) + result2 + result3);
  201.     }
  202. /*******************************************************************************
  203. *
  204. * arp_check - use ARP to check if given address is in use
  205. *
  206. * This routine broadcasts an ARP request and waits for a reply to determine if
  207. * an IP address offered by a DHCP server is already in use.
  208. *
  209. * RETURNS: ERROR if ARP indicates client in use, or OK otherwise.
  210. *
  211. * ERRNO: N/A
  212. *
  213. * NOMANUAL
  214. */
  215. int arp_check
  216.     (
  217.     struct in_addr *target, 
  218.     struct if_info *pIfData  /* interface used by lease */
  219.     )
  220.     {
  221.     int i = 0;
  222.     int tmp;
  223.     char inbuf [MAX_ARPLEN];
  224.     char *pField1;
  225.     char *pField2;
  226.     struct arphdr * pArpHdr = NULL;
  227.     struct ifreq ifr;
  228.     struct timeval timeout;
  229.     fd_set  readFds;
  230.     bzero (inbuf, MAX_ARPLEN);
  231.     pArpHdr = (struct arphdr *) inbuf;
  232.     pArpHdr->ar_hrd = htons (pIfData->haddr.htype);
  233.     pArpHdr->ar_pro = htons (ETHERTYPE_IP);
  234.     pArpHdr->ar_hln = pIfData->haddr.hlen;
  235.     pArpHdr->ar_pln = 4;
  236.     pArpHdr->ar_op = htons (ARPOP_REQUEST);
  237.     /* Set sender H/W address to your address for ARP requests. (RFC 1541). */
  238.     pField1 = &inbuf [ARPHL];  /* Source hardware address. */
  239.     pField2 = pField1 + pArpHdr->ar_hln + 4;    /* Target hardware address. */
  240.     for (i = 0; i < pIfData->haddr.hlen; i++)
  241.         {
  242.         pField1[i] = pIfData->haddr.haddr[i];
  243.         pField2[i] = 0;
  244.         }
  245.     /* Set sender IP address to 0 for ARP requests as per RFC 1541. */
  246.     pField1 += pArpHdr->ar_hln;     /* Source IP address. */
  247.     pField2 += pArpHdr->ar_hln;     /* Target IP address. */
  248.     tmp = 0;
  249.     bcopy ( (char *)&tmp, pField1, pArpHdr->ar_pln);
  250.     bcopy ( (char *)&target->s_addr, pField2, pArpHdr->ar_pln);
  251.     /* Update BPF filter to check for ARP reply from target IP address. */
  252.     arpfilter [9].k = htonl (target->s_addr);
  253.     if (ioctl (bpfArpDev, BIOCSETF, (int)&arpread) != 0)
  254.         return (OK);     /* Ignore errors (permits use of IP address). */
  255.     tmp = ARPHL + 2 * (pArpHdr->ar_hln + 4);    /* Size of ARP message. */
  256.     /* Set BPF to monitor interface for reply. */
  257.     bzero ( (char *)&ifr, sizeof (struct ifreq));
  258.     sprintf (ifr.ifr_name, "%s%d", pIfData->iface->if_name,
  259.                                    pIfData->iface->if_unit);
  260.     if (ioctl (bpfArpDev, BIOCSETIF, (int)&ifr) != 0)
  261.         return (OK);     /* Ignore errors (permits use of IP address). */
  262.     /*
  263.      * Moved dhcpcArpSend after SETIF so that a valid reply received before 
  264.      * BPF device activation is not missed.
  265.      */
  266.     dhcpcArpSend (pIfData->iface, inbuf, tmp);
  267.     /* Wait one-half second for (unexpected) reply from target IP address. */
  268.     timeout.tv_sec = 0;
  269.     timeout.tv_usec = 500000;
  270.     FD_ZERO (&readFds);
  271.     FD_SET (bpfArpDev, &readFds);
  272.     tmp = select (bpfArpDev + 1, &readFds, NULL, NULL, &timeout);
  273.     /* Disconnect BPF device from input stream until next ARP probe. */
  274.     ioctl (bpfArpDev, BIOCSTOP, 0);
  275.     if (tmp)  /* ARP reply received? Duplicate IP address. */
  276.         return (ERROR);
  277.     else  /* Timeout occurred - no ARP reply. Probe succeeded. */
  278.         return (OK);
  279.     }
  280. /*******************************************************************************
  281. *
  282. * arp_reply - use ARP to notify other hosts of new address in use
  283. *
  284. * This routine broadcasts an ARP reply when the DHCP client changes addresses
  285. * to a new value retrieved from a DHCP server.
  286. *
  287. * RETURNS: -1 if ARP indicates client in use, or 0 otherwise.
  288. *
  289. * ERRNO: N/A
  290. *
  291. * NOMANUAL
  292. */
  293. int arp_reply
  294.     (
  295.     struct in_addr *ipaddr,
  296.     struct if_info *pIfData  /* interface used by lease */
  297.     )
  298.     {
  299.     int i = 0;
  300.     char inbuf [MAX_ARPLEN];
  301.     char *pField1;
  302.     char *pField2;
  303.     struct arphdr * pArpHdr = NULL;
  304.     bzero (inbuf, MAX_ARPLEN);
  305.     pArpHdr = (struct arphdr *) inbuf;
  306.     pArpHdr->ar_hrd = htons (pIfData->haddr.htype);
  307.     pArpHdr->ar_pro = htons (ETHERTYPE_IP);
  308.     pArpHdr->ar_hln = pIfData->haddr.hlen;
  309.     pArpHdr->ar_pln = 4;
  310.     pArpHdr->ar_op = htons (ARPOP_REPLY);
  311.     /*
  312.      * Set sender and target H/W addresses to your address
  313.      * for sending an unsolicited reply.
  314.      */
  315.     pField1 = &inbuf [ARPHL];                   /* Source hardware address. */
  316.     pField2 = pField1 + pArpHdr->ar_hln + 4;    /* Target hardware address. */
  317.     for (i = 0; i < pIfData->haddr.hlen; i++)
  318.         {
  319.         pField1[i] = pField2[i] = pIfData->haddr.haddr[i];
  320.         }
  321.     /*
  322.      * Set sender and target IP address to given value
  323.      * to announce new IP address usage.
  324.      */
  325.     pField1 += pArpHdr->ar_hln;     /* Source IP address. */
  326.     pField2 += pArpHdr->ar_hln;     /* Target IP address. */
  327.     bcopy ( (char *)&ipaddr->s_addr, pField1, pArpHdr->ar_pln);
  328.     bcopy ( (char *)&ipaddr->s_addr, pField2, pArpHdr->ar_pln);
  329.     /* Broadcast unsolicited reply to notify all hosts of new IP address. */
  330.     i = ARPHL + 2 * (pArpHdr->ar_hln + 4);    /* Size of ARP message. */
  331.     dhcpcArpSend (pIfData->iface, inbuf, i);
  332.     return (0);
  333.     }
  334. /*******************************************************************************
  335. *
  336. * nvttostr - convert NVT ASCII to strings
  337. *
  338. * This routine implements a limited NVT conversion which removes any embedded
  339. * NULL characters from the input string.
  340. *
  341. * RETURNS: N/A
  342. *
  343. * ERRNO: N/A
  344. *
  345. * NOMANUAL
  346. */
  347. int nvttostr
  348.     (
  349.     char * nvt, 
  350.     char * str,
  351.     int  length
  352.     )
  353.     {
  354.     FAST int i = 0;
  355.     FAST char *tmp = NULL;
  356.     tmp = str;
  357.     for (i = 0; i < length; i++) 
  358.         {
  359.         if (nvt[i] != '') 
  360.             {
  361.             *tmp = nvt[i];
  362.             tmp++;
  363.             }
  364.         }
  365.     str [length] = '';
  366.     return (0);
  367.     }
  368. /*******************************************************************************
  369. *
  370. * align_msg - set the buffer pointers to access message components
  371. *
  372. * This routine sets the pointers in the given message descriptor
  373. * structure to access the various components of a received DHCP
  374. * message. It is used internally by the state machine for incoming
  375. * data stored from the BPF device. 
  376. *
  377. * RETURNS: N/A
  378. *
  379. * ERRNO:   N/A
  380. *
  381. * NOMANUAL
  382. */
  383. void align_msg
  384.     (
  385.     struct msg *  rmsg,  /* Components of received message */
  386.     char *  rbuf  /* Received IP packet */
  387.     )
  388.     {
  389.     rmsg->ip = (struct ip *) rbuf;
  390.     if ( (ntohs (rmsg->ip->ip_off) & 0x1fff) == 0 &&
  391.         ntohs (rmsg->ip->ip_len) >= (DFLTDHCPLEN - DFLTOPTLEN + 4) + UDPHL 
  392.      + IPHL)
  393.         {
  394. #if BSD<44
  395.         rmsg->udp = (struct udphdr *)&rbuf [ (rmsg->ip->ip_v_hl & 0xf) * WORD];
  396.         rmsg->dhcp = (struct dhcp *)&rbuf [ (rmsg->ip->ip_v_hl & 0xf) * WORD +
  397.                                            UDPHL];
  398. #else
  399.         rmsg->udp = (struct udphdr *) &rbuf [rmsg->ip->ip_hl * WORD];
  400.         rmsg->dhcp = (struct dhcp *) &rbuf [rmsg->ip->ip_hl * WORD +
  401.                                             UDPHL];
  402. #endif
  403.         }
  404.     else
  405.         {
  406.         rmsg->udp = NULL;
  407.         rmsg->dhcp = NULL;
  408.         }
  409.     return;
  410.     }
  411. /*******************************************************************************
  412. *
  413. * dhcp_msgtoparam - expand DHCP message into data structure
  414. *
  415. * This routine converts a DHCP message from the transmission format into the
  416. * dhcp_param structure. It copies the core fields directly and multiplexes
  417. * the options to the appropriate handle_* functions.
  418. *
  419. * RETURNS: 0 if conversion successful, or -1 otherwise
  420. *
  421. * ERRNO: N/A
  422. *
  423. * INTERNAL
  424. *
  425. * When calculating the values for the lease timers, floating-point calculations
  426. * can't be used because some boards (notably the SPARC architectures) disable 
  427. * software floating point by default to speed up context switching. These 
  428. * boards abort with an exception when floating point operations are 
  429. * encountered. The error introduced by the integer approximations is not
  430. * significant.
  431. *
  432. * NOMANUAL
  433. */
  434. int dhcp_msgtoparam
  435.     (
  436.     struct dhcp *msg,
  437.     int msglen,
  438.     struct dhcp_param *parameter
  439.     )
  440.     {
  441.     FAST char *optp = NULL;
  442.     char tag = 0;
  443.     BOOL sname_is_opt = FALSE;
  444.     BOOL file_is_opt = FALSE;
  445.     int err = 0;
  446.     char *endofopt;
  447.     endofopt = &msg->options [msglen - DFLTDHCPLEN + DFLTOPTLEN];
  448.     bzero (parameter->got_option, OPTMASKSIZE);
  449.     for (optp = &msg->options [MAGIC_LEN]; optp <= endofopt; optp++) 
  450.         {
  451.         tag = *optp;
  452.         /* skip the PAD option */
  453.         if (tag == _DHCP_PAD_TAG)
  454.             continue;
  455.         /* stop processing when the END option is encountered */
  456.         if (tag == _DHCP_END_TAG) 
  457.             break;
  458.         /* handle the "Option Overload" */
  459.         if (tag == _DHCP_OPT_OVERLOAD_TAG) 
  460.             {
  461.             optp += 2;
  462.             switch (*optp) 
  463.                 {
  464.                 case FILE_ISOPT:
  465.                     file_is_opt = TRUE;
  466.             break;
  467.                 case SNAME_ISOPT:
  468.                     sname_is_opt = TRUE;
  469.                     break;
  470.                 case BOTH_AREOPT:
  471.                     file_is_opt = sname_is_opt = TRUE;
  472.                     break;
  473.                 default:
  474.                     break;
  475.                 }
  476.             continue;
  477.             }
  478.         if ((tag > 0) && (tag < MAXTAGNUM) && (handle_param [(int)tag] != NULL))
  479.             {
  480.             if ( (err = (*handle_param [ (int)tag]) (optp, parameter)) != 0) 
  481.                 return (err);
  482.             else 
  483.                 SETBIT (parameter->got_option, tag);
  484.             }
  485.         /* Set the message type tag to distinguish DHCP and BOOTP messages. */
  486.         else if (tag == _DHCP_MSGTYPE_TAG)
  487.             SETBIT (parameter->got_option, tag);
  488.         optp++;
  489.         optp += *optp;
  490.         }
  491.     if (file_is_opt) 
  492.         {
  493.         endofopt = &msg->file [MAX_FILE];
  494.         for (optp = msg->file; optp <= endofopt; optp++) 
  495.             {
  496.             tag = *optp;
  497.             /* skip the PAD option */
  498.             if (tag == _DHCP_PAD_TAG) 
  499.                 continue;
  500.             /* stop processing when the END option is reached */
  501.             if (tag == _DHCP_END_TAG)
  502.                 break;
  503.             if (handle_param [ (int)tag] != NULL) 
  504.                 {
  505.                 if ( (err = (*handle_param [ (int)tag]) (optp, parameter)) != 0)
  506.                     return (err);
  507.                 else 
  508.                     SETBIT(parameter->got_option, tag);
  509.                 }
  510.             /* Set the message type to distinguish DHCP and BOOTP messages. */
  511.             else if (tag == _DHCP_MSGTYPE_TAG)
  512.                 SETBIT (parameter->got_option, tag);
  513.             optp++;
  514.             optp += *optp;
  515.             }
  516.         } 
  517.     else 
  518.         {
  519.         if ( (parameter->file = calloc (1, strlen (msg->file) + 1)) == NULL) 
  520.             return (-1);
  521.         strcpy (parameter->file, msg->file);
  522.         }
  523.     if (sname_is_opt) 
  524.         {
  525.         endofopt = &msg->sname [MAX_SNAME];
  526.         for (optp = msg->sname; optp <= endofopt; optp++) 
  527.             {
  528.             tag = *optp;
  529.             /* skip the PAD option */
  530.             if (tag == _DHCP_PAD_TAG)
  531.                 continue;
  532.             /* stop processing when the END option is reached */ 
  533.             if (tag == _DHCP_END_TAG)
  534.         break;
  535.             if (handle_param [ (int)tag] != NULL) 
  536.                 {
  537.         if ( (err = (*handle_param [ (int)tag]) (optp, parameter)) != 0)
  538.             return(err);
  539.                 else
  540.             SETBIT (parameter->got_option, tag);
  541.                 }
  542.             /* Set the message type to distinguish DHCP and BOOTP messages. */
  543.             else if (tag == _DHCP_MSGTYPE_TAG)
  544.                 SETBIT (parameter->got_option, tag);
  545.             optp++;
  546.             optp += *optp;
  547.             }
  548.         } 
  549.     else 
  550.         {
  551.         if ( (parameter->sname = calloc (1, strlen (msg->sname) + 1)) == NULL) 
  552.             return (-1);
  553.         strcpy(parameter->sname, msg->sname);
  554.         }
  555.     parameter->ciaddr.s_addr = msg->ciaddr.s_addr;
  556.     parameter->yiaddr.s_addr = msg->yiaddr.s_addr;
  557.     parameter->siaddr.s_addr = msg->siaddr.s_addr;
  558.     parameter->giaddr.s_addr = msg->giaddr.s_addr;
  559.     if (ISSET (parameter->got_option, _DHCP_MSGTYPE_TAG))
  560.         parameter->msgtype = DHCP_NATIVE;
  561.     else
  562.         parameter->msgtype = DHCP_BOOTP;
  563.     /* Set lease duration to infinite for BOOTP replies. */
  564.     if (parameter->msgtype == DHCP_BOOTP)
  565.         {
  566.         parameter->lease_duration = ~0;
  567.         return (0);
  568.         }
  569.     /* Assign any server name provided if 'sname' used for options. */
  570.   
  571.     if (sname_is_opt)
  572.         {
  573.         parameter->sname = parameter->temp_sname;
  574.         parameter->temp_sname = NULL;
  575.         }
  576.     /* Assign any bootfile provided if 'file' used for options. */
  577.     if (file_is_opt)
  578.         {
  579.         if (ISSET (parameter->got_option, _DHCP_BOOTFILE_TAG))
  580.             {
  581.             parameter->file = parameter->temp_file;
  582.             parameter->temp_file = NULL;
  583.             }
  584.         }
  585.   
  586.     if (parameter->dhcp_t1 == 0)
  587.         {
  588.         /* Timer t1 is half the lease duration - but don't divide. */
  589.         parameter->dhcp_t1 = (parameter->lease_duration) >> 1;
  590.         SETBIT (parameter->got_option, _DHCP_T1_TAG);
  591.         }
  592.     if (parameter->dhcp_t2 == 0)
  593.         {
  594.         /* Timer T2 is .875 of the lease - but don't use floating point. */
  595.         int tmp = (parameter->lease_duration * 7) >> 3;
  596.         parameter->dhcp_t2 = (unsigned long) tmp;
  597.         SETBIT(parameter->got_option, _DHCP_T2_TAG);
  598.         }
  599.     return(0);
  600.     }
  601. /*******************************************************************************
  602. *
  603. * clean_param - clean the parameters data structure
  604. *
  605. * This routine frees all the memory allocated for the storage of parameters
  606. * received from a DHCP server. It is called to remove the unselected offers
  607. * or if an error occurs in the state machine after offers have been received.
  608. *
  609. * RETURNS: 0, always.
  610. *
  611. * ERRNO: N/A
  612. *
  613. * NOMANUAL
  614. */
  615. int clean_param
  616.     (
  617.     struct dhcp_param *param
  618.     )
  619.     {
  620.     if (param == NULL)
  621.         return(0);
  622.     if (param->sname != NULL) 
  623.         free (param->sname);
  624.     if (param->temp_sname != NULL) 
  625.         free (param->temp_sname);
  626.     if (param->file != NULL) 
  627.         free (param->file);
  628.     if (param->temp_file != NULL) 
  629.         free (param->temp_file);
  630.     if (param->hostname != NULL) 
  631.         free (param->hostname);
  632.     if (param->merit_dump != NULL) 
  633.         free (param->merit_dump);
  634.     if (param->dns_domain != NULL) 
  635.         free (param->dns_domain);
  636.     if (param->root_path != NULL) 
  637.         free (param->root_path);
  638.     if (param->extensions_path != NULL) 
  639.         free (param->extensions_path);
  640.     if (param->nis_domain != NULL) 
  641.         free (param->nis_domain);
  642.     if (param->nb_scope != NULL) 
  643.         free (param->nb_scope);
  644.     if (param->errmsg != NULL) 
  645.         free (param->errmsg);
  646.     if (param->nisp_domain != NULL) 
  647.         free (param->nisp_domain);
  648.     if (param->mtu_plateau_table != NULL) 
  649.         {
  650.         if (param->mtu_plateau_table->shortnum != NULL)
  651.             free (param->mtu_plateau_table->shortnum);
  652.         free (param->mtu_plateau_table);
  653.         }
  654.     if (param->subnet_mask != NULL) 
  655.         free (param->subnet_mask);
  656.     if (param->swap_server != NULL) 
  657.         free (param->swap_server);
  658.     if (param->brdcast_addr != NULL) 
  659.         free (param->brdcast_addr);
  660.     if (param->router != NULL) 
  661.         {
  662.         if (param->router->addr != NULL)
  663.             free (param->router->addr);
  664.         free (param->router);
  665.         }
  666.     if (param->time_server != NULL) 
  667.         {
  668.         if (param->time_server->addr != NULL)
  669.             free (param->time_server->addr);
  670.         free (param->time_server);
  671.         }
  672.     if (param->name_server != NULL) 
  673.         {
  674.         if (param->name_server->addr != NULL)
  675.             free (param->name_server->addr);
  676.         free (param->name_server);
  677.         }
  678.     if (param->dns_server != NULL) 
  679.         {
  680.         if (param->dns_server->addr != NULL)
  681.             free (param->dns_server->addr);
  682.         free (param->dns_server);
  683.         }
  684.     if (param->log_server != NULL) 
  685.         {
  686.         if (param->log_server->addr != NULL)
  687.             free (param->log_server->addr);
  688.         free (param->log_server);
  689.         }
  690.     if (param->cookie_server != NULL) 
  691.         {
  692.         if (param->cookie_server->addr != NULL)
  693.             free (param->cookie_server->addr);
  694.         free (param->cookie_server);
  695.         }
  696.     if (param->lpr_server != NULL)
  697.         {
  698.         if (param->lpr_server->addr != NULL)
  699.             free (param->lpr_server->addr);
  700.         free (param->lpr_server);
  701.         }
  702.     if (param->impress_server != NULL) 
  703.         {
  704.         if (param->impress_server->addr != NULL)
  705.             free (param->impress_server->addr);
  706.         free (param->impress_server);
  707.         }
  708.     if (param->rls_server != NULL) 
  709.         {
  710.         if (param->rls_server->addr != NULL)
  711.             free (param->rls_server->addr);
  712.         free (param->rls_server);
  713.         }
  714.     if (param->policy_filter != NULL) 
  715.         {
  716.         if (param->policy_filter->addr != NULL)
  717.             free (param->policy_filter->addr);
  718.         free (param->policy_filter);
  719.         }
  720.     if (param->static_route != NULL) 
  721.         {
  722.         if (param->static_route->addr != NULL)
  723.             free (param->static_route->addr);
  724.         free (param->static_route);
  725.         }
  726.     if (param->nis_server != NULL) 
  727.         {
  728.         if (param->nis_server->addr != NULL)
  729.             free (param->nis_server->addr);
  730.         free (param->nis_server);
  731.         }
  732.     if (param->ntp_server != NULL) 
  733.         {
  734.         if (param->ntp_server->addr != NULL)
  735.             free (param->ntp_server->addr);
  736.         free (param->ntp_server);
  737.         }
  738.     if (param->nbn_server != NULL) 
  739.         {
  740.         if (param->nbn_server->addr != NULL)
  741.             free (param->nbn_server->addr);
  742.         free (param->nbn_server);
  743.         }
  744.     if (param->nbdd_server != NULL) 
  745.         {
  746.         if (param->nbdd_server->addr != NULL)
  747.             free (param->nbdd_server->addr);
  748.         free (param->nbdd_server);
  749.         }
  750.     if (param->xfont_server != NULL) 
  751.         {
  752.         if (param->xfont_server->addr != NULL)
  753.             free (param->xfont_server->addr);
  754.         free (param->xfont_server);
  755.         }
  756.     if (param->xdisplay_manager != NULL) 
  757.         {
  758.         if (param->xdisplay_manager->addr != NULL)
  759.             free (param->xdisplay_manager->addr);
  760.         free (param->xdisplay_manager);
  761.         }
  762.     if (param->nisp_server != NULL) 
  763.         {
  764.         if (param->nisp_server->addr != NULL)
  765.             free (param->nisp_server->addr);
  766.         free (param->nisp_server);
  767.         }
  768.     if (param->mobileip_ha != NULL) 
  769.         {
  770.         if (param->mobileip_ha->addr != NULL)
  771.             free (param->mobileip_ha->addr);
  772.         free (param->mobileip_ha);
  773.         }
  774.     if (param->smtp_server != NULL) 
  775.         {
  776.         if (param->smtp_server->addr != NULL)
  777.             free (param->smtp_server->addr);
  778.         free (param->smtp_server);
  779.         }
  780.     if (param->pop3_server != NULL) 
  781.         {
  782.         if (param->pop3_server->addr != NULL)
  783.             free (param->pop3_server->addr);
  784.         free (param->pop3_server);
  785.         }
  786.     if (param->nntp_server != NULL) 
  787.         {
  788.         if (param->nntp_server->addr != NULL)
  789.             free (param->nntp_server->addr);
  790.         free (param->nntp_server);
  791.         }
  792.     if (param->dflt_www_server != NULL) 
  793.         {
  794.         if (param->dflt_www_server->addr != NULL)
  795.             free (param->dflt_www_server->addr);
  796.         free (param->dflt_www_server);
  797.         }
  798.     if (param->dflt_finger_server != NULL) 
  799.         {
  800.         if (param->dflt_finger_server->addr != NULL)
  801.             free (param->dflt_finger_server->addr);
  802.         free (param->dflt_finger_server);
  803.         }
  804.     if (param->dflt_irc_server != NULL) 
  805.         {
  806.         if (param->dflt_irc_server->addr != NULL)
  807.             free (param->dflt_irc_server->addr);
  808.         free (param->dflt_irc_server);
  809.         }
  810.     if (param->streettalk_server != NULL) 
  811.         {
  812.         if (param->streettalk_server->addr != NULL)
  813.             free (param->streettalk_server->addr);
  814.         free (param->streettalk_server);
  815.         }
  816.     if (param->stda_server != NULL) 
  817.         {
  818.         if (param->stda_server->addr != NULL)
  819.             free (param->stda_server->addr);
  820.         free (param->stda_server);
  821.         }
  822.     if (param->vendlist != NULL)
  823.         free (param->vendlist);
  824.     bzero ( (char *)param, sizeof (struct dhcp_param));
  825.     return (0);
  826.     }
  827. /*******************************************************************************
  828. *
  829. * merge_param - combine the parameters from DHCP server responses
  830. *
  831. * This routine copies any parameters from an initial lease offer which were not
  832. * supplied in the later acknowledgement from the server. If the acknowledgement
  833. * from the server duplicates parameters from the offer, then the memory       
  834. * allocated for those parameters in the offer is released.
  835. *
  836. * RETURNS: 0, always.
  837. *
  838. * ERRNO: N/A
  839. *
  840. * NOMANUAL
  841. */
  842. /*
  843.  * if there is no information in newp but oldp, copy it to newp
  844.  * else free the appropriate memory of oldp
  845.  */
  846. int merge_param
  847.     (
  848.     struct dhcp_param *oldp,     /* Parameters from lease offer. */
  849.     struct dhcp_param *newp      /* Parameters from lease acknowledgement. */
  850.     )
  851.     {
  852.     if (oldp == NULL || newp == NULL)
  853.         return (0);
  854.     if (newp->sname == NULL && oldp->sname != NULL)
  855.         newp->sname = oldp->sname;
  856.     else if (oldp->sname != NULL)
  857.         free (oldp->sname);
  858.     if (newp->file == NULL && oldp->file != NULL)
  859.         newp->file = oldp->file;
  860.     else if (oldp->file != NULL) 
  861.         free (oldp->file);
  862.  
  863.     if (newp->hostname == NULL && oldp->hostname != NULL)
  864.         newp->hostname = oldp->hostname;
  865.     else if (oldp->hostname != NULL)
  866.         free (oldp->hostname);
  867.     if (newp->merit_dump == NULL && oldp->merit_dump != NULL)
  868.         newp->merit_dump = oldp->merit_dump;
  869.     else if (oldp->merit_dump != NULL)
  870.         free (oldp->merit_dump);
  871.     if (newp->dns_domain == NULL && oldp->dns_domain != NULL)
  872.         newp->dns_domain = oldp->dns_domain;
  873.     else if (oldp->dns_domain != NULL) 
  874.         free (oldp->dns_domain);
  875.     if (newp->root_path == NULL && oldp->root_path != NULL)
  876.         newp->root_path = oldp->root_path;
  877.     else if (oldp->root_path != NULL) 
  878.         free (oldp->root_path);
  879.     if (newp->extensions_path == NULL && oldp->extensions_path != NULL)
  880.         newp->extensions_path = oldp->extensions_path;
  881.     else if (oldp->extensions_path != NULL) 
  882.         free (oldp->extensions_path);
  883.     if (newp->nis_domain == NULL && oldp->nis_domain != NULL)
  884.         newp->nis_domain = oldp->nis_domain;
  885.     else if (oldp->nis_domain != NULL) 
  886.         free (oldp->nis_domain);
  887.     if (newp->nb_scope == NULL && oldp->nb_scope != NULL)
  888.         newp->nb_scope = oldp->nb_scope;
  889.     else if (oldp->nb_scope != NULL) 
  890.         free (oldp->nb_scope);
  891.     if (newp->errmsg == NULL && oldp->errmsg != NULL)
  892.         newp->errmsg = oldp->errmsg;
  893.     else if (oldp->errmsg != NULL) 
  894.         free (oldp->errmsg);
  895.     if (newp->nisp_domain == NULL && oldp->nisp_domain != NULL)
  896.         newp->nisp_domain = oldp->nisp_domain;
  897.     else if (oldp->nisp_domain != NULL) 
  898.         free (oldp->nisp_domain);
  899.     if (newp->mtu_plateau_table == NULL && oldp->mtu_plateau_table != NULL) 
  900.         newp->mtu_plateau_table = oldp->mtu_plateau_table;
  901.     else 
  902.         {
  903.         if (oldp->mtu_plateau_table != NULL)
  904.             {
  905.             if (oldp->mtu_plateau_table->shortnum != NULL)
  906.                 free (oldp->mtu_plateau_table->shortnum);
  907.             free (oldp->mtu_plateau_table);
  908.             }
  909.         }
  910.     if (newp->subnet_mask == NULL && oldp->subnet_mask != NULL)
  911.         newp->subnet_mask = oldp->subnet_mask;
  912.     else if (oldp->subnet_mask != NULL) 
  913.         free (oldp->subnet_mask);
  914.     if (newp->swap_server == NULL && oldp->swap_server != NULL)
  915.         newp->swap_server = oldp->swap_server;
  916.     else if (oldp->swap_server != NULL) 
  917.         free (oldp->swap_server);
  918.     if (newp->brdcast_addr == NULL && oldp->brdcast_addr != NULL)
  919.         newp->brdcast_addr = oldp->brdcast_addr;
  920.     else if (oldp->brdcast_addr != NULL) 
  921.         free (oldp->brdcast_addr);
  922.     if (newp->router_solicit.s_addr == 0 && oldp->router_solicit.s_addr != 0)
  923.         bcopy ( (char *)&oldp->router_solicit, 
  924.                (char *)&newp->router_solicit, sizeof (u_long));
  925.     if (newp->router == NULL && oldp->router != NULL) 
  926.       newp->router = oldp->router;
  927.     else 
  928.         {
  929.         if (oldp->router != NULL && oldp->router->addr != NULL) 
  930.             free (oldp->router->addr);
  931.         if (oldp->router != NULL)
  932.             free (oldp->router);
  933.         }
  934.     if (newp->time_server == NULL && oldp->time_server != NULL)
  935.         newp->time_server = oldp->time_server;
  936.     else 
  937.         { 
  938.         if (oldp->time_server != NULL && oldp->time_server->addr != NULL) 
  939.             free (oldp->time_server->addr);
  940.         if (oldp->time_server != NULL)
  941.             free (oldp->time_server);
  942.         }
  943.     if (newp->name_server == NULL && oldp->name_server != NULL) 
  944.         newp->name_server = oldp->name_server;
  945.     else 
  946.         {
  947.         if (oldp->name_server != NULL && oldp->name_server->addr != NULL) 
  948.             free (oldp->name_server->addr);
  949.         if (oldp->name_server != NULL)
  950.             free (oldp->name_server);
  951.         }
  952.     if (newp->dns_server == NULL && oldp->dns_server != NULL) 
  953.         newp->dns_server = oldp->dns_server;
  954.     else 
  955.         {
  956.         if (oldp->dns_server != NULL && oldp->dns_server->addr != NULL) 
  957.             free (oldp->dns_server->addr);
  958.         if (oldp->dns_server != NULL)
  959.             free (oldp->dns_server);
  960.         }
  961.     if (newp->log_server == NULL && oldp->log_server != NULL) 
  962.         newp->log_server = oldp->log_server;
  963.     else 
  964.         {
  965.         if (oldp->log_server != NULL && oldp->log_server->addr != NULL) 
  966.             free (oldp->log_server->addr);
  967.         if (oldp->log_server != NULL)
  968.             free (oldp->log_server);
  969.         }
  970.     if (newp->cookie_server == NULL && oldp->cookie_server != NULL) 
  971.         newp->cookie_server = oldp->cookie_server;
  972.     else 
  973.         {
  974.         if (oldp->cookie_server != NULL && oldp->cookie_server->addr != NULL) 
  975.             free (oldp->cookie_server->addr);
  976.         if (oldp->cookie_server != NULL)
  977.             free (oldp->cookie_server);
  978.         }
  979.     if (newp->lpr_server == NULL && oldp->lpr_server != NULL) 
  980.         newp->lpr_server = oldp->lpr_server;
  981.     else 
  982.         {
  983.         if (oldp->lpr_server != NULL && oldp->lpr_server->addr != NULL) 
  984.             free (oldp->lpr_server->addr);
  985.         if (oldp->lpr_server != NULL)
  986.             free (oldp->lpr_server);
  987.         }
  988.     if (newp->impress_server == NULL && oldp->impress_server != NULL) 
  989.         newp->impress_server = oldp->impress_server;
  990.     else 
  991.         {
  992.         if (oldp->impress_server != NULL && oldp->impress_server->addr != NULL)
  993.             free (oldp->impress_server->addr);
  994.         if (oldp->impress_server != NULL)
  995.             free (oldp->impress_server);
  996.         }
  997.     if (newp->rls_server == NULL && oldp->rls_server != NULL) 
  998.         newp->rls_server = oldp->rls_server;
  999.     else 
  1000.         {
  1001.         if (oldp->rls_server != NULL && oldp->rls_server->addr != NULL) 
  1002.             free (oldp->rls_server->addr);
  1003.         if (oldp->rls_server != NULL)
  1004.             free (oldp->rls_server);
  1005.         }
  1006.     if (newp->policy_filter == NULL && oldp->policy_filter != NULL) 
  1007.         newp->policy_filter = oldp->policy_filter;
  1008.     else 
  1009.         {
  1010.         if (oldp->policy_filter != NULL && oldp->policy_filter->addr != NULL) 
  1011.             free (oldp->policy_filter->addr);
  1012.         if (oldp->policy_filter != NULL)
  1013.             free (oldp->policy_filter);
  1014.         }
  1015.     if (newp->static_route == NULL && oldp->static_route != NULL) 
  1016.         newp->static_route = oldp->static_route;
  1017.     else 
  1018.         {
  1019.         if (oldp->static_route != NULL && oldp->static_route->addr != NULL) 
  1020.             free (oldp->static_route->addr);
  1021.         if (oldp->static_route != NULL)
  1022.             free (oldp->static_route);
  1023.         }
  1024.     if (newp->nis_server == NULL && oldp->nis_server != NULL) 
  1025.         newp->nis_server = oldp->nis_server;
  1026.     else 
  1027.         {
  1028.         if (oldp->nis_server != NULL && oldp->nis_server->addr != NULL) 
  1029.             free (oldp->nis_server->addr);
  1030.         if (oldp->nis_server != NULL)
  1031.             free (oldp->nis_server);
  1032.         }
  1033.     if (newp->ntp_server == NULL && oldp->ntp_server != NULL) 
  1034.         newp->ntp_server = oldp->ntp_server;
  1035.     else 
  1036.         {
  1037.         if (oldp->ntp_server != NULL && oldp->ntp_server->addr != NULL) 
  1038.             free (oldp->ntp_server->addr);
  1039.         if (oldp->ntp_server != NULL)
  1040.             free (oldp->ntp_server);
  1041.         }
  1042.     if (newp->nbn_server == NULL && oldp->nbn_server != NULL) 
  1043.         newp->nbn_server = oldp->nbn_server;
  1044.     else 
  1045.         {
  1046.         if (oldp->nbn_server != NULL && oldp->nbn_server->addr != NULL) 
  1047.             free (oldp->nbn_server->addr);
  1048.         if (oldp->nbn_server != NULL)
  1049.             free (oldp->nbn_server);
  1050.         }
  1051.     if (newp->nbdd_server == NULL && oldp->nbdd_server != NULL) 
  1052.         newp->nbdd_server = oldp->nbdd_server;
  1053.     else 
  1054.         {
  1055.         if (oldp->nbdd_server != NULL && oldp->nbdd_server->addr != NULL) 
  1056.             free (oldp->nbdd_server->addr);
  1057.         if (oldp->nbdd_server != NULL)
  1058.             free (oldp->nbdd_server);
  1059.         }
  1060.     if (newp->xfont_server == NULL && oldp->xfont_server != NULL) 
  1061.         newp->xfont_server = oldp->xfont_server;
  1062.     else 
  1063.         {
  1064.         if (oldp->xfont_server != NULL && oldp->xfont_server->addr != NULL) 
  1065.             free (oldp->xfont_server->addr);
  1066.         if (oldp->xfont_server != NULL)
  1067.             free (oldp->xfont_server);
  1068.         }
  1069.     if (newp->xdisplay_manager == NULL && oldp->xdisplay_manager != NULL) 
  1070.         newp->xdisplay_manager = oldp->xdisplay_manager;
  1071.     else 
  1072.         {
  1073.         if (oldp->xdisplay_manager != NULL && 
  1074.             oldp->xdisplay_manager->addr != NULL) 
  1075.             free (oldp->xdisplay_manager->addr);
  1076.         if (oldp->xdisplay_manager != NULL)
  1077.             free (oldp->xdisplay_manager);
  1078.         }
  1079.     if (newp->nisp_server == NULL && oldp->nisp_server != NULL) 
  1080.         newp->nisp_server = oldp->nisp_server;
  1081.     else 
  1082.         {
  1083.         if (oldp->nisp_server != NULL && oldp->nisp_server->addr != NULL) 
  1084.             free (oldp->nisp_server->addr);
  1085.         if (oldp->nisp_server != NULL)
  1086.             free (oldp->nisp_server);
  1087.         }
  1088.     if (newp->mobileip_ha == NULL && oldp->mobileip_ha != NULL) 
  1089.         newp->mobileip_ha = oldp->mobileip_ha;
  1090.     else 
  1091.         { 
  1092.         if (oldp->mobileip_ha != NULL && oldp->mobileip_ha->addr != NULL) 
  1093.             free (oldp->mobileip_ha->addr);
  1094.         if (oldp->mobileip_ha != NULL)
  1095.             free (oldp->mobileip_ha);
  1096.         }
  1097.     if (newp->smtp_server == NULL && oldp->smtp_server != NULL) 
  1098.         newp->smtp_server = oldp->smtp_server;
  1099.     else 
  1100.         {
  1101.         if (oldp->smtp_server != NULL && oldp->smtp_server->addr != NULL) 
  1102.             free (oldp->smtp_server->addr);
  1103.         if (oldp->smtp_server != NULL)
  1104.             free (oldp->smtp_server);
  1105.         }
  1106.     if (newp->pop3_server == NULL && oldp->pop3_server != NULL) 
  1107.         newp->pop3_server = oldp->pop3_server;
  1108.     else 
  1109.         {
  1110.         if (oldp->pop3_server != NULL && oldp->pop3_server->addr != NULL) 
  1111.             free (oldp->pop3_server->addr);
  1112.         if (oldp->pop3_server != NULL)
  1113.             free (oldp->pop3_server);
  1114.         }
  1115.     if (newp->nntp_server == NULL && oldp->nntp_server != NULL) 
  1116.         newp->nntp_server = oldp->nntp_server;
  1117.     else 
  1118.         {
  1119.         if (oldp->nntp_server != NULL && oldp->nntp_server->addr != NULL) 
  1120.             free (oldp->nntp_server->addr);
  1121.         if (oldp->nntp_server != NULL)
  1122.             free (oldp->nntp_server);
  1123.         }
  1124.     if (newp->dflt_www_server == NULL && oldp->dflt_www_server != NULL) 
  1125.         newp->dflt_www_server = oldp->dflt_www_server;
  1126.     else 
  1127.         {
  1128.         if (oldp->dflt_www_server != NULL && 
  1129.             oldp->dflt_www_server->addr != NULL) 
  1130.             free (oldp->dflt_www_server->addr);
  1131.         if (oldp->dflt_www_server != NULL)
  1132.             free (oldp->dflt_www_server);
  1133.         }
  1134.     if (newp->dflt_finger_server == NULL && oldp->dflt_finger_server != NULL)
  1135.         newp->dflt_finger_server = oldp->dflt_finger_server;
  1136.     else 
  1137.         {
  1138.         if (oldp->dflt_finger_server != NULL && 
  1139.             oldp->dflt_finger_server->addr != NULL) 
  1140.             free (oldp->dflt_finger_server->addr);
  1141.         if (oldp->dflt_finger_server != NULL)
  1142.             free (oldp->dflt_finger_server);
  1143.         }
  1144.     if (newp->dflt_irc_server == NULL && oldp->dflt_irc_server != NULL) 
  1145.         newp->dflt_irc_server = oldp->dflt_irc_server;
  1146.     else 
  1147.         {
  1148.         if (oldp->dflt_irc_server != NULL && 
  1149.             oldp->dflt_irc_server->addr != NULL) 
  1150.             free (oldp->dflt_irc_server->addr);
  1151.         if (oldp->dflt_irc_server != NULL)
  1152.             free (oldp->dflt_irc_server);
  1153.         }
  1154.     if (newp->streettalk_server == NULL && oldp->streettalk_server != NULL) 
  1155.         newp->streettalk_server = oldp->streettalk_server;
  1156.     else 
  1157.         {
  1158.         if (oldp->streettalk_server != NULL && 
  1159.             oldp->streettalk_server->addr != NULL) 
  1160.             free (oldp->streettalk_server->addr);
  1161.         if (oldp->streettalk_server != NULL)
  1162.             free (oldp->streettalk_server);
  1163.         }
  1164.     if (newp->stda_server == NULL && oldp->stda_server != NULL) 
  1165.         newp->stda_server = oldp->stda_server;
  1166.     else 
  1167.         {
  1168.         if (oldp->stda_server != NULL && oldp->stda_server->addr != NULL) 
  1169.             free (oldp->stda_server->addr);
  1170.         if (oldp->stda_server != NULL)
  1171.             free (oldp->stda_server);
  1172.         }
  1173.     /* Remove any vendor-specific information from an earlier response. */
  1174.     if (oldp->vendlist != NULL)
  1175.         free (oldp->vendlist);
  1176.  
  1177.     return (0);
  1178.     }
  1179. /*******************************************************************************
  1180. *
  1181. * initialize - initialize data structures for network message transfer
  1182. *
  1183. * This routine sets the DHCP ports, resets the network interface, and allocates
  1184. * storage for incoming messages. It is called from the dhcp_client_setup()
  1185. * routine during the overall initialization of the DHCP client library.
  1186. *
  1187. * RETURNS: 0 if initialization successful, or -1 otherwise. 
  1188. *
  1189. * ERRNO: N/A
  1190. *
  1191. * NOMANUAL
  1192. */
  1193. int initialize
  1194.     (
  1195.     int  serverPort,  /* port monitored by DHCP servers */
  1196.     int  clientPort,  /* port monitored by DHCP client */
  1197.     int  bufSize  /* required size for transmit buffer */
  1198.     )
  1199.     {
  1200.     char *  sbufp;
  1201.     int  arpSize;  /* Maximum size for ARP reply. */
  1202.     int         result;
  1203.     /* Create BPF device for performing ARP probes. */
  1204.     arpSize = bufSize - DFLTDHCPLEN - UDPHL - IPHL;  /* Max. link header */
  1205.     arpSize += MAX_ARPLEN + sizeof (struct bpf_hdr);
  1206.     if (bpfDevCreate ("/bpf/dhcpc-arp", 1, arpSize) == ERROR)
  1207.         {
  1208.         return (-1);
  1209.         }
  1210.     bpfArpDev = open ("/bpf/dhcpc-arp0", 0, 0);
  1211.     if (bpfArpDev < 0)
  1212.         {
  1213.         bpfDevDelete ("/bpf/dhcpc-arp0");
  1214.         return (-1);
  1215.         }
  1216.     /* Enable immediate mode for reading messages */
  1217.     result = 1;
  1218.     result = ioctl (bpfArpDev, BIOCIMMEDIATE, (int)&result);
  1219.     if (result != 0)
  1220. {
  1221. close (bpfArpDev);
  1222.         bpfDevDelete ("/bpf/dhcpc-arp0");
  1223. return (-1);
  1224. }
  1225.     /*
  1226.      * Set filter to accept ARP replies when the arp_check() routine
  1227.      * attaches the BPF device to a network interface.
  1228.      */
  1229.     if (ioctl (bpfArpDev, BIOCSETF, (int)&arpread) != 0)
  1230.         {
  1231.         close (bpfArpDev);
  1232.         bpfDevDelete ("/bpf/dhcpc-arp0");
  1233.         return (-1);
  1234.         } 
  1235.     /* Always use default ports for client and server. */
  1236.     dhcps_port = htons (serverPort);
  1237.     dhcpc_port = htons (clientPort);
  1238.     sbuf.size = bufSize;    /* Maximum message size, provided by user. */
  1239.     if ( (sbuf.buf = (char *)memalign (4, bufSize)) == NULL)
  1240.         {
  1241. #ifdef DHCPC_DEBUG
  1242.         logMsg ("allocation error for sbuf in initializen", 0, 0, 0, 0, 0, 0);
  1243. #endif
  1244.         close (bpfArpDev);
  1245.         bpfDevDelete ("/bpf/dhcpc-arp0");
  1246.         return(-1);
  1247.         } 
  1248.     bzero (sbuf.buf, sbuf.size);
  1249.     sbufp = sbuf.buf;
  1250.     dhcpcMsgOut.ip = (struct ip *)sbufp;
  1251.     dhcpcMsgOut.udp = (struct udphdr *)&sbufp [IPHL];
  1252.     dhcpcMsgOut.dhcp = (struct dhcp *)&sbufp [IPHL + UDPHL];
  1253.     return (0);
  1254.     }
  1255. /*******************************************************************************
  1256. *
  1257. * reset_if - halt the network and reset the network interface
  1258. *
  1259. * This routine sets the IP address of the network interface to a random
  1260. * value of 10.x.x.x, which is an old ARPA debugging address, resets the
  1261. * broadcast address and subnet mask, and flushes the routing tables.
  1262. * It is called before initiating a lease negotiation if no event notification 
  1263. * hook is present. It is also always called for a lease established at boot 
  1264. * time, whether or not an event hook is registered for that lease.
  1265. *
  1266. * RETURNS: N/A
  1267. *
  1268. * ERRNO: N/A
  1269. *
  1270. * NOMANUAL
  1271. */
  1272. void reset_if
  1273.     (
  1274.     struct if_info *  pIfData  /* interface used by lease */
  1275.     )
  1276.     {
  1277.     struct in_addr addr;
  1278.     struct in_addr mask; 
  1279.     struct in_addr brdaddr;
  1280.     addr.s_addr = htonl ( (generate_xid (pIfData) & 0xfff) | 0x0a000000);
  1281.     mask.s_addr = htonl (0xff000000);
  1282.     brdaddr.s_addr = inet_addr ("255.255.255.255");
  1283.     config_if (pIfData, &addr, &mask, &brdaddr);
  1284.     flushroutes ();
  1285.     }
  1286. /*******************************************************************************
  1287. *
  1288. * down_if - change network interface flags
  1289. *
  1290. * This routine clears the IFF_UP flag of the network interface. It is called
  1291. * when a lease is manually terminated with a dhcpcRelease() or dhcpcShutdown()
  1292. * call if no event hook is present for the lease. It is always called when
  1293. * removing a lease established at boot time.
  1294. *
  1295. * RETURNS: N/A
  1296. *
  1297. * ERRNO: N/A
  1298. *
  1299. * NOMANUAL
  1300. */
  1301. void down_if
  1302.     (
  1303.     struct if_info *ifp
  1304.     )
  1305.     {
  1306.     int sockfd;
  1307.     struct ifreq ridreq;
  1308.     reset_if (ifp);
  1309.     if ( (sockfd = socket (AF_INET, SOCK_RAW, 0)) < 0) 
  1310.         return;
  1311.     bzero ( (char *)&ridreq, sizeof (struct ifreq));
  1312.     sprintf (ridreq.ifr_name, "%s%d", ifp->name, ifp->unit);
  1313.     ridreq.ifr_addr.sa_len = sizeof (struct sockaddr_in);
  1314.     /* down interface */
  1315.     ioctl (sockfd, SIOCGIFFLAGS, (int) (caddr_t) &ridreq);
  1316.     ridreq.ifr_flags &= (~IFF_UP);
  1317.     ioctl (sockfd, SIOCSIFFLAGS, (int) (caddr_t) &ridreq);
  1318.     close (sockfd);
  1319.     return;
  1320.     }
  1321. /*******************************************************************************
  1322. *
  1323. * config_if - configure network interface
  1324. *
  1325. * This routine sets one or more of the current address, broadcast address, and 
  1326. * subnet mask, depending on whether or not the corresponding parameters are 
  1327. * NULL.  It is called when a lease is obtained or the network is reset. When a 
  1328. * new lease is obtained, a successful return value is used to cause assignment 
  1329. * of new routing tables.
  1330. *
  1331. * RETURNS: -1 on error, 0 if new settings assigned, 1 otherwise.
  1332. *
  1333. * ERRNO: N/A
  1334. *
  1335. * NOMANUAL
  1336. */
  1337. int config_if
  1338.     (
  1339.     struct if_info *ifp,
  1340.     struct in_addr *addr,
  1341.     struct in_addr *mask,
  1342.     struct in_addr *brdcst
  1343.     )
  1344.     {
  1345.     int sockfd = 0;
  1346.     int status;
  1347.     struct ifreq ifr;
  1348.     struct in_addr current_addr;
  1349.     struct in_addr  current_mask;
  1350.     struct in_addr  current_brdcst;
  1351.     if ( (sockfd = socket (AF_INET, SOCK_RAW, 0)) < 0) 
  1352.         return (-1);
  1353.     bzero ( (char *)&current_addr, sizeof (current_addr));
  1354.     bzero ( (char *)&current_mask, sizeof (current_mask));
  1355.     bzero ( (char *)&current_brdcst, sizeof (current_brdcst));
  1356.     bzero ( (char *)&ifr, sizeof (struct ifreq));
  1357.     sprintf (ifr.ifr_name, "%s%d", ifp->name, ifp->unit);
  1358.     ifr.ifr_addr.sa_len = sizeof (struct sockaddr_in);
  1359.     status = ioctl (sockfd, SIOCGIFADDR, (int)&ifr);
  1360.     current_addr.s_addr =
  1361.                        ( (struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  1362.     status = ioctl (sockfd, SIOCGIFNETMASK, (int)&ifr);
  1363.     current_mask.s_addr =
  1364.                        ( (struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  1365.     status = ioctl (sockfd, SIOCGIFBRDADDR, (int)&ifr);
  1366.     current_brdcst.s_addr =
  1367.                   ( (struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr.s_addr;
  1368.     if (current_addr.s_addr == addr->s_addr &&
  1369.         (mask == NULL || current_mask.s_addr == mask->s_addr) &&
  1370.         (brdcst == NULL || current_brdcst.s_addr == brdcst->s_addr)) 
  1371.         {
  1372.         close (sockfd);
  1373.         return (1);
  1374.         }
  1375.     flushroutes (); 
  1376.     /* down interface */
  1377.     ioctl (sockfd, SIOCGIFFLAGS, (int)&ifr);
  1378.     ifr.ifr_flags &= (~IFF_UP);
  1379.     ioctl (sockfd, SIOCSIFFLAGS, (int)&ifr);
  1380.     /*
  1381.      * Deleting the interface address is required to correctly scrub the
  1382.      * routing table based on the current netmask.
  1383.      */
  1384.     bzero ( (char *)&ifr, sizeof (struct ifreq));
  1385.     sprintf (ifr.ifr_name, "%s%d", ifp->name, ifp->unit);
  1386.     ifr.ifr_addr.sa_len = sizeof (struct sockaddr_in);
  1387.     ( (struct sockaddr_in *) &ifr.ifr_addr)->sin_family = AF_INET;
  1388.     ( (struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = 
  1389.                                                            current_addr.s_addr;
  1390.     status = ioctl (sockfd, SIOCDIFADDR, (int)&ifr);
  1391.     if (status < 0) 
  1392.         {
  1393.          /* Sometimes no address has been set, so ignore that error. */
  1394.         if (errno != EADDRNOTAVAIL)
  1395.             {
  1396.             close (sockfd);
  1397.             return (-1);
  1398.             }
  1399.         }
  1400.     if (mask != NULL) 
  1401.         {
  1402.         bzero ( (char *)&ifr, sizeof (struct ifreq));
  1403.         sprintf (ifr.ifr_name, "%s%d", ifp->name, ifp->unit);
  1404.         ifr.ifr_addr.sa_len = sizeof (struct sockaddr_in);
  1405.         ( (struct sockaddr_in *) &ifr.ifr_addr)->sin_family = AF_INET;
  1406.         ( (struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = 
  1407.                                                                  mask->s_addr;
  1408.         status = ioctl (sockfd, SIOCSIFNETMASK, (int)&ifr);
  1409.         if (status < 0) 
  1410.             {
  1411.             close (sockfd);
  1412.             return (-1);
  1413.             }
  1414.         }
  1415.     if (brdcst != NULL) 
  1416.         {
  1417.         bzero ( (char *)&ifr, sizeof (struct ifreq));
  1418.         sprintf (ifr.ifr_name, "%s%d", ifp->name, ifp->unit);
  1419.         ifr.ifr_addr.sa_len = sizeof (struct sockaddr_in);
  1420.         ( (struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_family = AF_INET;
  1421.         ( (struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr.s_addr = 
  1422.                                                                brdcst->s_addr;
  1423.         status = ioctl (sockfd, SIOCSIFBRDADDR, (int)&ifr);
  1424.         if (status < 0) 
  1425.             {
  1426.             close (sockfd);
  1427.             return (-1);
  1428.             }
  1429.         }
  1430.     if (addr != NULL) 
  1431.         {
  1432.         bzero ( (char *)&ifr, sizeof (struct ifreq));
  1433.         sprintf (ifr.ifr_name, "%s%d", ifp->name, ifp->unit);
  1434.         ifr.ifr_addr.sa_len = sizeof (struct sockaddr_in);
  1435.         ( (struct sockaddr_in *) &ifr.ifr_addr)->sin_family = AF_INET;
  1436.         ( (struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = 
  1437.                                                                  addr->s_addr;
  1438.         status = ioctl (sockfd, SIOCSIFADDR, (int)&ifr);
  1439.         if (status < 0) 
  1440.             {
  1441.             close (sockfd);
  1442.             return (-1);
  1443.             }
  1444.         }
  1445.     /* bring interface back up */
  1446.     ioctl (sockfd, SIOCGIFFLAGS, (int)&ifr);
  1447.     ifr.ifr_flags |= IFF_UP;
  1448.     ioctl (sockfd, SIOCSIFFLAGS, (int)&ifr);
  1449.     close (sockfd);
  1450.     return (0);
  1451.     }
  1452. /*******************************************************************************
  1453. *
  1454. * set_route - set network routing table
  1455. *
  1456. * This routine is called when config_if() assigns new address information.
  1457. * It sets the default route for a new lease if the DHCP server provided the
  1458. * router IP address.
  1459. *
  1460. * RETURNS: N/A
  1461. *
  1462. * ERRNO: N/A
  1463. *
  1464. * NOMANUAL
  1465. */
  1466. void set_route
  1467.     (
  1468.     struct dhcp_param *param
  1469.     )
  1470.     {
  1471.     int sockfd = 0;
  1472. #if BSD<44
  1473.     struct rtentry rt;
  1474. #else
  1475.     struct ortentry rt;
  1476. #endif
  1477.     struct sockaddr dst, gateway;
  1478.     if (param == NULL)
  1479.         return;
  1480.     sockfd = socket(AF_INET, SOCK_RAW, 0);
  1481.     if (sockfd < 0) 
  1482.         {
  1483. #ifdef DHCPC_DEBUG
  1484.         logMsg("socket() error in set_route()n", 0, 0, 0, 0, 0, 0);
  1485. #endif
  1486.         return;
  1487.         }
  1488.     /* set default route, if router IP address is available. */
  1489.     if (ISSET(param->got_option, _DHCP_ROUTER_TAG) && param->router != NULL &&
  1490.         param->router->addr != NULL) 
  1491.         {
  1492. #if BSD<44
  1493.         bzero ( (char *)&rt, sizeof (struct rtentry));
  1494. #else
  1495.         bzero ( (char *)&rt, sizeof (struct ortentry));
  1496. #endif
  1497.         bzero ( (char *)&dst, sizeof (struct sockaddr));
  1498.         bzero ( (char *)&gateway, sizeof (struct sockaddr));
  1499.         rt.rt_flags = RTF_UP | RTF_GATEWAY;
  1500.         ( (struct sockaddr_in *)&dst)->sin_family = AF_INET;
  1501.         ( (struct sockaddr_in *)&dst)->sin_len = sizeof (struct sockaddr_in);
  1502.         ( (struct sockaddr_in *)&dst)->sin_addr.s_addr = INADDR_ANY; 
  1503.         ( (struct sockaddr_in *)&gateway)->sin_family = AF_INET;
  1504.         ( (struct sockaddr_in *)&gateway)->sin_len = 
  1505.                                                    sizeof (struct sockaddr_in);
  1506.         ( (struct sockaddr_in *)&gateway)->sin_addr.s_addr =
  1507.                                                    param->router->addr->s_addr;
  1508.         rt.rt_dst = dst;
  1509.         rt.rt_gateway = gateway;
  1510.         if (ioctl (sockfd, SIOCADDRT, (int)&rt) < 0) 
  1511.             {
  1512. #ifdef DHCPC_DEBUG
  1513.             logMsg ("SIOCADDRT (default route)n", 0, 0, 0, 0, 0, 0);
  1514. #endif
  1515.             close (sockfd);
  1516.             }
  1517.         }
  1518.     close (sockfd);
  1519.     return;
  1520.     }
  1521. /*******************************************************************************
  1522. *
  1523. * make_decline - construct a DHCP decline message
  1524. *
  1525. * This routine constructs an outgoing UDP/IP message containing the values
  1526. * required to decline an offered IP address.
  1527. *
  1528. * RETURNS: size of decline message, or 0 if error
  1529. *
  1530. * ERRNO: N/A
  1531. *
  1532. * NOMANUAL
  1533. */
  1534. int make_decline
  1535.     (
  1536.     struct dhcp_reqspec *pReqSpec,
  1537.     struct if_info *  pIfData  /* interface used by lease */
  1538.     )
  1539.     {
  1540.     int offopt = 0;  /* offset in options field */
  1541.     int msgsize;  /* total size of DHCP message */
  1542.     u_long tmpul = 0;
  1543.     struct ps_udph pudph;
  1544.     bzero ( (char *)&pudph, sizeof (pudph));
  1545.     /* construct dhcp part */
  1546.     bzero (sbuf.buf, sbuf.size);
  1547.     dhcpcMsgOut.dhcp->op = BOOTREQUEST;
  1548.     dhcpcMsgOut.dhcp->htype = pIfData->haddr.htype;
  1549.     dhcpcMsgOut.dhcp->hlen = pIfData->haddr.hlen;
  1550.     dhcpcMsgOut.dhcp->xid = htonl (generate_xid (pIfData));
  1551.     dhcpcMsgOut.dhcp->giaddr = dhcpcMsgIn.dhcp->giaddr;
  1552.     bcopy (pIfData->haddr.haddr, dhcpcMsgOut.dhcp->chaddr,
  1553.            dhcpcMsgOut.dhcp->hlen);
  1554.     /* insert magic cookie */
  1555.     bcopy ( (char *)dhcpCookie, dhcpcMsgOut.dhcp->options, MAGIC_LEN);
  1556.     offopt = MAGIC_LEN;
  1557.     /* insert message type */
  1558.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MSGTYPE_TAG;
  1559.     dhcpcMsgOut.dhcp->options [offopt++] = 1;
  1560.     dhcpcMsgOut.dhcp->options [offopt++] = DHCPDECLINE;
  1561.     /* insert requested IP */
  1562.     if (pReqSpec->ipaddr.s_addr == 0)
  1563.         return (0);
  1564.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_REQUEST_IPADDR_TAG;
  1565.     dhcpcMsgOut.dhcp->options [offopt++] = 4;
  1566.     bcopy ( (char *)&pReqSpec->ipaddr, &dhcpcMsgOut.dhcp->options [offopt], 4);
  1567.     offopt += 4;
  1568.     /* insert client identifier */
  1569.     if (pReqSpec->clid != NULL)
  1570.         {
  1571.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_CLIENT_ID_TAG;
  1572.         dhcpcMsgOut.dhcp->options [offopt++] = pReqSpec->clid->len;
  1573.         bcopy (pReqSpec->clid->id, &dhcpcMsgOut.dhcp->options [offopt], 
  1574.                pReqSpec->clid->len);
  1575.         offopt += pReqSpec->clid->len;
  1576.         }
  1577.     /* insert server identifier */
  1578.    dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_SERVER_ID_TAG;
  1579.    dhcpcMsgOut.dhcp->options [offopt++] = 4;
  1580.    bcopy ( (char *)&pReqSpec->srvaddr, &dhcpcMsgOut.dhcp->options [offopt], 4);
  1581.    offopt += 4;
  1582.     /* Insert error message, if available. */
  1583.     if (pReqSpec->dhcp_errmsg != NULL)
  1584.         {
  1585.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_ERRMSG_TAG;
  1586.         dhcpcMsgOut.dhcp->options [offopt++] = strlen (pReqSpec->dhcp_errmsg);
  1587.         bcopy (pReqSpec->dhcp_errmsg, &dhcpcMsgOut.dhcp->options [offopt],
  1588.        strlen (pReqSpec->dhcp_errmsg));
  1589.         offopt += strlen (pReqSpec->dhcp_errmsg);
  1590.         }
  1591.     dhcpcMsgOut.dhcp->options [offopt] = _DHCP_END_TAG;
  1592.     /*
  1593.      * For backward compatibility with earlier DHCP servers, set the
  1594.      * reported message size to be at least as large as a BOOTP message.
  1595.      */
  1596.     msgsize = (DFLTDHCPLEN - DFLTOPTLEN) + offopt + 1;
  1597.     if (msgsize < DFLTBOOTPLEN)
  1598.         msgsize = DFLTBOOTPLEN;
  1599.     /* construct udp part */
  1600.     dhcpcMsgOut.udp->uh_sport = dhcpc_port;
  1601.     dhcpcMsgOut.udp->uh_dport = dhcps_port;
  1602.     dhcpcMsgOut.udp->uh_ulen = htons (msgsize + UDPHL);
  1603.     dhcpcMsgOut.udp->uh_sum = 0;
  1604.     /* fill pseudo udp header */
  1605.     pudph.srcip.s_addr = 0;
  1606.     pudph.dstip.s_addr = pReqSpec->srvaddr.s_addr;
  1607.     pudph.zero = 0;
  1608.     pudph.prto = IPPROTO_UDP;
  1609.     pudph.ulen = dhcpcMsgOut.udp->uh_ulen;
  1610.     dhcpcMsgOut.udp->uh_sum = udp_cksum (&pudph, (char *)dhcpcMsgOut.udp,
  1611.                                          ntohs (pudph.ulen));
  1612.     /* construct ip part */
  1613. #if BSD<44
  1614.     dhcpcMsgOut.ip->ip_v_hl = 0;
  1615.     dhcpcMsgOut.ip->ip_v_hl = IPVERSION << 4;
  1616.     dhcpcMsgOut.ip->ip_v_hl |= IPHL >> 2;
  1617. #else
  1618.     dhcpcMsgOut.ip->ip_v = IPVERSION;
  1619.     dhcpcMsgOut.ip->ip_hl = IPHL >> 2;
  1620. #endif
  1621.     dhcpcMsgOut.ip->ip_tos = 0;
  1622.     dhcpcMsgOut.ip->ip_len = htons (msgsize + UDPHL + IPHL);
  1623.     tmpul = generate_xid (pIfData);
  1624.     tmpul += (tmpul >> 16);
  1625.     dhcpcMsgOut.ip->ip_id = (u_short) (~tmpul);
  1626.     dhcpcMsgOut.ip->ip_off = htons(IP_DF);                         /* XXX */
  1627.     dhcpcMsgOut.ip->ip_ttl = 0x20;                                 /* XXX */
  1628.     dhcpcMsgOut.ip->ip_p = IPPROTO_UDP;
  1629.     msgsize += UDPHL + IPHL;
  1630.     dhcpcMsgOut.ip->ip_src.s_addr = 0;
  1631.     dhcpcMsgOut.ip->ip_dst.s_addr = INADDR_BROADCAST;
  1632.     dhcpcMsgOut.ip->ip_sum = 0;
  1633. #if BSD<44
  1634.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip,
  1635.                                         (dhcpcMsgOut.ip->ip_v_hl & 0xf) << 2);
  1636. #else
  1637.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip,
  1638.                                         dhcpcMsgOut.ip->ip_hl << 2);
  1639. #endif
  1640.     return (msgsize);
  1641.     }
  1642. /*******************************************************************************
  1643. *
  1644. * make_release - construct a DHCP release message
  1645. *
  1646. * This routine constructs an outgoing UDP/IP message containing the values
  1647. * required to relinquish the active lease.
  1648. *
  1649. * RETURNS: Size of DHCP message, in bytes
  1650. *
  1651. * ERRNO: N/A
  1652. *
  1653. * NOMANUAL
  1654. */
  1655. int make_release
  1656.     (
  1657.     struct dhcp_reqspec *pReqSpec,
  1658.     struct if_info *  pIfData,  /* interface used by lease */
  1659.     BOOL  oldFlag  /* Use older (padded) DHCP message format? */
  1660.     )
  1661.     {
  1662.     int offopt = 0;  /* offset in options field */
  1663.     int msgsize;
  1664.     /* construct dhcp part */
  1665.     bzero (sbuf.buf, sbuf.size);
  1666.     dhcpcMsgOut.dhcp->op = BOOTREQUEST;
  1667.     dhcpcMsgOut.dhcp->htype = pIfData->haddr.htype;
  1668.     dhcpcMsgOut.dhcp->hlen = pIfData->haddr.hlen;
  1669.     dhcpcMsgOut.dhcp->xid = htonl (generate_xid (pIfData));
  1670.     dhcpcMsgOut.dhcp->ciaddr = pReqSpec->ipaddr;
  1671.     bcopy (pIfData->haddr.haddr, dhcpcMsgOut.dhcp->chaddr,
  1672.            dhcpcMsgOut.dhcp->hlen);
  1673.     /* insert magic cookie */
  1674.     bcopy ( (char *)dhcpCookie, dhcpcMsgOut.dhcp->options, MAGIC_LEN);
  1675.     offopt = MAGIC_LEN;
  1676.     /* insert message type */
  1677.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MSGTYPE_TAG;
  1678.     dhcpcMsgOut.dhcp->options [offopt++] = 1;
  1679.     dhcpcMsgOut.dhcp->options [offopt++] = DHCPRELEASE;
  1680.     /* insert client identifier */
  1681.     if (pReqSpec->clid != NULL)
  1682.         {
  1683.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_CLIENT_ID_TAG;
  1684.         dhcpcMsgOut.dhcp->options [offopt++] = pReqSpec->clid->len;
  1685.         bcopy (pReqSpec->clid->id, &dhcpcMsgOut.dhcp->options [offopt],
  1686.                pReqSpec->clid->len);
  1687.         offopt += pReqSpec->clid->len;
  1688.         }
  1689.     /* insert server identifier */
  1690.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_SERVER_ID_TAG;
  1691.     dhcpcMsgOut.dhcp->options [offopt++] = 4;
  1692.     bcopy ( (char *)&pReqSpec->srvaddr, &dhcpcMsgOut.dhcp->options [offopt], 4);
  1693.     offopt += 4;
  1694.     /* Insert error message, if available. */
  1695.     if (pReqSpec->dhcp_errmsg != NULL)
  1696.         {
  1697.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_ERRMSG_TAG;
  1698.         dhcpcMsgOut.dhcp->options [offopt++] = strlen (pReqSpec->dhcp_errmsg);
  1699.         bcopy (pReqSpec->dhcp_errmsg, &dhcpcMsgOut.dhcp->options [offopt],
  1700.                strlen (pReqSpec->dhcp_errmsg));
  1701.         offopt += strlen (pReqSpec->dhcp_errmsg);
  1702.         }
  1703.     dhcpcMsgOut.dhcp->options [offopt] = _DHCP_END_TAG;
  1704.     msgsize = (DFLTDHCPLEN - DFLTOPTLEN) + offopt + 1;
  1705.     if (oldFlag)
  1706.         {
  1707.         /*
  1708.          * This flag indicates that the client did not receive a response
  1709.          * to the initial set of discover messages but did receive one
  1710.          * using the older message format. The (older) responding server
  1711.          * ignores messages less than the minimum length obtained with a
  1712.          * fixed options field, so pad the message to reach that length.
  1713.          */
  1714.         if (msgsize < DFLTDHCPLEN)
  1715.             msgsize = DFLTDHCPLEN;
  1716.         }
  1717.     return (msgsize);
  1718.     }
  1719. /*******************************************************************************
  1720. *
  1721. * dhcp_decline - send a DHCP decline message
  1722. *
  1723. * This routine constructs a message declining an offered IP address and sends
  1724. * it directly to the responding server. It is called when an ARP request 
  1725. * detects that the offered address is already in use.
  1726. *
  1727. * RETURNS: 0 if message sent, or -1 on error.
  1728. *
  1729. * ERRNO: N/A
  1730. *
  1731. * NOMANUAL
  1732. */
  1733. int dhcp_decline
  1734.     (
  1735.     struct dhcp_reqspec *  pDhcpcReqSpec,
  1736.     struct if_info *  pIfData  /* interface used by lease */
  1737.     )
  1738.     {
  1739.     struct sockaddr_in  dest;  /* Server's destination address */
  1740.     struct ifnet *  pIf;  /* Transmit device */
  1741.     int  length;  /* Amount of data in message */
  1742. #ifdef DHCPC_DEBUG
  1743.     char output [INET_ADDR_LEN];
  1744. #endif
  1745.     if (pDhcpcReqSpec->srvaddr.s_addr == 0)
  1746.         return(-1);
  1747.     length = make_decline (pDhcpcReqSpec, pIfData);
  1748.     if (length == 0)
  1749.         return (-1);
  1750.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  1751.     dest.sin_len = sizeof (struct sockaddr_in);
  1752.     dest.sin_family = AF_INET;
  1753.     dest.sin_addr.s_addr = INADDR_BROADCAST;
  1754.     pIf = pIfData->iface;
  1755.     if (dhcpSend (pIf, &dest, sbuf.buf, length, TRUE) == ERROR)
  1756.         {
  1757. #ifdef DHCPC_DEBUG
  1758.         logMsg ("Can't send DHCPDECLINE.n", 0, 0, 0, 0, 0, 0);
  1759. #endif
  1760.         return (-1);
  1761.         }
  1762. #ifdef DHCPC_DEBUG
  1763.     inet_ntoa_b (pDhcpcReqSpec->ipaddr, output);
  1764.     logMsg ("send DHCPDECLINE(%s)n", (int)output, 0, 0, 0, 0, 0);
  1765. #endif
  1766.     return (0);
  1767.     }
  1768. /*******************************************************************************
  1769. *
  1770. * dhcp_release - send a DHCP release message
  1771. *
  1772. * This routine constructs a message declining an offered IP address and sends
  1773. * it directly to the responding server. It is called when an error prevents
  1774. * the use of an acquired lease, or when the lease is relinquished manually
  1775. * by a dhcpcRelease() or dhcpcShutdown() call. The message is sent directly to 
  1776. * the responding DHCP server.
  1777. *
  1778. * RETURNS: 0 if message sent, or -1 on error.
  1779. *
  1780. * ERRNO: N/A
  1781. *
  1782. * NOMANUAL
  1783. */
  1784. int dhcp_release
  1785.     (
  1786.     struct dhcp_reqspec *pDhcpcReqSpec,
  1787.     struct if_info *  pIfData,  /* interface used by lease */
  1788.     BOOL  oldFlag  /* Use older (padded) DHCP message format? */
  1789.     )
  1790.     {
  1791. #ifdef DHCPC_DEBUG
  1792.     char output [INET_ADDR_LEN];
  1793. #endif
  1794.     int length;
  1795.     if (pDhcpcReqSpec->srvaddr.s_addr == 0)
  1796.         return (-1);
  1797.     /* send DHCP message */
  1798.     length = make_release (pDhcpcReqSpec, pIfData, oldFlag);
  1799.     if (send_unicast (&pDhcpcReqSpec->srvaddr, dhcpcMsgOut.dhcp, length) < 0) 
  1800.         return (-1);
  1801. #ifdef DHCPC_DEBUG
  1802.     inet_ntoa_b (pDhcpcReqSpec->ipaddr, output);
  1803.     logMsg("send DHCPRELEASE(%s)n", (int)output, 0, 0, 0, 0, 0);
  1804. #endif
  1805.     return(0);
  1806.     }
  1807. /*******************************************************************************
  1808. *
  1809. * dhcpcPrivateCleanup - remove data structures from client library
  1810. *
  1811. * The dhcpcCleanup routine uses this routine to release the locally
  1812. * allocated data structures which the initialize() call creates. It is
  1813. * part of the shutdown process for the DHCP client library. The routine
  1814. * executes after all leases are inactive and their data is released.
  1815. *
  1816. * RETURNS: N/A
  1817. *
  1818. * ERRNO: N/A
  1819. *
  1820. * NOMANUAL
  1821. */
  1822. void dhcpcPrivateCleanup (void)
  1823.     {
  1824.     /* Close open file and remove BPF device for ARP probe. */
  1825.     close (bpfArpDev);
  1826.     bpfDevDelete ("/bpf/dhcpc-arp");
  1827.     /* Release transmission buffer. */
  1828.     free (sbuf.buf);
  1829.     return;
  1830.     }
  1831.     
  1832. /*******************************************************************************
  1833. *
  1834. * set_declinfo - initialize request specification for decline message
  1835. *
  1836. * This routine assigns the fields in the request specifier used to construct
  1837. * messages to the appropriate values for a DHCP decline message according to
  1838. * the parameters of the currently active lease.
  1839. *
  1840. * RETURNS: N/A
  1841. *
  1842. * ERRNO: N/A
  1843. *
  1844. * NOMANUAL
  1845. */
  1846. void set_declinfo
  1847.     (
  1848.     struct dhcp_reqspec *pDhcpcReqSpec,
  1849.     LEASE_DATA *  pLeaseData,
  1850.     char *errmsg,
  1851.     int arpans
  1852.     )
  1853.     {
  1854.     char output [INET_ADDR_LEN];
  1855.     struct dhcp_param *  paramp;
  1856.     paramp = pLeaseData->dhcpcParam;
  1857.     pDhcpcReqSpec->ipaddr = paramp->yiaddr;
  1858.     pDhcpcReqSpec->srvaddr = paramp->server_id;
  1859.     if (pLeaseData->leaseReqSpec.clid != NULL)
  1860.         pDhcpcReqSpec->clid = pLeaseData->leaseReqSpec.clid;
  1861.     else
  1862.         pDhcpcReqSpec->clid = NULL;
  1863.     if (errmsg[0] == 0) 
  1864.         {
  1865.         inet_ntoa_b (paramp->yiaddr, output);
  1866.         if (arpans != OK)
  1867.             sprintf (errmsg, "IP address (%s) is already in use.", output);
  1868.         else 
  1869.             sprintf (errmsg, "IP address (%s) doesn't match requested value.",
  1870.                       output);
  1871.         }
  1872.     pDhcpcReqSpec->dhcp_errmsg = errmsg;
  1873.     return;
  1874.     }
  1875. /*******************************************************************************
  1876. *
  1877. * set_relinfo - initialize request specification for release message
  1878. *
  1879. * This routine assigns the fields in the request specifier used to construct
  1880. * messages to the appropriate values for a DHCP release message according to
  1881. * the parameters of the currently active lease.
  1882. *
  1883. * RETURNS: N/A
  1884. *
  1885. * ERRNO: N/A
  1886. *
  1887. * NOMANUAL
  1888. */
  1889. void set_relinfo
  1890.     (
  1891.     struct dhcp_reqspec *pDhcpcReqSpec,
  1892.     LEASE_DATA *  pLeaseData,
  1893.     char *errmsg
  1894.     )
  1895.     {
  1896.     char output [INET_ADDR_LEN];
  1897.     struct dhcp_param *paramp;
  1898.     paramp = pLeaseData->dhcpcParam;
  1899.     pDhcpcReqSpec->ipaddr.s_addr = paramp->yiaddr.s_addr;
  1900.     pDhcpcReqSpec->srvaddr.s_addr = paramp->server_id.s_addr;
  1901.     if (pLeaseData->leaseReqSpec.clid != NULL)
  1902.         pDhcpcReqSpec->clid = pLeaseData->leaseReqSpec.clid;
  1903.     else
  1904.         pDhcpcReqSpec->clid = NULL;
  1905.     if (pLeaseData->leaseReqSpec.dhcp_errmsg != NULL)
  1906.         pDhcpcReqSpec->dhcp_errmsg = pLeaseData->leaseReqSpec.dhcp_errmsg;
  1907.     else
  1908.         {
  1909.         inet_ntoa_b (paramp->yiaddr, output);
  1910.         sprintf (errmsg, "Releasing the current IP address (%s).", output);
  1911.         pDhcpcReqSpec->dhcp_errmsg = errmsg;
  1912.         }
  1913.     return;
  1914.     }
  1915. /*******************************************************************************
  1916. *
  1917. * make_discover - construct a DHCP discover message
  1918. *
  1919. * This routine constructs an outgoing UDP/IP message containing the values
  1920. * required to broadcast a lease request. The <xidFlag> indicates whether
  1921. * a transaction ID should be generated. Because multiple leases are supported,
  1922. * the contents of the transmit buffer are not guaranteed to remain unchanged.
  1923. * Therefore, each message must be rebuilt before it is sent. However, the
  1924. * transaction ID must not be changed after the initial transmission.
  1925. *
  1926. * RETURNS: Size of discover message, in bytes
  1927. *
  1928. * ERRNO: N/A
  1929. *
  1930. * NOMANUAL
  1931. */
  1932. int make_discover 
  1933.     (
  1934.     LEASE_DATA *  pLeaseData,  /* lease-specific data structures */
  1935.     BOOL  xidFlag  /* generate a new transaction ID? */
  1936.     )
  1937.     {
  1938.     int offopt = 0;  /* offset in options field */
  1939.     int msgsize;  /* total size of DHCP message */
  1940.     u_long tmpul = 0;
  1941.     u_short tmpus = 0;
  1942.     struct dhcp_reqspec *  pReqSpec;
  1943.     pReqSpec = &pLeaseData->leaseReqSpec;
  1944.     /* construct dhcp part */
  1945.     bzero (sbuf.buf, sbuf.size);
  1946.     dhcpcMsgOut.dhcp->op = BOOTREQUEST;
  1947.     dhcpcMsgOut.dhcp->htype = pLeaseData->ifData.haddr.htype;
  1948.     dhcpcMsgOut.dhcp->hlen = pLeaseData->ifData.haddr.hlen;
  1949.     if (xidFlag)
  1950.         {
  1951.         pLeaseData->xid = generate_xid (&pLeaseData->ifData);
  1952.         /* Update BPF filter to check for new transaction ID. */
  1953.         dhcpfilter [20].k = pLeaseData->xid;
  1954.         ioctl (pLeaseData->ifData.bpfDev, BIOCSETF, (u_int)&dhcpread);
  1955.         }
  1956.     dhcpcMsgOut.dhcp->xid = htonl (pLeaseData->xid);
  1957.     bcopy (pLeaseData->ifData.haddr.haddr, dhcpcMsgOut.dhcp->chaddr, 
  1958.            dhcpcMsgOut.dhcp->hlen);
  1959.     /* insert magic cookie */
  1960.     bcopy ( (char *)dhcpCookie, dhcpcMsgOut.dhcp->options, MAGIC_LEN);
  1961.     offopt = MAGIC_LEN;
  1962.     /* insert message type */
  1963.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MSGTYPE_TAG;
  1964.     dhcpcMsgOut.dhcp->options [offopt++] = 1;
  1965.     dhcpcMsgOut.dhcp->options [offopt++] = DHCPDISCOVER;
  1966.     /* Insert requested IP address, if any. */
  1967.     if (pReqSpec->ipaddr.s_addr != 0)
  1968.         {
  1969.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_REQUEST_IPADDR_TAG;
  1970.         dhcpcMsgOut.dhcp->options [offopt++] = 4;
  1971.         bcopy ( (char *)&pReqSpec->ipaddr.s_addr,
  1972.                 &dhcpcMsgOut.dhcp->options [offopt], 4);
  1973.         offopt += 4;
  1974.         }
  1975.     /* insert Maximum DHCP message size */
  1976.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MAXMSGSIZE_TAG;
  1977.     dhcpcMsgOut.dhcp->options [offopt++] = 2;
  1978.     tmpus = htons (pReqSpec->maxlen);
  1979.     bcopy ( (char *)&tmpus, &dhcpcMsgOut.dhcp->options [offopt], 2);
  1980.     offopt += 2;
  1981.     /* Insert request list, if any. */
  1982.     if (pReqSpec->reqlist.len != 0)
  1983.         {
  1984.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_REQ_LIST_TAG;
  1985.         dhcpcMsgOut.dhcp->options [offopt++] = pReqSpec->reqlist.len;
  1986.         bcopy (pReqSpec->reqlist.list, &dhcpcMsgOut.dhcp->options [offopt],
  1987.                pReqSpec->reqlist.len);
  1988.         offopt += pReqSpec->reqlist.len;
  1989.         }
  1990.     /* Insert all other entries from custom options field, if any. */
  1991.     if (pReqSpec->pOptions != NULL)
  1992.         {
  1993.         bcopy (pReqSpec->pOptions, &dhcpcMsgOut.dhcp->options [offopt],
  1994.                pReqSpec->optlen);
  1995.         offopt += pReqSpec->optlen;
  1996.         }
  1997.     dhcpcMsgOut.dhcp->options[offopt] = _DHCP_END_TAG;
  1998.     msgsize = (DFLTDHCPLEN - DFLTOPTLEN) + offopt + 1;
  1999.     if (pLeaseData->oldFlag)
  2000.         {
  2001.         /*
  2002.          * This flag indicates that the client did not receive a response
  2003.          * to the initial set of discover messages. Older servers might
  2004.          * ignore messages less than the minimum length obtained with a
  2005.          * fixed options field, so pad the message to reach that length.
  2006.          */
  2007.         if (msgsize < DFLTDHCPLEN)
  2008.             msgsize = DFLTDHCPLEN;
  2009.         }
  2010.     /* make udp part */
  2011.     /* fill udp header */
  2012.     dhcpcMsgOut.udp->uh_sport = dhcpc_port;
  2013.     dhcpcMsgOut.udp->uh_dport = dhcps_port;
  2014.     dhcpcMsgOut.udp->uh_ulen = htons (msgsize + UDPHL);
  2015.     /* fill pseudo udp header */
  2016.     spudph.srcip.s_addr = 0;
  2017.     spudph.dstip.s_addr = 0xffffffff;
  2018.     spudph.zero = 0;
  2019.     spudph.prto = IPPROTO_UDP;
  2020.     spudph.ulen = dhcpcMsgOut.udp->uh_ulen;
  2021.     /* make ip part */
  2022.     /* fill ip header */
  2023. #if BSD<44
  2024.     dhcpcMsgOut.ip->ip_v_hl = 0;
  2025.     dhcpcMsgOut.ip->ip_v_hl = IPVERSION << 4;
  2026.     dhcpcMsgOut.ip->ip_v_hl |= IPHL >> 2;
  2027. #else
  2028.     dhcpcMsgOut.ip->ip_v = IPVERSION;
  2029.     dhcpcMsgOut.ip->ip_hl = IPHL >> 2;
  2030. #endif
  2031.     dhcpcMsgOut.ip->ip_tos = 0;
  2032.     dhcpcMsgOut.ip->ip_len = htons (msgsize + UDPHL + IPHL);
  2033.     tmpul = generate_xid (&pLeaseData->ifData);
  2034.     tmpul += (tmpul >> 16);
  2035.     /* dhcpcMsgOut.ip->ip_id = htons ( (u_short) (~tmpul));*/
  2036.     dhcpcMsgOut.ip->ip_id = (u_short) (~tmpul);
  2037.     dhcpcMsgOut.ip->ip_off = htons (IP_DF);                        /* XXX */
  2038.     dhcpcMsgOut.ip->ip_ttl = 0x20;                                 /* XXX */
  2039.     dhcpcMsgOut.ip->ip_p = IPPROTO_UDP;
  2040.     dhcpcMsgOut.ip->ip_src.s_addr = 0;
  2041.     dhcpcMsgOut.ip->ip_dst.s_addr = 0xffffffff;
  2042.     dhcpcMsgOut.ip->ip_sum = 0;
  2043.     msgsize += UDPHL + IPHL;
  2044. #if BSD<44
  2045.     /* tmpus = checksum ( (u_short *)snd.ip, (snd.ip->ip_v_hl & 0xf) << 2);
  2046.     snd.ip->ip_sum = htons (tmpus); */
  2047.   dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip, 
  2048.                                       (dhcpcMsgOut.ip->ip_v_hl & 0xf) << 2);
  2049. #else
  2050.     /* tmpus = checksum ( (u_short *)snd.ip, snd.ip->ip_hl << 2);
  2051.     snd.ip->ip_sum = htons (tmpus); */
  2052.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip, 
  2053.                                         dhcpcMsgOut.ip->ip_hl << 2);
  2054. #endif
  2055.     return (msgsize);
  2056.     }
  2057. /*******************************************************************************
  2058. *
  2059. * make_request - construct a DHCP request message
  2060. *
  2061. * This routine constructs an outgoing UDP/IP message containing the values
  2062. * required to request a lease. There is some variation in contents depending
  2063. * on whether the request is meant to establish a lease, renew a lease, or
  2064. * verify an existing lease. Also, when constructing a lease renewal message,
  2065. * the routine exits before any headers are are added so that the message may 
  2066. * be sent with send_unicast().
  2067. *
  2068. * Besides the five types of lease request messages, this routine constructs
  2069. * the DHCPINFORM messages added in RFC 2131 when the <type> argument is
  2070. * INFORMING. Those messages enable a host to obtain additional configuration
  2071. * parameters even though it has an externally configured address.
  2072. *
  2073. * .IP
  2074. * The <xidFlag> indicates whether a transaction ID should be generated. 
  2075. * Because multiple leases are supported, the contents of the transmit buffer 
  2076. * are not guaranteed to remain unchanged. Therefore, each message must be 
  2077. * rebuilt before it is sent. However, the transaction ID must not be changed 
  2078. * after the initial transmission.
  2079. *
  2080. * RETURNS: size of message if constructed succesfully, or -1 on error.
  2081. *
  2082. * ERRNO: N/A
  2083. *
  2084. * NOMANUAL
  2085. */
  2086. int make_request
  2087.     (
  2088.     LEASE_DATA *  pLeaseData,  /* lease-specific data structures */
  2089.     int type,
  2090.     BOOL  xidFlag  /* generate a new transaction ID? */
  2091.     )
  2092.     {
  2093.     int offopt = 0;                   /* offset in options field */
  2094.     int msgsize;  /* total size of DHCP message */
  2095.     int discoverSecs;   /* 'secs' field from DHCP discover message */
  2096.     u_long tmpul = 0;
  2097.     u_short tmpus = 0;
  2098.     struct dhcp_reqspec *  pReqSpec = NULL;
  2099.     struct dhcp_param *  paramp = NULL;
  2100.     pReqSpec = &pLeaseData->leaseReqSpec;
  2101.     paramp = pLeaseData->dhcpcParam;
  2102.     /* 
  2103.      * save value of 'secs' field from the previous DISCOVER message 
  2104.      * before dhcpcMsgOut is cleared. The 'secs' value is required for
  2105.      * the outgoing REQUEST message (RFC 2131).
  2106.      */
  2107.     discoverSecs = dhcpcMsgOut.dhcp->secs;
  2108.     /* construct dhcp part */
  2109.     bzero (sbuf.buf, sbuf.size);
  2110.     dhcpcMsgOut.dhcp->op = BOOTREQUEST;
  2111.     dhcpcMsgOut.dhcp->htype = pLeaseData->ifData.haddr.htype;
  2112.     dhcpcMsgOut.dhcp->hlen = pLeaseData->ifData.haddr.hlen;
  2113.     if (xidFlag)
  2114.         {
  2115.         pLeaseData->xid = generate_xid (&pLeaseData->ifData);
  2116.         /* Update BPF filter to check for new transaction ID. */
  2117.         dhcpfilter [20].k = pLeaseData->xid;
  2118.         ioctl (pLeaseData->ifData.bpfDev, BIOCSETF, (u_int)&dhcpread);
  2119.         }
  2120.     dhcpcMsgOut.dhcp->xid = htonl (pLeaseData->xid);
  2121.     /* set it to 'secs' value from DISCOVER message */
  2122.     dhcpcMsgOut.dhcp->secs = discoverSecs;  
  2123.     if (type == INFORMING)
  2124.         {
  2125.         /* Set externally assigned IP address. */
  2126.         dhcpcMsgOut.dhcp->ciaddr.s_addr = pReqSpec->ipaddr.s_addr;
  2127.         }
  2128.     else if (type == REQUESTING || type == REBOOTING)
  2129.         dhcpcMsgOut.dhcp->ciaddr.s_addr = 0;
  2130.     else
  2131.         dhcpcMsgOut.dhcp->ciaddr.s_addr = paramp->yiaddr.s_addr;
  2132.     bcopy (pLeaseData->ifData.haddr.haddr, dhcpcMsgOut.dhcp->chaddr, 
  2133.            dhcpcMsgOut.dhcp->hlen);
  2134.     /* insert magic cookie */
  2135.     bcopy ( (char *)dhcpCookie, dhcpcMsgOut.dhcp->options, MAGIC_LEN);
  2136.     offopt = MAGIC_LEN;
  2137.     /* insert message type */
  2138.     
  2139.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MSGTYPE_TAG;
  2140.     dhcpcMsgOut.dhcp->options [offopt++] = 1;
  2141.     if (type == INFORMING)
  2142.         dhcpcMsgOut.dhcp->options [offopt++] = DHCPINFORM;
  2143.     else
  2144.         dhcpcMsgOut.dhcp->options [offopt++] = DHCPREQUEST;
  2145.     /* Insert requesting IP address when required. Omit when forbidden. */
  2146.     if (type == REQUESTING || type == REBOOTING) 
  2147.         {
  2148.         if (paramp->yiaddr.s_addr != 0)
  2149.             {
  2150.             dhcpcMsgOut.dhcp->options[offopt++] = _DHCP_REQUEST_IPADDR_TAG;
  2151.             dhcpcMsgOut.dhcp->options[offopt++] = 4;
  2152.             bcopy ( (char *)&paramp->yiaddr.s_addr, 
  2153.                    &dhcpcMsgOut.dhcp->options [offopt], 4);
  2154.             offopt += 4;
  2155.             }
  2156.         else
  2157.             return (-1);
  2158.         }
  2159.     /* Insert server identifier when required. Omit when forbidden. */
  2160.     if (type == REQUESTING) 
  2161.         {
  2162.         if (paramp->server_id.s_addr == 0) 
  2163.             {
  2164.             return(-1);
  2165.             }
  2166.         dhcpcMsgOut.dhcp->options[offopt++] = _DHCP_SERVER_ID_TAG;
  2167.         dhcpcMsgOut.dhcp->options[offopt++] = 4;
  2168.         bcopy ( (char *)&paramp->server_id.s_addr, 
  2169.                &dhcpcMsgOut.dhcp->options [offopt], 4);
  2170.         offopt += 4;
  2171.         }
  2172.     /* insert Maximum DHCP message size */
  2173.     dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_MAXMSGSIZE_TAG;
  2174.     dhcpcMsgOut.dhcp->options [offopt++] = 2;
  2175.     tmpus = htons (pReqSpec->maxlen);
  2176.     bcopy ( (char *)&tmpus, &dhcpcMsgOut.dhcp->options [offopt], 2);
  2177.     offopt += 2;
  2178.     /* Insert request list, if any. */
  2179.     if (pReqSpec->reqlist.len != 0)
  2180.         {
  2181.         dhcpcMsgOut.dhcp->options [offopt++] = _DHCP_REQ_LIST_TAG;
  2182.         dhcpcMsgOut.dhcp->options [offopt++] = pReqSpec->reqlist.len;
  2183.         bcopy (pReqSpec->reqlist.list, &dhcpcMsgOut.dhcp->options [offopt],
  2184.                pReqSpec->reqlist.len);
  2185.         offopt += pReqSpec->reqlist.len;
  2186.         }
  2187.     /* Insert all other entries from custom options field, if any. */
  2188.     if (pReqSpec->pOptions != NULL)
  2189.         {
  2190.         bcopy (pReqSpec->pOptions, &dhcpcMsgOut.dhcp->options [offopt],
  2191.                pReqSpec->optlen);
  2192.         offopt += pReqSpec->optlen;
  2193.         }
  2194.     dhcpcMsgOut.dhcp->options[offopt] = _DHCP_END_TAG;
  2195.     msgsize = (DFLTDHCPLEN - DFLTOPTLEN) + offopt + 1;
  2196.     if (pLeaseData->oldFlag)
  2197.         {
  2198.         /*
  2199.          * This flag indicates that the client did not receive a response
  2200.          * to the initial set of discover messages but did receive one
  2201.          * using the older message format. The (older) responding server
  2202.          * ignores messages less than the minimum length obtained with a
  2203.          * fixed options field, so pad the message to reach that length.
  2204.          */
  2205.         if (msgsize < DFLTDHCPLEN)
  2206.             msgsize = DFLTDHCPLEN;
  2207.         }
  2208.     if (type == RENEWING)    /* RENEWING is unicast with the normal socket */
  2209.         return (msgsize);
  2210.     /* make udp part */
  2211.     /* fill udp header */
  2212.     dhcpcMsgOut.udp->uh_sport = dhcpc_port;
  2213.     dhcpcMsgOut.udp->uh_dport = dhcps_port;
  2214.     dhcpcMsgOut.udp->uh_ulen = htons (msgsize + UDPHL);
  2215.     /* fill pseudo udp header */
  2216.     spudph.zero = 0;
  2217.     spudph.prto = IPPROTO_UDP;
  2218.     spudph.ulen = dhcpcMsgOut.udp->uh_ulen;
  2219.     /* make ip part */
  2220.     /* fill ip header */
  2221. #if BSD<44
  2222.     dhcpcMsgOut.ip->ip_v_hl = 0;
  2223.     dhcpcMsgOut.ip->ip_v_hl = IPVERSION << 4;
  2224.     dhcpcMsgOut.ip->ip_v_hl |= IPHL >> 2;
  2225. #else
  2226.     dhcpcMsgOut.ip->ip_v = IPVERSION;
  2227.     dhcpcMsgOut.ip->ip_hl = IPHL >> 2;
  2228. #endif
  2229.     dhcpcMsgOut.ip->ip_tos = 0;
  2230.     dhcpcMsgOut.ip->ip_len = htons (msgsize + UDPHL + IPHL);
  2231.     tmpul = generate_xid (&pLeaseData->ifData);
  2232.     tmpul += (tmpul >> 16);
  2233.     dhcpcMsgOut.ip->ip_id = (u_short) (~tmpul);
  2234.     dhcpcMsgOut.ip->ip_off = htons (IP_DF);                        /* XXX */
  2235.     dhcpcMsgOut.ip->ip_ttl = 0x20;                                 /* XXX */
  2236.     dhcpcMsgOut.ip->ip_p = IPPROTO_UDP;
  2237.     msgsize += UDPHL + IPHL;
  2238.     switch (type) 
  2239.         {
  2240.         case REQUESTING:     /* fall-through */
  2241.         case REBOOTING:      /* fall-through */
  2242.         case VERIFYING:
  2243.             dhcpcMsgOut.ip->ip_src.s_addr = spudph.srcip.s_addr = 0;
  2244.             dhcpcMsgOut.ip->ip_dst.s_addr = spudph.dstip.s_addr = 0xffffffff;
  2245.             break;
  2246.         case REBINDING:
  2247.             dhcpcMsgOut.ip->ip_src.s_addr = spudph.srcip.s_addr = 
  2248.                                             paramp->yiaddr.s_addr;
  2249.             dhcpcMsgOut.ip->ip_dst.s_addr = spudph.dstip.s_addr = 0xffffffff;
  2250.             break;
  2251.         case INFORMING:
  2252.             dhcpcMsgOut.ip->ip_src.s_addr = spudph.srcip.s_addr = 
  2253.                                             pReqSpec->ipaddr.s_addr;
  2254.             dhcpcMsgOut.ip->ip_dst.s_addr = spudph.dstip.s_addr = 0xffffffff;
  2255.             break; 
  2256.         }
  2257.     dhcpcMsgOut.ip->ip_sum = 0;
  2258. #if BSD<44
  2259.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip, 
  2260.                                         (dhcpcMsgOut.ip->ip_v_hl & 0xf) << 2);
  2261. #else
  2262.     dhcpcMsgOut.ip->ip_sum = checksum ( (u_short *)dhcpcMsgOut.ip, 
  2263.                                         dhcpcMsgOut.ip->ip_hl << 2);
  2264. #endif
  2265.     return (msgsize);
  2266.     }
  2267. /*******************************************************************************
  2268. *
  2269. * send_unicast - send a DHCP message via unicast
  2270. *
  2271. * This routine sends a previously constructed DHCP message to the DHCP 
  2272. * server port on the specified IP address. It is used to send a request 
  2273. * for lease renewal or a DHCP release message to the appropriate DHCP server.
  2274. *
  2275. * RETURNS: 0 if message sent, or -1 on error.
  2276. *
  2277. * ERRNO: N/A
  2278. *
  2279. * NOMANUAL
  2280. */
  2281. int send_unicast
  2282.     (
  2283.     struct in_addr *dstip,
  2284.     struct dhcp *sdhcp,
  2285.     int length  /* length of DHCP message */
  2286.     )
  2287.     {
  2288.     struct sockaddr_in dst;
  2289.     struct msghdr msg;
  2290.     struct iovec bufvec[1];
  2291.     int bufsize = length;
  2292.     int status;
  2293.     status = setsockopt (dhcpcDataSock, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize,
  2294.          sizeof (bufsize));
  2295.     if (status < 0) 
  2296.         {
  2297.         printf ("setsockopt error %d (%x).n", status, errno);
  2298.         return (-1);
  2299.         }
  2300.     bzero ( (char *)&dst, sizeof (dst));
  2301.     dst.sin_family = AF_INET;
  2302.     dst.sin_addr.s_addr = dstip->s_addr;
  2303.     dst.sin_port = dhcps_port;
  2304.     bufvec[0].iov_base = (char *)sdhcp;
  2305.     bufvec[0].iov_len = bufsize;
  2306.     bzero ( (char *)&msg, sizeof (msg));
  2307.     msg.msg_name = (caddr_t)&dst;
  2308.     msg.msg_namelen = sizeof (dst);
  2309.     msg.msg_iov = bufvec;
  2310.     msg.msg_iovlen = 1;
  2311.     status = sendmsg (dhcpcDataSock, &msg, 0);
  2312.     if (status < 0)
  2313.         {
  2314.         printf ("sendmsg error %d (%x).n", status, errno);
  2315.         return (-1);
  2316.         }
  2317.     return(0);
  2318.     }
  2319. /*******************************************************************************
  2320. *
  2321. * handle_ip - process DHCP options containing a single IP address
  2322. *
  2323. * This routine extracts the IP address from the given option body and 
  2324. * copies it to the appropriate field in the parameters structure. It is
  2325. * called by the dhcp_msgtoparam() conversion routine when specified by
  2326. * the handle_param[] global array.
  2327. *
  2328. * RETURNS: 0 if extraction successful, or -1 on error.
  2329. *
  2330. * ERRNO: N/A
  2331. *
  2332. * NOMANUAL
  2333. */
  2334. int handle_ip
  2335.     (
  2336.     char *buf,
  2337.     struct dhcp_param *param
  2338.     )
  2339.     {
  2340.     struct in_addr *addr = NULL;
  2341.     char option;
  2342.     option = *buf;
  2343.     /* Set the appropriate pointers to access allocated memory. */
  2344.     if (option == _DHCP_SERVER_ID_TAG) 
  2345.         {
  2346.         addr = &param->server_id;
  2347.         } 
  2348.     else if (option == _DHCP_ROUTER_SOLICIT_TAG)
  2349.         addr = &param->router_solicit;
  2350.     else 
  2351.         {
  2352.         addr = (struct in_addr *)calloc (1, sizeof (struct in_addr));
  2353.         if (addr == NULL) 
  2354.             return (-1);
  2355.         switch (option) 
  2356.             {
  2357.             case _DHCP_SUBNET_MASK_TAG:
  2358.                 if (param->subnet_mask != NULL) 
  2359.                     free (param->subnet_mask);
  2360.                 param->subnet_mask = addr;
  2361.                 break;
  2362.             case _DHCP_SWAP_SERVER_TAG:
  2363.                 if (param->swap_server != NULL) 
  2364.                     free (param->swap_server);
  2365.                 param->swap_server = addr;
  2366.                 break;
  2367.             case _DHCP_BRDCAST_ADDR_TAG:
  2368.                 if (param->brdcast_addr != NULL) 
  2369.                     free (param->brdcast_addr);
  2370.                 param->brdcast_addr = addr;
  2371.                 break;
  2372.             default:
  2373.                 free (addr);
  2374.                 return (EINVAL);
  2375.             }
  2376.         }
  2377.     bcopy (OPTBODY (buf), (char *)addr, DHCPOPTLEN (buf));
  2378.     return (0);
  2379.     }
  2380. /*******************************************************************************
  2381. *
  2382. * handle_num - process DHCP options containing a single numeric value
  2383. *
  2384. * This routine extracts the numeric value from the given option body and 
  2385. * stores it in the appropriate field in the parameters structure. It is
  2386. * called by the dhcp_msgtoparam() conversion routine when specified by
  2387. * the handle_param[] global array.
  2388. *
  2389. * RETURNS: 0 if extraction successful, or -1 on error.
  2390. *
  2391. * ERRNO: N/A
  2392. *
  2393. * NOMANUAL
  2394. */
  2395. int handle_num
  2396.     (
  2397.     char *buf,
  2398.     struct dhcp_param *param
  2399.     )
  2400.     {
  2401.     char   charnum = 0;
  2402.     short  shortnum = 0;
  2403.     long   longnum = 0;
  2404.     switch (DHCPOPTLEN (buf)) 
  2405.         {
  2406.         case 1:
  2407.             charnum = *OPTBODY (buf);
  2408.             break;
  2409.         case 2:
  2410.             shortnum = GETHS (OPTBODY (buf));
  2411.             break;
  2412.         case 4:
  2413.             longnum = GETHL (OPTBODY (buf));
  2414.             break;
  2415.         default:
  2416.             return (-1);
  2417.         }
  2418.     switch (*buf) 
  2419.         {
  2420.         case _DHCP_TIME_OFFSET_TAG:
  2421.             param->time_offset = longnum;
  2422.             break;
  2423.         case _DHCP_BOOTSIZE_TAG:
  2424.             param->bootsize = (unsigned short)shortnum;
  2425.             break;
  2426.         case _DHCP_MAX_DGRAM_SIZE_TAG:
  2427.             param->max_dgram_size = (unsigned short)shortnum;
  2428.             break;
  2429.         case _DHCP_DEFAULT_IP_TTL_TAG:
  2430.             param->default_ip_ttl = (unsigned char)charnum;
  2431.             break;
  2432.         case _DHCP_MTU_AGING_TIMEOUT_TAG:
  2433.             param->mtu_aging_timeout = (unsigned long)longnum;
  2434.             break;
  2435.         case _DHCP_IF_MTU_TAG:
  2436.             param->intf_mtu = (unsigned short)shortnum;
  2437.             break;
  2438.         case _DHCP_ARP_CACHE_TIMEOUT_TAG:
  2439.             param->arp_cache_timeout = (unsigned long)longnum;
  2440.             break;
  2441.         case _DHCP_DEFAULT_TCP_TTL_TAG:
  2442.             param->default_tcp_ttl = (unsigned char)charnum;
  2443.             break;
  2444.         case _DHCP_KEEPALIVE_INTERVAL_TAG:
  2445.             param->keepalive_inter = (unsigned long)longnum;
  2446.             break;
  2447.         case _DHCP_NB_NODETYPE_TAG:
  2448.             param->nb_nodetype = (unsigned)charnum;
  2449.             break;
  2450.         case _DHCP_LEASE_TIME_TAG:
  2451.             param->lease_duration = (unsigned long)longnum;
  2452.             break;
  2453.         case _DHCP_T1_TAG:
  2454.             param->dhcp_t1 = (unsigned long)longnum;
  2455.             break;
  2456.         case _DHCP_T2_TAG:
  2457.             param->dhcp_t2 = (unsigned long)longnum;
  2458.             break;
  2459.         default:
  2460.             return (EINVAL);
  2461.         }
  2462.     return(0);
  2463.     }
  2464. /*******************************************************************************
  2465. *
  2466. * handle_ips - process DHCP options containing multiple IP addresses
  2467. *
  2468. * This routine extracts the IP addresses from the given option body and 
  2469. * copies them to the appropriate field in the parameters structure. It is
  2470. * called by the dhcp_msgtoparam() conversion routine when specified by
  2471. * the handle_param[] global array.
  2472. *
  2473. * RETURNS: 0 if extraction successful, or -1 on error.
  2474. *
  2475. * ERRNO: N/A
  2476. *
  2477. * NOMANUAL
  2478. */
  2479. int handle_ips
  2480.     (
  2481.     char *buf,
  2482.     struct dhcp_param *param
  2483.     )
  2484.     {
  2485.     struct in_addr  *addr = NULL;
  2486.     struct in_addrs *addrs = NULL;
  2487.     unsigned char  num = 0;
  2488.     num = DHCPOPTLEN (buf) / 4;
  2489.     addr = (struct in_addr *)calloc ( (int)num, sizeof (struct in_addr));
  2490.     if (addr  == NULL)
  2491.         return(-1);
  2492.     addrs = (struct in_addrs *)calloc (1, sizeof(struct in_addrs));
  2493.     if (addrs  == NULL) 
  2494.         {
  2495.         free (addr);
  2496.         return (-1);
  2497.         }
  2498.     switch (*buf) 
  2499.         {
  2500.         case _DHCP_ROUTER_TAG:
  2501.             if (param->router != NULL) 
  2502.                 {
  2503.                 if (param->router->addr != NULL) 
  2504.                     free (param->router->addr);
  2505.                 free (param->router);
  2506.                 }
  2507.             param->router = addrs;
  2508.             param->router->num = num;
  2509.             param->router->addr = addr;
  2510.             break;
  2511.         case _DHCP_TIME_SERVER_TAG:
  2512.             if (param->time_server != NULL) 
  2513.                 {
  2514.                 if (param->time_server->addr != NULL) 
  2515.                     free (param->time_server->addr);
  2516.                 free (param->time_server);
  2517.                 }
  2518.             param->time_server = addrs;
  2519.             param->time_server->num = num;
  2520.             param->time_server->addr = addr;
  2521.             break;
  2522.         case _DHCP_NAME_SERVER_TAG:
  2523.             if (param->name_server != NULL) 
  2524.                 {
  2525.                 if (param->name_server->addr != NULL) 
  2526.                     free (param->name_server->addr);
  2527.                 free (param->name_server);
  2528.                 }
  2529.             param->name_server = addrs;
  2530.             param->name_server->num = num;
  2531.             param->name_server->addr = addr;
  2532.             break;
  2533.         case _DHCP_DNS_SERVER_TAG:
  2534.             if (param->dns_server != NULL) 
  2535.                 {
  2536.                 if (param->dns_server->addr != NULL) 
  2537.                     free (param->dns_server->addr);
  2538.                 free (param->dns_server);
  2539.                 }
  2540.             param->dns_server = addrs;
  2541.             param->dns_server->num = num;
  2542.             param->dns_server->addr = addr;
  2543.             break;
  2544.         case _DHCP_LOG_SERVER_TAG:
  2545.             if (param->log_server != NULL) 
  2546.                 {
  2547.                 if (param->log_server->addr != NULL) 
  2548.                     free (param->log_server->addr);
  2549.                 free (param->log_server);
  2550.                 }
  2551.             param->log_server = addrs;
  2552.             param->log_server->num = num;
  2553.             param->log_server->addr = addr;
  2554.             break;
  2555.         case _DHCP_COOKIE_SERVER_TAG:
  2556.             if (param->cookie_server != NULL) 
  2557.                 {
  2558.                 if (param->cookie_server->addr != NULL) 
  2559.                     free (param->cookie_server->addr);
  2560.                 free (param->cookie_server);
  2561.                 }
  2562.             param->cookie_server = addrs;
  2563.             param->cookie_server->num = num;
  2564.             param->cookie_server->addr = addr;
  2565.             break;
  2566.         case _DHCP_LPR_SERVER_TAG:
  2567.             if (param->lpr_server != NULL) 
  2568.                 {
  2569.                 if (param->lpr_server->addr != NULL) 
  2570.                     free (param->lpr_server->addr);
  2571.                 free (param->lpr_server);
  2572.                 }
  2573.             param->lpr_server = addrs;
  2574.             param->lpr_server->num = num;
  2575.             param->lpr_server->addr = addr;
  2576.             break;
  2577.         case _DHCP_IMPRESS_SERVER_TAG:
  2578.             if (param->impress_server != NULL) 
  2579.                 {
  2580.                 if (param->impress_server->addr != NULL) 
  2581.                     free (param->impress_server->addr);
  2582.                 free (param->impress_server);
  2583.                 }
  2584.             param->impress_server = addrs;
  2585.             param->impress_server->num = num;
  2586.             param->impress_server->addr = addr;
  2587.             break;
  2588.         case _DHCP_RLS_SERVER_TAG:
  2589.             if (param->rls_server != NULL) 
  2590.                 {
  2591.                 if (param->rls_server->addr != NULL) 
  2592.                     free (param->rls_server->addr);
  2593.                 free (param->rls_server);
  2594.                 }
  2595.             param->rls_server = addrs;
  2596.             param->rls_server->num = num;
  2597.             param->rls_server->addr = addr;
  2598.             break;
  2599.         case _DHCP_NIS_SERVER_TAG:
  2600.             if (param->nis_server != NULL) 
  2601.                 {
  2602.                 if (param->nis_server->addr != NULL) 
  2603.                     free (param->nis_server->addr);
  2604.                 free (param->nis_server);
  2605.                 }
  2606.             param->nis_server = addrs;
  2607.             param->nis_server->num = num;
  2608.             param->nis_server->addr = addr;
  2609.             break;
  2610.         case _DHCP_NTP_SERVER_TAG:
  2611.             if (param->ntp_server != NULL)
  2612.                 {
  2613.                 if (param->ntp_server->addr != NULL) 
  2614.                     free (param->ntp_server->addr);
  2615.                 free (param->ntp_server);
  2616.                 }
  2617.             param->ntp_server = addrs;
  2618.             param->ntp_server->num = num;
  2619.             param->ntp_server->addr = addr;
  2620.             break;
  2621.         case _DHCP_NBN_SERVER_TAG:
  2622.             if (param->nbn_server != NULL) 
  2623.                 {
  2624.                 if (param->nbn_server->addr != NULL) 
  2625.                     free (param->nbn_server->addr);
  2626.                 free (param->nbn_server);
  2627.                 }
  2628.             param->nbn_server = addrs;
  2629.             param->nbn_server->num = num;
  2630.             param->nbn_server->addr = addr;
  2631.             break;
  2632.         case _DHCP_NBDD_SERVER_TAG:
  2633.             if (param->nbdd_server != NULL) 
  2634.                 {
  2635.                 if (param->nbdd_server->addr != NULL) 
  2636.                     free (param->nbdd_server->addr);
  2637.                 free (param->nbdd_server);
  2638.                 }
  2639.             param->nbdd_server = addrs;
  2640.             param->nbdd_server->num = num;
  2641.             param->nbdd_server->addr = addr;
  2642.             break;
  2643.         case _DHCP_XFONT_SERVER_TAG:
  2644.             if (param->xfont_server != NULL)
  2645.                 {
  2646.                 if (param->xfont_server->addr != NULL) 
  2647.                     free (param->xfont_server->addr);
  2648.                 free (param->xfont_server);
  2649.                 }
  2650.             param->xfont_server = addrs;
  2651.             param->xfont_server->num = num;
  2652.             param->xfont_server->addr = addr;
  2653.             break;
  2654.         case _DHCP_XDISPLAY_MANAGER_TAG:
  2655.             if (param->xdisplay_manager != NULL) 
  2656.                 {
  2657.                 if (param->xdisplay_manager->addr != NULL) 
  2658.                     free (param->xdisplay_manager->addr);
  2659.                 free (param->xdisplay_manager);
  2660.                 }
  2661.             param->xdisplay_manager = addrs;
  2662.             param->xdisplay_manager->num = num;
  2663.             param->xdisplay_manager->addr = addr;
  2664.             break;
  2665.         case _DHCP_NISP_SERVER_TAG:
  2666.             if (param->nisp_server != NULL) 
  2667.                 {
  2668.                 if (param->nisp_server->addr != NULL) 
  2669.                     free (param->nisp_server->addr);
  2670.                 free (param->nisp_server);
  2671.                 }
  2672.             param->nisp_server = addrs;
  2673.             param->nisp_server->num = num;
  2674.             param->nisp_server->addr = addr;
  2675.             break;
  2676.         case _DHCP_MOBILEIP_HA_TAG:
  2677.             if (param->mobileip_ha != NULL) 
  2678.                 {
  2679.                 if (param->mobileip_ha->addr != NULL) 
  2680.                     free (param->mobileip_ha->addr);
  2681.                 free (param->mobileip_ha);
  2682.                 }
  2683.             param->mobileip_ha = addrs;
  2684.             param->mobileip_ha->num = num;
  2685.             param->mobileip_ha->addr = addr;
  2686.             break;
  2687.         case _DHCP_SMTP_SERVER_TAG:
  2688.             if (param->smtp_server != NULL) 
  2689.                 {
  2690.                 if (param->smtp_server->addr != NULL) 
  2691.                     free (param->smtp_server->addr);
  2692.                 free (param->smtp_server);
  2693.                 }
  2694.             param->smtp_server = addrs;
  2695.             param->smtp_server->num = num;
  2696.             param->smtp_server->addr = addr;
  2697.             break;
  2698.         case _DHCP_POP3_SERVER_TAG:
  2699.             if (param->pop3_server != NULL) 
  2700.                 {
  2701.                 if (param->pop3_server->addr != NULL) 
  2702.                     free (param->pop3_server->addr);
  2703.                 free (param->pop3_server);
  2704.                 }
  2705.             param->pop3_server = addrs;
  2706.             param->pop3_server->num = num;
  2707.             param->pop3_server->addr = addr;
  2708.             break;
  2709.         case _DHCP_NNTP_SERVER_TAG:
  2710.             if (param->nntp_server != NULL) 
  2711.                 {
  2712.                 if (param->nntp_server->addr != NULL) 
  2713.                     free (param->nntp_server->addr);
  2714.                 free (param->nntp_server);
  2715.                 }
  2716.             param->nntp_server = addrs;
  2717.             param->nntp_server->num = num;
  2718.             param->nntp_server->addr = addr;
  2719.             break;
  2720.         case _DHCP_DFLT_WWW_SERVER_TAG:
  2721.             if (param->dflt_www_server != NULL) 
  2722.                 {
  2723.                 if (param->dflt_www_server->addr != NULL) 
  2724.                     free (param->dflt_www_server->addr);
  2725.                 free (param->dflt_www_server);
  2726.                 }
  2727.             param->dflt_www_server = addrs;
  2728.             param->dflt_www_server->num = num;
  2729.             param->dflt_www_server->addr = addr;
  2730.             break;
  2731.         case _DHCP_DFLT_FINGER_SERVER_TAG:
  2732.             if (param->dflt_finger_server != NULL) 
  2733.                 {
  2734.                 if (param->dflt_finger_server->addr != NULL)
  2735.             free (param->dflt_finger_server->addr);
  2736.                 free (param->dflt_finger_server);
  2737.                 }
  2738.             param->dflt_finger_server = addrs;
  2739.             param->dflt_finger_server->num = num;
  2740.             param->dflt_finger_server->addr = addr;
  2741.             break;
  2742.         case _DHCP_DFLT_IRC_SERVER_TAG:
  2743.             if (param->dflt_irc_server != NULL) 
  2744.                 {
  2745.                 if (param->dflt_irc_server->addr != NULL) 
  2746.                     free (param->dflt_irc_server->addr);
  2747.                 free (param->dflt_irc_server);
  2748.                 }
  2749.             param->dflt_irc_server = addrs;
  2750.             param->dflt_irc_server->num = num;
  2751.             param->dflt_irc_server->addr = addr;
  2752.             break;
  2753.         case _DHCP_STREETTALK_SERVER_TAG:
  2754.             if (param->streettalk_server != NULL) 
  2755.                 {
  2756.                 if (param->streettalk_server->addr != NULL) 
  2757.                     free (param->streettalk_server->addr);
  2758.                 free (param->streettalk_server);
  2759.                 }
  2760.             param->streettalk_server = addrs;
  2761.             param->streettalk_server->num = num;
  2762.             param->streettalk_server->addr = addr;
  2763.             break;
  2764.         case _DHCP_STDA_SERVER_TAG:
  2765.             if (param->stda_server != NULL) 
  2766.                 {
  2767.                 if (param->stda_server->addr != NULL) 
  2768.                     free (param->stda_server->addr);
  2769.                 free (param->stda_server);
  2770.                 }
  2771.             param->stda_server = addrs;
  2772.             param->stda_server->num = num;
  2773.             param->stda_server->addr = addr;
  2774.             break;
  2775.         default:
  2776.             free (addr);
  2777.             free (addrs);
  2778.             return (EINVAL);
  2779.         } 
  2780.     bcopy (OPTBODY (buf), (char *)addr, DHCPOPTLEN (buf));
  2781.     return (0);
  2782.     }
  2783. /*******************************************************************************
  2784. *
  2785. * handle_str - process DHCP options containing NVT ASCII strings
  2786. *
  2787. * This routine extracts the NVT ASCII string from the given option body and 
  2788. * copies it to the appropriate field in the parameters structure. It is
  2789. * called by the dhcp_msgtoparam() conversion routine when specified by
  2790. * the handle_param[] global array.
  2791. *
  2792. * RETURNS: 0 if extraction successful, or -1 on error.
  2793. *
  2794. * ERRNO: N/A
  2795. *
  2796. * NOMANUAL
  2797. */
  2798. int handle_str
  2799.     (
  2800.     char *buf,
  2801.     struct dhcp_param *param
  2802.     )
  2803.     {
  2804.     char *str = NULL;
  2805.     str = calloc (1, (DHCPOPTLEN (buf) + 1));  /* +1 for null terminator. */
  2806.     if (str == NULL)
  2807.         return (-1);
  2808.     switch (*buf) 
  2809.         {
  2810.         case _DHCP_HOSTNAME_TAG:
  2811.             if (param->hostname != NULL) 
  2812.                 free (param->hostname);
  2813.             param->hostname = str;
  2814.             break;
  2815.         case _DHCP_MERIT_DUMP_TAG:
  2816.             if (param->merit_dump != NULL) 
  2817.                 free (param->merit_dump);
  2818.             param->merit_dump = str;
  2819.             break;
  2820.         case _DHCP_DNS_DOMAIN_TAG:
  2821.             if (param->dns_domain != NULL) 
  2822.                 free (param->dns_domain);
  2823.             param->dns_domain = str;
  2824.             break;
  2825.         case _DHCP_ROOT_PATH_TAG:
  2826.             if (param->root_path != NULL) 
  2827.                 free (param->root_path);
  2828.             param->root_path = str;
  2829.             break;
  2830.         case _DHCP_EXTENSIONS_PATH_TAG:
  2831.             if (param->extensions_path != NULL)
  2832.                 free (param->extensions_path);
  2833.             param->extensions_path = str;
  2834.             break;
  2835.         case _DHCP_NIS_DOMAIN_TAG:
  2836.             if (param->nis_domain != NULL) 
  2837.                 free (param->nis_domain);
  2838.             param->nis_domain = str;
  2839.             break;
  2840.         case _DHCP_NB_SCOPE_TAG:
  2841.             if (param->nb_scope != NULL) 
  2842.                 free (param->nb_scope);
  2843.             param->nb_scope = str;
  2844.             break;
  2845.         case _DHCP_ERRMSG_TAG:
  2846.             if (param->errmsg != NULL) 
  2847.                 free (param->errmsg);
  2848.             param->errmsg = str;
  2849.             break;
  2850.         case _DHCP_NISP_DOMAIN_TAG:
  2851.             if (param->nisp_domain != NULL) 
  2852.                 free (param->nisp_domain);
  2853.             param->nisp_domain = str;
  2854.             break;
  2855.         case _DHCP_TFTP_SERVERNAME_TAG:
  2856.             if (param->temp_sname != NULL) 
  2857.                 free (param->temp_sname);
  2858.             param->temp_sname = str;
  2859.             break;
  2860.         case _DHCP_BOOTFILE_TAG:
  2861.             if (param->temp_file != NULL) 
  2862.                 free (param->temp_file);
  2863.             param->temp_file = str;
  2864.             break; 
  2865.         default:
  2866.             free (str);
  2867.             return (EINVAL);
  2868.         }
  2869.     bcopy (OPTBODY (buf), str, DHCPOPTLEN (buf));
  2870.     str [DHCPOPTLEN (buf)] = '';
  2871.     return (0);
  2872.     }
  2873. /*******************************************************************************
  2874. *
  2875. * handle_bool - process DHCP options containing boolean values
  2876. *
  2877. * This routine extracts the boolean value from the given option body and 
  2878. * stores it in the appropriate field in the parameters structure. It is
  2879. * called by the dhcp_msgtoparam() conversion routine when specified by
  2880. * the handle_param[] global array.
  2881. *
  2882. * RETURNS: 0 if extraction successful, or -1 on error.
  2883. *
  2884. * ERRNO: N/A
  2885. *
  2886. * NOMANUAL
  2887. */
  2888. int handle_bool
  2889.     (
  2890.     char *buf,
  2891.     struct dhcp_param *param
  2892.     )
  2893.     {
  2894.     switch (*buf) 
  2895.         {
  2896.         case _DHCP_IP_FORWARD_TAG:
  2897.             param->ip_forward = *OPTBODY (buf);
  2898.             break;
  2899.         case _DHCP_NONLOCAL_SRCROUTE_TAG:
  2900.             param->nonlocal_srcroute = *OPTBODY (buf);
  2901.             break;
  2902.         case _DHCP_ALL_SUBNET_LOCAL_TAG:
  2903.             param->all_subnet_local = *OPTBODY (buf);
  2904.             break;
  2905.         case _DHCP_MASK_DISCOVER_TAG:
  2906.             param->mask_discover = *OPTBODY (buf);
  2907.             break;
  2908.         case _DHCP_MASK_SUPPLIER_TAG:
  2909.             param->mask_supplier = *OPTBODY (buf);
  2910.             break;
  2911.         case _DHCP_ROUTER_DISCOVER_TAG:
  2912.             param->router_discover = *OPTBODY (buf);
  2913.             break;
  2914.         case _DHCP_TRAILER_TAG:
  2915.             param->trailer = *OPTBODY (buf);
  2916.             break;
  2917.         case _DHCP_ETHER_ENCAP_TAG:
  2918.             param->ether_encap = *OPTBODY (buf);
  2919.             break;
  2920.         case _DHCP_KEEPALIVE_GARBAGE_TAG:
  2921.             param->keepalive_garba = *OPTBODY (buf);
  2922.             break;
  2923.         default:
  2924.             return (EINVAL);
  2925.         }
  2926.     return (0);
  2927.     }
  2928. /*******************************************************************************
  2929. *
  2930. * handle_ippairs - process DHCP options containing multiple IP value pairs
  2931. *
  2932. * This routine extracts the IP pairs from the given option body and 
  2933. * stores them in the appropriate field in the parameters structure. It is
  2934. * called by the dhcp_msgtoparam() conversion routine when specified by
  2935. * the handle_param[] global array.
  2936. *
  2937. * RETURNS: 0 if extraction successful, or -1 on error.
  2938. *
  2939. * ERRNO: N/A
  2940. *
  2941. * NOMANUAL
  2942. */
  2943. int handle_ippairs
  2944.     (
  2945.     char *buf,
  2946.     struct dhcp_param *param
  2947.     )
  2948.     {
  2949.     struct in_addr  *addr = NULL;
  2950.     struct in_addrs *addrs = NULL;
  2951.     unsigned char   num = 0;
  2952.     num = DHCPOPTLEN(buf) / 4;
  2953.     addr = (struct in_addr *)calloc ( (int) num, sizeof (struct in_addr)); 
  2954.     if (addr == NULL)
  2955.         return(-1);
  2956.     addrs = (struct in_addrs *)calloc (1, sizeof (struct in_addrs));
  2957.     if (addrs == NULL)
  2958.         { 
  2959.         free (addr);
  2960.         return (-1);
  2961.         }
  2962.     switch (*buf) 
  2963.         {
  2964.         case _DHCP_POLICY_FILTER_TAG: /* IP address followed by subnet mask. */
  2965.             if (param->policy_filter != NULL) 
  2966.                 {
  2967.                 if (param->policy_filter->addr != NULL) 
  2968.                     free (param->policy_filter->addr);
  2969.                 free (param->policy_filter);
  2970.                 }
  2971.             param->policy_filter = addrs;
  2972.             param->policy_filter->num = num / 2;
  2973.             param->policy_filter->addr = addr;
  2974.             break;
  2975.         case _DHCP_STATIC_ROUTE_TAG:   /* Destination IP followed by router. */
  2976.             if (param->static_route != NULL) 
  2977.                 {
  2978.                 if (param->static_route->addr != NULL) 
  2979.                     free (param->static_route->addr);
  2980.                 free (param->static_route);
  2981.                 }
  2982.             param->static_route = addrs;
  2983.             param->static_route->num = num / 2;
  2984.             param->static_route->addr = addr;
  2985.             break;
  2986.         default:
  2987.             free (addr);
  2988.             free (addrs);
  2989.             return (EINVAL);
  2990.         }
  2991.     bcopy (OPTBODY (buf), (char *)addr, DHCPOPTLEN (buf));
  2992.     return (0);
  2993.     }
  2994. /*******************************************************************************
  2995. *
  2996. * handle_nums - process DHCP options containing multiple numeric values
  2997. *
  2998. * This routine extracts the numbers from the given option body and 
  2999. * stores them in the appropriate field in the parameters structure. It is
  3000. * called by the dhcp_msgtoparam() conversion routine when specified by
  3001. * the handle_param[] global array.
  3002. *
  3003. * RETURNS: 0 if extraction successful, or -1 on error.
  3004. *
  3005. * ERRNO: N/A
  3006. *
  3007. * NOMANUAL
  3008. */
  3009. int handle_nums
  3010.     (
  3011.     char *buf,
  3012.     struct dhcp_param *param
  3013.     )
  3014.     {
  3015.     int i = 0;
  3016.     int max = 0;
  3017.     if (*buf != _DHCP_MTU_PLATEAU_TABLE_TAG) 
  3018.         return (EINVAL);
  3019.     else 
  3020.         {
  3021.         if (param->mtu_plateau_table != NULL) 
  3022.             {
  3023.             if (param->mtu_plateau_table->shortnum != NULL)
  3024.         free (param->mtu_plateau_table->shortnum);
  3025.             free (param->mtu_plateau_table);
  3026.             }
  3027.         param->mtu_plateau_table = 
  3028.                        (struct u_shorts *)calloc(1, sizeof (struct u_shorts));
  3029.         if (param->mtu_plateau_table == NULL) 
  3030.             return(-1);
  3031.         max = param->mtu_plateau_table->num = DHCPOPTLEN (buf) / 2;
  3032.         param->mtu_plateau_table->shortnum =
  3033.                             (u_short *)calloc (max, sizeof (unsigned short));
  3034.         if (param->mtu_plateau_table->shortnum == NULL) 
  3035.             {
  3036.             free (param->mtu_plateau_table);
  3037.             return(-1);
  3038.             }
  3039.         for (i = 0; i < max; i++) 
  3040.             param->mtu_plateau_table->shortnum[i] = GETHS (&buf [i * 2 + 2]);
  3041.         }
  3042.     return (0);
  3043.     }
  3044. /*******************************************************************************
  3045. *
  3046. * handle_list - process the DHCP option containing vendor specific data 
  3047. *
  3048. * This routine extracts the list of vendor-specific information from the 
  3049. * given option body and stores it in the appropriate field in the parameters 
  3050. * structure. It is called by the dhcp_msgtoparam() conversion routine when 
  3051. * specified by the handle_param[] global array.
  3052. *
  3053. * RETURNS: 0 if extraction successful, or -1 on error.
  3054. *
  3055. * ERRNO: N/A
  3056. *
  3057. * NOMANUAL
  3058. */
  3059. int handle_list
  3060.     (
  3061.     char *buf,
  3062.     struct dhcp_param *param
  3063.     )
  3064.     {
  3065.     if (*buf != _DHCP_VENDOR_SPEC_TAG)
  3066.         return (EINVAL);
  3067.    
  3068.     if (param->vendlist != NULL)
  3069.         free (param->vendlist);
  3070.     param->vendlist = calloc (1, sizeof (struct vendor_list));
  3071.     if (param->vendlist == NULL)
  3072.         return (-1);
  3073.     bcopy (OPTBODY (buf), param->vendlist->list, DHCPOPTLEN (buf));
  3074.     param->vendlist->len = DHCPOPTLEN (buf);
  3075.     return (0);
  3076.     }