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

VxWorks

开发平台:

C/C++

  1. /* bootpLib.c - Bootstrap Protocol (BOOTP) client library */
  2. /* Copyright 1984 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01x,07dec01,wap  Use htons() to set ip_len and ip_id fields in IP header,
  8.                  and htonl() to set the XID field in the packet body/BPF filter
  9.                  so that BOOTP works on little-endian targets (SPR #72059)
  10. 01w,15oct01,rae  merge from truestack ver 01z, base 01v
  11. 01v,17mar99,spm  added support for identical unit numbers (SPR #20913)
  12. 01u,04sep98,ham  corrected lack of params for etherInputHookAdd(),SPR#21909
  13. 01t,28aug98,n_s  corrected MAC address comparison in bootpInputHook. spr #20902
  14. 01s,17jul97,dgp  doc: correct unsupported interfaces per SPR 8940
  15. 02c,14dec97,jdi  doc: cleanup.
  16. 02b,10dec97,gnn  making man page fixes
  17. 02a,08dec97,gnn  END code review fixes
  18. 01z,03dec97,spm  corrected parameter description for bootpMsgSend (SPR #9401);
  19.                  minor changes to man pages and code spacing
  20. 01y,03oct97,gnn  removed references to endDriver global.
  21. 01x,25sep97,gnn  SENS beta feedback fixes
  22. 01w,26aug97,spm  fixed bootpParamsGet - gateway not retrieved (SPR #9137)
  23. 01v,12aug97,gnn  changes necessitated by MUX/END update.
  24. 01u,30apr97,jag  man page edit for function bootParamsGet()
  25. 01t,07apr97,spm  changed BOOTP interface to DHCP style: all options supported
  26. 01s,17dec96,gnn  added code to handle the new etherHooks and END stuff.
  27. 01r,08nov96,spm  Updated example of bootpParamsGet() for SPR 7120
  28. 01q,22sep96,spm  Fixed SPR 7120: added support for gateways to bootpParamsGet()
  29. 01p,01feb96,gnn  added the end of vendor data (0xff) to the request packet
  30.  we send
  31. 01o,16jan94,rhp  fix typo in library man page
  32. 01n,17oct94,rhp  remove docn reference to bootpdLib (SPR#2351)
  33. 01n,22sep92,jdi  documentation cleanup.
  34. 01m,14aug92,elh  documentation changes.
  35. 01l,11jun92,elh  modified parameters to bootpParamsGet.
  36. 01k,26may92,rrr  the tree shuffle
  37.   -changed includes to have absolute path from h/
  38. 01j,16apr92,elh  moved routines shared by icmp to icmpLib.
  39. 01i,28feb92,elh  ansified.
  40. 01h,27aug91,elh  rewritten to use standard bootp protocol,
  41.  redesigned to be more modular, rewrote documentation.
  42. 01g,15aug90,dnw  added slot parameter to bootpParamsGet()
  43.    +hjb  fixed bug in bootpForwarder() not setting hw addr in arp ioctl
  44. 01f,12aug90,dnw  changed bootpParamsGet() to check every tick for reply message
  45.                  instead of every 4 seconds, for faster response.
  46.  changed bootpParamsGet() to print '.' every time it broadcasts
  47.                  request.
  48. 01e,12aug90,hjb  major redesign and implementation of the protocol
  49. 01d,07may90,hjb  made bootp IP checksum portable; modifications to the protocol
  50.  for better forwarding service.
  51. 01c,19apr90,hjb  minor fixups bootpRequestSend(), added protocol extension
  52.  to solve the routing problem when bootp forwarder is used.
  53. 01b,11apr90,hjb  de-linted.
  54. 01a,11mar90,hjb  written.
  55. */
  56. /*
  57. DESCRIPTION
  58. This library implements the client side of the Bootstrap Protocol
  59. (BOOTP).  This protocol allows a host to initialize automatically by
  60.  obtaining its IP address, boot file name, and boot host's IP address over
  61. a network. The bootpLibInit() routine links this library into the
  62. VxWorks image. This happens automatically if INCLUDE_BOOTP is defined
  63. at the time the image is built.
  64. CONFIGURATION INTERFACE
  65. When used during boot time, the BOOTP library attempts to retrieve
  66. the required configuration information from a BOOTP server using
  67. the interface described below. If it is successful, the remainder
  68. of the boot process continues as if the information were entered manually.
  69. HIGH-LEVEL INTERFACE
  70. The bootpParamsGet() routine retrieves a set of configuration parameters
  71. according to the client-server interaction described in RFC 951 and
  72. clarified in RFC 1542. The parameter descriptor structure it accepts as
  73. an argument allows the retrieval of any combination of the options described
  74. in RFC 1533 (if supported by the BOOTP server and specified in the database).
  75. During the default system boot process, the routine obtains the boot file, the
  76. Internet address, and the host Internet address.  It also obtains the subnet
  77. mask and the Internet address of an IP router, if available.
  78. LOW-LEVEL INTERFACE
  79. The bootpMsgGet() routine transmits an arbitrary BOOTP request message and
  80. provides direct access to any reply. This interface provides a method for
  81. supporting alternate BOOTP implementations which may not fully comply with
  82. the recommended behavior in RFC 1542. For example, it allows transmission
  83. of BOOTP messages to an arbitrary UDP port and provides access to the
  84. vendor-specific field to handle custom formats which differ from the RFC 1533
  85. implementation. The bootpParamsGet() routine already extracts all options
  86.  which that document defines.
  87. EXAMPLE
  88. The following code fragment demonstrates use of the BOOTP library: 
  89. .CS
  90.     #include "bootpLib.h"
  91.     #define _MAX_BOOTP_RETRIES  1
  92.     struct bootpParams  bootParams;
  93.     struct in_addr  clntAddr;
  94.     struct in_addr  hostAddr;
  95.     char  bootFile [SIZE_FILE];
  96.     int  subnetMask;
  97.     struct in_addr_list routerList;
  98.     struct in_addr  gateway;
  99.     struct ifnet *  pIf;
  100.     /@ Retrieve the interface descriptor of the transmitting device. @/
  101.     pIf = ifunit ("ln0");
  102.     if (pIf == NULL)
  103.         {
  104.         printf ("Device not found.n");
  105.         return (ERROR);
  106.         }
  107.     /@ Setup buffers for information from BOOTP server. @/
  108.     bzero ( (char *)&clntAddr, sizeof (struct in_addr));
  109.     bzero ( (char *)&hostAddr, sizeof (struct in_addr));
  110.     bzero (bootFile, SIZE_FILE);
  111.     subnetMask  = 0;
  112.     bzero ( (char *)&gateway, sizeof (struct in_addr));
  113.     /@ Set all pointers in parameter descriptor to NULL. @/
  114.     bzero ((char *)&bootParams, sizeof (struct bootpParams));
  115.     /@ Set pointers corresponding to desired options. @/
  116.     bootParams.netmask = (struct in_addr *)&subnetMask;
  117.     routerlist.addr = &gateway;
  118.     routerlist.num = 1;
  119.     bootParams.routers = &routerlist;
  120.     /@
  121.      @ Send request and wait for reply, retransmitting as necessary up to
  122.      @ given limit. Copy supplied entries into buffers if reply received.
  123.      @/
  124.     result = bootpParamsGet (pIf, _MAX_BOOTP_RETRIES,
  125.                           &clntAddr, &hostAddr, NULL, bootFile, &bootParams);
  126.     if (result != OK)
  127.         return (ERROR);
  128. .CE
  129. INCLUDE FILES: bootpLib.h
  130. SEE ALSO: RFC 951, RFC 1542, RFC 1533,
  131. INTERNAL
  132. The diagram below defines the structure chart of bootpLib.
  133.                                    
  134.    |             |               
  135.    v             v                
  136. bootpLibInit bootpParamsGet
  137.      / 
  138.     |    |
  139.     v  v      
  140.       bootpMsgGet   bootpParamsFill
  141. */
  142. /* includes */
  143. #include "vxWorks.h"
  144. #include "ioLib.h"
  145. #include "bootpLib.h"
  146. #include "m2Lib.h"      /* M2_blah  */
  147. #include "bpfDrv.h"
  148. #include "vxLib.h"  /* checksum() declaration */
  149. #include "netinet/ip.h"
  150. #include "netinet/udp.h"
  151. #include "netinet/if_ether.h"
  152. #include "stdio.h"  /* sprintf() declaration */
  153. #include "stdlib.h"  /* rand() declaration */
  154. #include "end.h"
  155. #include "muxLib.h"
  156. /* defines */
  157. #define _BOOTP_MAX_DEVNAME  13  /* "/bpf/bootpc0" */
  158. /* locals */
  159. LOCAL int       bootpConvert (int);
  160. LOCAL BOOL  bootpInitialized;
  161. LOCAL struct
  162.     {
  163.     struct ip           ih;             /* IP header            */
  164.     struct udphdr       uh;             /* UDP header           */
  165.     BOOTP_MSG           bp;             /* Bootp message        */
  166.     } bootpMsg;
  167. LOCAL char * pMsgBuffer;  /* Storage for BOOTP replies from BPF. */
  168. LOCAL int bootpBufSize;  /* Size of storage buffer. */
  169.     /* Berkeley Packet Filter instructions for catching BOOTP messages. */
  170. LOCAL struct bpf_insn bootpfilter[] = {
  171.   BPF_STMT(BPF_LD+BPF_TYPE,0),                /* Save lltype in accumulator */
  172.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IP, 0, 22),  /* IP packet? */
  173.   /*
  174.    * The remaining statements use the (new) BPF_HLEN alias to avoid any
  175.    * link-layer dependencies. The expected destination port and transaction
  176.    * ID values are altered when necessary by the BOOTP routines to match the
  177.    * actual settings.
  178.    */
  179.   BPF_STMT(BPF_LD+BPF_H+BPF_ABS+BPF_HLEN, 6),    /* A <- IP FRAGMENT field */
  180.   BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 20, 0),         /* OFFSET == 0 ? */
  181.   BPF_STMT(BPF_LDX+BPF_HLEN, 0),          /* X <- frame data offset */
  182.   BPF_STMT(BPF_LD+BPF_B+BPF_IND, 9),      /* A <- IP_PROTO field */
  183.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_UDP, 0, 17),     /* UDP ? */
  184.   BPF_STMT(BPF_LD+BPF_HLEN, 0),           /* A <- frame data offset */
  185.   BPF_STMT(BPF_LDX+BPF_B+BPF_MSH+BPF_HLEN, 0), /* X <- IPHDR LEN field */
  186.   BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),     /* A <- start of UDP datagram */
  187.   BPF_STMT(BPF_MISC+BPF_TAX, 0),          /* X <- start of UDP datagram */
  188.   BPF_STMT(BPF_LD+BPF_H+BPF_IND, 2),      /* A <- UDP DSTPORT */
  189.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 68, 0, 11), /* check DSTPORT */
  190.   BPF_STMT(BPF_LD+BPF_H+BPF_ABS+BPF_HLEN, 2),  /* A <- IP LEN field */
  191.   BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, BOOTPLEN + UDPHL + IPHL, 0, 9),
  192.                                                  /* Correct IP length? */
  193.   BPF_STMT(BPF_LD+BPF_H+BPF_IND, 4),      /* A <- UDP LEN field */
  194.   BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, BOOTPLEN + UDPHL, 0, 7),
  195.                                                  /* Correct UDP length? */
  196.   BPF_STMT(BPF_LD+BPF_B+BPF_IND, 8),      /* A <- BOOTP op field */
  197.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, BOOTREPLY, 0, 5),
  198.   BPF_STMT(BPF_LD+BPF_W+BPF_IND, 12),      /* A <- BOOTP xid field */
  199.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, -1, 0, 3),   /* -1 replaced with real xid */
  200.   BPF_STMT(BPF_LD+BPF_W+BPF_IND, 244),    /* A <- BOOTP options */
  201.   BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x63825363, 0, 1),
  202.                                                  /* Matches magic cookie? */
  203.   BPF_STMT(BPF_RET+BPF_K+BPF_HLEN, BOOTPLEN + UDPHL + IPHL),
  204.                                            /*
  205.                                             * ignore data beyond expected
  206.                                             * size (some drivers add padding).
  207.                                             */
  208.   BPF_STMT(BPF_RET+BPF_K, 0)          /* unrecognized message: ignore frame */
  209.   };
  210. LOCAL struct bpf_program bootpread = {
  211.     sizeof (bootpfilter) / sizeof (struct bpf_insn),
  212.     bootpfilter
  213.     };
  214. LOCAL u_char magicCookie1048 [4] = VM_RFC1048;
  215. /* 1048 cookie type  */
  216. #define VEOF_RFC1048 {255}
  217. LOCAL u_char endOfVend[1] = VEOF_RFC1048;
  218. LOCAL void bootpParamsFill (struct in_addr *, struct in_addr *, char *,
  219.                             char *, struct bootpParams *, BOOTP_MSG *);
  220. LOCAL u_char * bootpTagFind (u_char *, int, int *);
  221. /*******************************************************************************
  222. *
  223. * bootpLibInit - BOOTP client library initialization
  224. *
  225. * This routine creates and initializes the global data structures used by
  226. * the BOOTP client library to obtain configuration parameters. The <maxSize>
  227. * parameter specifies the largest link level header for all supported devices.
  228. * This value determines the maximum length of the outgoing IP packet containing
  229. * a BOOTP message.
  230. *
  231. * This routine must be called before using any other library routines. The
  232. * routine is called automatically if INCLUDE_BOOTP is defined at the time
  233. * the system is built and uses the BOOTP_MAXSIZE configuration setting
  234. * for the <maxSize> parameter.
  235. *
  236. * RETURNS: OK, or ERROR if initialization fails.
  237. *
  238. * ERRNO: S_bootpLib_MEM_ERROR;
  239. *
  240. */
  241. STATUS bootpLibInit
  242.     (
  243.     int  maxSize  /* largest link-level header, in bytes */
  244.     )
  245.     {
  246.     int bufSize;  /* Size of receive buffer (BOOTP msg + BPF header) */
  247.     if (bootpInitialized)
  248.         return (OK);
  249.     if (bpfDrv () == ERROR)
  250.         {
  251.         return (ERROR);
  252.         }
  253.     bufSize = maxSize + BOOTPLEN + UDPHL + IPHL + sizeof (struct bpf_hdr);
  254.     if (bpfDevCreate ("/bpf/bootpc", 1, bufSize) == ERROR)
  255.         {
  256.         bpfDrvRemove ();
  257.         return (ERROR);
  258.         }
  259.     /* Allocate receive buffer based on maximum message size. */
  260.     pMsgBuffer = memalign (4, bufSize);
  261.     if (pMsgBuffer == NULL)
  262.         {
  263.         bpfDevDelete ("/bpf/bootpc");
  264.         bpfDrvRemove ();
  265.         errno = S_bootpLib_MEM_ERROR;
  266.         return (ERROR);
  267.         }
  268.     bootpBufSize = bufSize;
  269.     bootpInitialized = TRUE;
  270.     return (OK);
  271.     }
  272. /******************************************************************************
  273. *
  274. * bootpParamsGet - retrieve boot parameters using BOOTP
  275. *
  276. * This routine performs a BOOTP message exchange according to the process
  277. * described in RFC 1542, so the server and client UDP ports are always
  278. * equal to the defined values of 67 and 68.
  279. *
  280. * The <pIf> argument indicates the network device which will be used to send
  281. * and receive BOOTP messages. The BOOTP client only supports devices attached
  282. * to the IP protocol with the MUX/END interface. The MTU size must be large
  283. * enough to receive an IP packet of 328 bytes (corresponding to the BOOTP
  284. * message length of 300 bytes). The specified device also must be capable of
  285. * sending broadcast messages, unless this routine sends the request messages
  286. * directly to the IP address of a specific server.
  287. *
  288. * The <maxSends> parameter specifies the total number of requests before
  289. * before this routine stops waiting for a reply. After the final request,
  290. * this routine will wait for the current interval before returning error.
  291. * The timeout interval following each request follows RFC 1542, beginning
  292. * at 4 seconds and doubling until a maximum limit of 64 seconds.
  293. *
  294. * The <pClientAddr> parameter provides optional storage for the assigned
  295. * IP address from the `yiaddr' field of a BOOTP reply. Since this routine
  296. * can execute before the system is capable of accepting unicast datagrams
  297. * or responding to ARP requests for a specific IP address, the corresponding
  298. * `ciaddr' field in the BOOTP request message is equal to zero.
  299. *
  300. * The <pServerAddr> parameter provides optional storage for the IP address
  301. * of the responding server (from the `siaddr' field of a BOOTP reply).
  302. * This routine broadcasts the BOOTP request message unless this buffer
  303. * is available (i.e. not NULL) and contains the explicit IP address of a
  304. * BOOTP server as a non-zero value.
  305. *
  306. * The <pHostName> parameter provides optional storage for the server's
  307. * host name (from the `sname' field of a BOOTP reply). This routine also
  308. * copies any initial string in that buffer into the `sname' field of the
  309. * BOOTP request (which restricts booting to a specified host).
  310. *
  311. * The <pBootFile> parameter provides optional storage for the boot file
  312. * name (from the `file' field of a BOOTP reply). This routine also copies
  313. * any initial string in that buffer into the `file' field of the BOOTP
  314. * request message, which typically supplies a generic name to the server.
  315. *
  316. * The remaining fields in the BOOTP request message use the values which
  317. * RFC 1542 defines. In particular, the `giaddr' field is set to zero and
  318. * the suggested "magic cookie" is always inserted in the (otherwise empty)
  319. * `vend' field.
  320. * The <pBootpParams> argument provides access to any options defined in
  321. * RFC 1533 using the following definition:
  322. *
  323. * .CS
  324. *    struct bootpParams
  325. *        {
  326. *        struct in_addr *            netmask;
  327. *        unsigned short *            timeOffset;
  328. *        struct in_addr_list *       routers;
  329. *        struct in_addr_list *       timeServers;
  330. *        struct in_addr_list *       nameServers;
  331. *        struct in_addr_list *       dnsServers;
  332. *        struct in_addr_list *       logServers;
  333. *        struct in_addr_list *       cookieServers;
  334. *        struct in_addr_list *       lprServers;
  335. *        struct in_addr_list *       impressServers;
  336. *        struct in_addr_list *       rlpServers;
  337. *        char *                      clientName;
  338. *        unsigned short *            filesize;
  339. *        char *                      dumpfile;
  340. *        char *                      domainName;
  341. *        struct in_addr *            swapServer;
  342. *        char *                      rootPath;
  343. *        char *                      extoptPath;
  344. *        unsigned char *             ipForward;
  345. *        unsigned char *             nonlocalSourceRoute;
  346. *        struct in_addr_list *       policyFilter;
  347. *        unsigned short *            maxDgramSize;
  348. *        unsigned char *             ipTTL;
  349. *        unsigned long *             mtuTimeout;
  350. *        struct ushort_list *        mtuTable;
  351. *        unsigned short *            intfaceMTU;
  352. *        unsigned char *             allSubnetsLocal;
  353. *        struct in_addr *            broadcastAddr;
  354. *        unsigned char *             maskDiscover;
  355. *        unsigned char *             maskSupplier;
  356. *        unsigned char *             routerDiscover;
  357. *        struct in_addr *            routerDiscAddr;
  358. *        struct in_addr_list *       staticRoutes;
  359. *        unsigned char *             arpTrailers;
  360. *        unsigned long *             arpTimeout;
  361. *        unsigned char *             etherPacketType;
  362. *        unsigned char *             tcpTTL;
  363. *        unsigned long *             tcpInterval;
  364. *        unsigned char *             tcpGarbage;
  365. *        char *                      nisDomain;
  366. *        struct in_addr_list *       nisServers;
  367. *        struct in_addr_list *       ntpServers;
  368. *        char *                      vendString;
  369. *        struct in_addr_list *       nbnServers;
  370. *        struct in_addr_list *       nbddServers;
  371. *        unsigned char *             nbNodeType;
  372. *        char *                      nbScope;
  373. *        struct in_addr_list *       xFontServers;
  374. *        struct in_addr_list *       xDisplayManagers;
  375. *        char *                      nispDomain;
  376. *        struct in_addr_list *       nispServers;
  377. *        struct in_addr_list *       ipAgents;
  378. *        struct in_addr_list *       smtpServers;
  379. *        struct in_addr_list *       pop3Servers;
  380. *        struct in_addr_list *       nntpServers;
  381. *        struct in_addr_list *       wwwServers;
  382. *        struct in_addr_list *       fingerServers;
  383. *        struct in_addr_list *       ircServers;
  384. *        struct in_addr_list *       stServers;
  385. *        struct in_addr_list *       stdaServers; 
  386. *        };
  387. * .CE
  388. *
  389. * This structure allows the retrieval of any BOOTP option specified in
  390. * RFC 1533. The list of 2-byte (unsigned short) values is defined as:
  391. *
  392. * .CS
  393. *    struct ushort_list
  394. *        {
  395. *        unsigned char       num;
  396. *        unsigned short *    shortlist;
  397. *        };
  398. * .CE
  399. *
  400. * The IP address lists use the following similar definition:
  401. *
  402. * .CS
  403. *    struct in_addr_list
  404. *        {
  405. *        unsigned char       num;
  406. *        struct in_addr *    addrlist;
  407. *        };
  408. * .CE
  409. *
  410. * When these lists are present, the routine stores values retrieved from
  411. * the BOOTP reply in the location indicated by the `shortlist' or `addrlist'
  412. * members.  The amount of space available is indicated by the `num' member.
  413. * When the routine returns, the `num' member indicates the actual number of
  414. * entries retrieved.  In the case of `bootpParams.policyFilter.num' 
  415. * and `bootpParams.staticRoutes.num', the `num' member value should be 
  416. * interpreted as the number of IP address pairs requested and received.
  417. *
  418. * .LP
  419. * The contents of the BOOTP parameter descriptor implicitly selects options
  420. * for retrieval from the BOOTP server.  This routine attempts to retrieve the
  421. * values for any options whose corresponding field pointers are non-NULL
  422. * values.  To obtain these parameters, the BOOTP server must support the
  423. * vendor-specific options described in RFC 1048 (or its successors) and the 
  424. * corresponding parameters must be specified in the BOOTP server database. 
  425. * Where meaningful, the values are returned in host byte order. 
  426. *
  427. * The BOOTP request issued during system startup with this routine attempts
  428. * to retrieve a subnet mask for the boot device, in addition to the host and
  429. * client addresses and the boot file name.
  430. *
  431. * RETURNS: OK, or ERROR if unsuccessful.
  432. *
  433. * SEE ALSO: bootLib, RFC 1048, RFC 1533
  434. */
  435. STATUS bootpParamsGet
  436.     (
  437.     struct ifnet *  pIf,  /* network device used by client */
  438.     u_int  maxSends, /* maximum transmit attempts */
  439.     struct in_addr *  pClientAddr,  /* retrieved client address buffer */
  440.     struct in_addr *  pServerAddr,  /* buffer for server's IP address */
  441.     char *  pHostName,  /* 64 byte (max) host name buffer */
  442.     char *  pBootFile,  /* 128 byte (max) file name buffer */
  443.     struct bootpParams *  pBootpParams  /* parameters descriptor     */
  444.     )
  445.     {
  446.     BOOTP_MSG bootpMessage; /* bootp message */
  447.     struct in_addr ipDest; /* ip dest address  */
  448.     int length;
  449.     int htype;
  450.     int maxSize;  /* Largest BOOTP message available from BPF device. */
  451.     if (!bootpInitialized)
  452.         {
  453.         errno = S_bootpLib_NOT_INITIALIZED;
  454.         return (ERROR);
  455.         }
  456.     if (pIf == NULL)
  457.         {
  458.         errno = S_bootpLib_BAD_DEVICE;
  459.         return (ERROR);
  460.         }
  461.     if (muxDevExists (pIf->if_name, pIf->if_unit) == FALSE)
  462.         {
  463.         errno = S_bootpLib_BAD_DEVICE;
  464.         return (ERROR);
  465.         }
  466.     /* Verify interface data sizes are appropriate for message. */
  467.     if (pIf->if_mtu == 0)
  468.         {
  469.         errno = S_bootpLib_BAD_DEVICE;
  470.         return (ERROR);
  471.         }
  472.     length = pIf->if_mtu;
  473.     if (length < BOOTPLEN + UDPHL + IPHL)
  474.         {
  475.         /*
  476.          * Devices must accept messages equal to an IP datagram
  477.          * of 328 bytes, which corresponds to the fixed-size BOOTP
  478.          * message with the minimum headers.
  479.          */
  480.         errno = S_bootpLib_BAD_DEVICE;
  481.         return (ERROR);
  482.         }
  483.     length = pIf->if_hdrlen + BOOTPLEN + UDPHL + IPHL;
  484.     maxSize = bootpBufSize - sizeof (struct bpf_hdr);
  485.     if (length > maxSize)
  486.         {
  487.         /* Link level header exceeds maximum supported value. */
  488.         errno = S_bootpLib_BAD_DEVICE;
  489.         return (ERROR);
  490.         }
  491.     htype = bootpConvert (pIf->if_type);
  492.     if (htype == ERROR)
  493.         {
  494.         /* Unknown device type. Can't encode with RFC 1700 value. */
  495.         errno = S_bootpLib_BAD_DEVICE;
  496.         return (ERROR);
  497.         }
  498.     /* Fill in BOOTP request message. */
  499.     bzero ((char *) &bootpMessage, sizeof (BOOTP_MSG));
  500.     bootpMessage.bp_op = BOOTREQUEST;
  501.     bootpMessage.bp_htype = htype;
  502.     bootpMessage.bp_hlen = pIf->if_addrlen;
  503.     if (bootpMessage.bp_hlen > SIZE_HLEN)
  504.         bootpMessage.bp_hlen = SIZE_HLEN;
  505.     bcopy ( (char *) ( (struct arpcom *)pIf)->ac_enaddr,
  506.            bootpMessage.bp_chaddr, bootpMessage.bp_hlen);
  507.     /* Check for specific boot host name. */
  508.     if (pHostName != NULL)
  509.         {
  510.         length = strlen (pHostName);
  511.         if (length >= SIZE_SNAME)  /* Leave space for EOS character. */
  512.             length = SIZE_SNAME - 1;
  513.         (void) strncpy ( (char *) bootpMessage.bp_sname, pHostName, length);
  514.         }
  515.     /* Check for partial boot file. */
  516.     if (pBootFile != NULL)
  517.         {
  518.         length = strlen (pBootFile);
  519.         if (length >= SIZE_FILE)  /* Leave space for EOS character. */
  520.             length = SIZE_FILE - 1;
  521.         (void) strncpy ( (char *) bootpMessage.bp_file, pBootFile, length);
  522.         }
  523.     /* Fill in RFC 1048 magic cookie. */
  524.     bcopy ( (char *) magicCookie1048, (char *) bootpMessage.bp_vend,
  525.             sizeof (magicCookie1048));
  526.     bcopy ( (char *) endOfVend, (char *) bootpMessage.bp_vend +
  527.            sizeof(magicCookie1048), sizeof(endOfVend));
  528.     /* Check for specific BOOTP server's IP address, or use broadcast. */
  529.     if (pServerAddr == NULL || pServerAddr->s_addr == 0)
  530.         ipDest.s_addr = INADDR_BROADCAST;
  531.     else
  532.         ipDest.s_addr = pServerAddr->s_addr;
  533.     /* Send BOOTP request and retrieve reply using the reserved ports. */
  534.     if (bootpMsgGet (pIf, &ipDest, _BOOTP_CPORT, _BOOTP_SPORT,
  535.                      &bootpMessage, maxSends) == ERROR)
  536.         return (ERROR);
  537.     /* Fill in any entries requested by user and provided by server. */
  538.     bootpParamsFill (pClientAddr, pServerAddr, pHostName, pBootFile,
  539.                      pBootpParams, &bootpMessage);
  540.     return (OK);
  541.     }
  542. /******************************************************************************
  543. *
  544. * bootpParamsFill - copy requested BOOTP options
  545. *
  546. * This routine fills in the non-NULL fields in the given parameter descriptor
  547. * with the corresponding entries from the received BOOTP message.  It is only
  548. * called internally after bootpMsgGet() completes successfully.
  549. *
  550. * RETURNS: N/A
  551. *
  552. * ERRNO: N/A
  553. *
  554. * NOMANUAL
  555. */
  556. LOCAL void bootpParamsFill
  557.     (
  558.     struct in_addr *  pClientAddr,    /* buffer for client address */
  559.     struct in_addr *    pServerAddr,    /* buffer for server's IP address */
  560.     char *              pHostName,      /* 64 byte (max) host name buffer */
  561.     char *              pBootFile,      /* 128 byte (max) file name buffer */
  562.     struct bootpParams * pBootpParams,  /* parameters descriptor */
  563.     BOOTP_MSG *  pBootpReply  /* reply from BOOTP server */
  564.     )
  565.     {
  566.     int  loop;
  567.     int  limit;
  568.     u_char *  cp;
  569.     int length;
  570.     int number;
  571.     /* Copy entries from message body if requested by user. */
  572.         /* Fill in assigned IP address. */
  573.     if (pClientAddr != NULL)
  574.         *pClientAddr = pBootpReply->bp_yiaddr;
  575.         /* Fill in boot server's IP address. */
  576.     if (pServerAddr != NULL)
  577.         *pServerAddr = pBootpReply->bp_siaddr;
  578.         /* Fill in boot file. */
  579.     if (pBootFile != NULL)
  580.         {
  581.         if (pBootpReply->bp_file [0] == EOS)
  582.             {
  583.             pBootFile[0] = EOS;
  584.             }
  585.         else
  586.             strcpy (pBootFile, (char *)pBootpReply->bp_file);
  587.         }
  588.     
  589.         /* Fill in server name. */
  590.     if (pHostName != NULL)
  591.         {
  592.         if (pBootpReply->bp_sname[0] == EOS)
  593.             pHostName[0] = EOS;
  594.         else
  595.             strcpy (pHostName, pBootpReply->bp_sname);
  596.         }
  597.     /* Fill in optional entries requested by user, if present in reply. */
  598.         /* Retrieve subnet mask. */
  599.     if (pBootpParams->netmask != NULL)
  600.         {
  601.         length = 0;
  602.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_SUBNET_MASK, &length);
  603.         if (cp != NULL)
  604.             bcopy ( (char *) cp, (char *)pBootpParams->netmask, length);
  605.         else
  606.             bzero ( (char *)pBootpParams->netmask, sizeof (struct in_addr));
  607.         }
  608.         /* Retrieve time offset. */
  609.     if (pBootpParams->timeOffset != NULL)
  610.         {
  611.         length = 0;
  612.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_TIME_OFFSET, &length);
  613.         if (cp != NULL)
  614.             *pBootpParams->timeOffset = ntohs (*(unsigned short *)cp);
  615.         else
  616.             *pBootpParams->timeOffset = 0;
  617.         }
  618.         /* Retrieve IP addresses of IP routers, up to number requested. */
  619.     if (pBootpParams->routers != NULL && 
  620.         pBootpParams->routers->addrlist != NULL)
  621.         {
  622.         length = 0;
  623.         limit = 0;
  624.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_GATEWAY, &length);
  625.         if (cp != NULL)
  626.             {
  627.             number = length / sizeof (struct in_addr);
  628.             limit = (pBootpParams->routers->num < number) ?
  629.                      pBootpParams->routers->num : number;
  630.             for (loop = 0; loop < limit; loop++)
  631.                 {
  632.                 bcopy ( (char *)cp, 
  633.                        (char *)&pBootpParams->routers->addrlist[loop], 
  634.                        sizeof (struct in_addr));
  635.                 cp += sizeof (struct in_addr);
  636.                 }
  637.             }
  638.         pBootpParams->routers->num = limit;
  639.         }
  640.         /* Retrieve IP addresses of time servers, up to number requested. */
  641.     if (pBootpParams->timeServers != NULL &&
  642.         pBootpParams->timeServers->addrlist != NULL)
  643.         {
  644.         length = 0;
  645.         limit = 0;
  646.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_TIME_SERVER, &length);
  647.         if (cp != NULL)
  648.             {
  649.             number = length / sizeof (struct in_addr);
  650.             limit = (pBootpParams->timeServers->num < number) ?
  651.                      pBootpParams->timeServers->num : number;
  652.             for (loop = 0; loop < limit; loop++)
  653.                 {
  654.                 bcopy ( (char *)cp,
  655.                        (char *)&pBootpParams->timeServers->addrlist[loop], 
  656.                        sizeof (struct in_addr));
  657.                 cp += sizeof (struct in_addr);
  658.                 }
  659.             }
  660.         pBootpParams->timeServers->num = limit;
  661.         }
  662.         /* Retrieve IP addresses of name servers, up to number requested. */
  663.     if (pBootpParams->nameServers != NULL &&
  664.         pBootpParams->nameServers->addrlist != NULL)
  665.         {
  666.         length = 0;
  667.         limit = 0;
  668.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NAME_SERVER, &length);
  669.         if (cp != NULL)
  670.             {
  671.             number = length / sizeof (struct in_addr);
  672.             limit = (pBootpParams->nameServers->num < number) ?
  673.                      pBootpParams->nameServers->num : number;
  674.             for (loop = 0; loop < limit; loop++)
  675.                 {
  676.                 bcopy ( (char *)cp,
  677.                        (char *)&pBootpParams->nameServers->addrlist[loop], 
  678.                        sizeof (struct in_addr));
  679.                 cp += sizeof (struct in_addr);
  680.                 }
  681.             }
  682.         pBootpParams->nameServers->num = limit;
  683.         }
  684.         /* Retrieve IP addresses of DNS servers, up to number requested. */
  685.     if (pBootpParams->dnsServers != NULL && 
  686.         pBootpParams->dnsServers->addrlist != NULL)
  687.         {
  688.         length = 0;
  689.         limit = 0;
  690.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_DNS_SERVER, &length);
  691.         if (cp != NULL)
  692.             {
  693.             number = length / sizeof (struct in_addr);
  694.             limit = (pBootpParams->dnsServers->num < number) ?
  695.                      pBootpParams->dnsServers->num : number;
  696.             for (loop = 0; loop < limit; loop++)
  697.                 {
  698.                 bcopy ( (char *)cp,
  699.                        (char *)&pBootpParams->dnsServers->addrlist[loop], 
  700.                        sizeof (struct in_addr));
  701.                 cp += sizeof (struct in_addr);
  702.                 }
  703.             }
  704.         pBootpParams->dnsServers->num = limit;
  705.         }
  706.         /* Retrieve IP addresses of log servers, up to number requested. */
  707.     if (pBootpParams->logServers != NULL && 
  708.         pBootpParams->logServers->addrlist != NULL)
  709.         {
  710.         length = 0;
  711.         limit = 0;
  712.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_LOG_SERVER, &length);
  713.         if (cp != NULL)
  714.             {
  715.             number = length / sizeof (struct in_addr);
  716.             limit = (pBootpParams->logServers->num < number) ?
  717.                      pBootpParams->logServers->num : number;
  718.             for (loop = 0; loop < limit; loop++)
  719.                 {
  720.                 bcopy ( (char *)cp,
  721.                        (char *)&pBootpParams->logServers->addrlist[loop], 
  722.                        sizeof (struct in_addr));
  723.                 cp += sizeof (struct in_addr);
  724.                 }
  725.             }
  726.         pBootpParams->logServers->num = limit;
  727.         }
  728.         /* Retrieve IP addresses of cookie servers, up to number requested. */
  729.     if (pBootpParams->cookieServers != NULL && 
  730.         pBootpParams->cookieServers->addrlist != NULL)
  731.         {
  732.         length = 0;
  733.         limit = 0;
  734.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_COOKIE_SERVER, &length);
  735.         if (cp != NULL)
  736.             {
  737.             number = length / sizeof (struct in_addr);
  738.             limit = (pBootpParams->cookieServers->num < number) ?
  739.                      pBootpParams->cookieServers->num : number;
  740.             for (loop = 0; loop < limit; loop++)
  741.                 {
  742.                 bcopy ( (char *)cp,
  743.                        (char *)&pBootpParams->cookieServers->addrlist[loop], 
  744.                        sizeof (struct in_addr));
  745.                 cp += sizeof (struct in_addr);
  746.                 }
  747.             }
  748.         pBootpParams->cookieServers->num = limit;
  749.         }
  750.         /* Retrieve IP addresses of LPR servers, up to number requested. */
  751.     if (pBootpParams->lprServers != NULL && 
  752.         pBootpParams->lprServers->addrlist != NULL)
  753.         {
  754.         length = 0;
  755.         limit = 0;
  756.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_LPR_SERVER, &length);
  757.         if (cp != NULL)
  758.             {
  759.             number = length / sizeof (struct in_addr);
  760.             limit = (pBootpParams->lprServers->num < number) ?
  761.                      pBootpParams->lprServers->num : number;
  762.             for (loop = 0; loop < limit; loop++)
  763.                 {
  764.                 bcopy ( (char *)cp,
  765.                        (char *)&pBootpParams->lprServers->addrlist[loop], 
  766.                        sizeof (struct in_addr));
  767.                 cp += sizeof (struct in_addr);
  768.                 }
  769.             }
  770.         pBootpParams->lprServers->num = limit;
  771.         }
  772.         /* Retrieve IP addresses of Impress servers, up to number requested. */
  773.     if (pBootpParams->impressServers != NULL && 
  774.         pBootpParams->impressServers->addrlist != NULL)
  775.         {
  776.         length = 0;
  777.         limit = 0;
  778.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_IMPRESS_SERVER, &length);
  779.         if (cp != NULL)
  780.             {
  781.             number = length / sizeof (struct in_addr);
  782.             limit = (pBootpParams->impressServers->num < number) ?
  783.                      pBootpParams->impressServers->num : number;
  784.             for (loop = 0; loop < limit; loop++)
  785.                 {
  786.                 bcopy ( (char *)cp,
  787.                        (char *)&pBootpParams->impressServers->addrlist[loop], 
  788.                        sizeof (struct in_addr));
  789.                 cp += sizeof (struct in_addr);
  790.                 }
  791.             }
  792.         pBootpParams->impressServers->num = limit;
  793.         }
  794.         /* Retrieve IP addresses of RLP servers, up to number requested. */
  795.     if (pBootpParams->rlpServers != NULL && 
  796.         pBootpParams->rlpServers->addrlist != NULL)
  797.         {
  798.         length = 0;
  799.         limit = 0;
  800.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_RLP_SERVER, &length);
  801.         if (cp != NULL)
  802.             {
  803.             number = length / sizeof (struct in_addr);
  804.             limit = (pBootpParams->rlpServers->num < number) ?
  805.                      pBootpParams->rlpServers->num : number;
  806.             for (loop = 0; loop < limit; loop++)
  807.                 {
  808.                 bcopy ( (char *)cp,
  809.                        (char *)&pBootpParams->rlpServers->addrlist[loop], 
  810.                        sizeof (struct in_addr));
  811.                 cp += sizeof (struct in_addr);
  812.                 }
  813.             }
  814.         pBootpParams->rlpServers->num = limit;
  815.         }
  816.         /* Retrieve hostname of client. */
  817.     if (pBootpParams->clientName != NULL)
  818.         {
  819.         length = 0;
  820.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_HOSTNAME, &length);
  821.         if (cp != NULL)
  822.             {
  823.             bcopy ( (char *)cp, pBootpParams->clientName, length);
  824.             pBootpParams->clientName [length] = EOS;
  825.             }
  826.         else
  827.             pBootpParams->clientName[0] = EOS;
  828.         }
  829.         /* Retrieve size of boot file. */
  830.     if (pBootpParams->filesize != NULL)
  831.         {
  832.         length = 0;
  833.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_BOOTSIZE, &length);
  834.         if (cp != NULL)
  835.             *pBootpParams->filesize = ntohs (*(unsigned short *)cp);
  836.         else
  837.             *pBootpParams->filesize = 0;
  838.         }
  839.         /* Retrieve name of dump file. */
  840.     if (pBootpParams->dumpfile != NULL)
  841.         {
  842.         length = 0;
  843.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_MERIT_DUMP, &length);
  844.         if (cp != NULL)
  845.             {
  846.             bcopy ( (char *)cp, pBootpParams->dumpfile, length);
  847.             pBootpParams->dumpfile [length] = EOS;
  848.             }
  849.         else
  850.             pBootpParams->dumpfile[0] = EOS;
  851.         }
  852.         /* Retrieve name of DNS domain. */
  853.     if (pBootpParams->domainName != NULL)
  854.         {
  855.         length = 0;
  856.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_DNS_DOMAIN, &length);
  857.         if (cp != NULL)
  858.             {
  859.             bcopy ( (char *)cp, pBootpParams->domainName, length);
  860.             pBootpParams->domainName [length] = EOS;
  861.             }
  862.         else
  863.             pBootpParams->domainName[0] = EOS;
  864.         }
  865.         /* Retrieve IP address of swap server. */
  866.     if (pBootpParams->swapServer != NULL)
  867.         {
  868.         length = 0;
  869.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_SWAP_SERVER, &length);
  870.         if (cp != NULL)
  871.             bcopy ( (char *)cp, (char *)pBootpParams->swapServer, length);
  872.         else
  873.             bzero ( (char *)pBootpParams->swapServer, sizeof (struct in_addr));
  874.         }
  875.         /* Retrieve pathname of root disk. */
  876.     if (pBootpParams->rootPath != NULL)
  877.         {
  878.         length = 0;
  879.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_ROOT_PATH, &length);
  880.         if (cp != NULL)
  881.             {
  882.             bcopy ( (char *)cp, pBootpParams->rootPath, length);
  883.             pBootpParams->rootPath [length] = EOS;
  884.             }
  885.         else
  886.             pBootpParams->rootPath[0] = EOS;
  887.         }
  888.         /* Retrieve pathname of extended options file. */
  889.     if (pBootpParams->extoptPath != NULL)
  890.         {
  891.         length = 0;
  892.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_EXTENSIONS_PATH, &length);
  893.         if (cp != NULL)
  894.             {
  895.             bcopy ( (char *)cp, pBootpParams->extoptPath, length);
  896.             pBootpParams->extoptPath [length] = EOS;
  897.             }
  898.         else
  899.             pBootpParams->extoptPath[0] = EOS;
  900.         }
  901.         /* Retrieve IP forwarding option. */
  902.     if (pBootpParams->ipForward != NULL)
  903.         {
  904.         length = 0;
  905.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_IP_FORWARD, &length);
  906.         if (cp != NULL)
  907.             *pBootpParams->ipForward = *cp;
  908.         else
  909.             *pBootpParams->ipForward = 0;
  910.         }
  911.         /* Retrieve non-local source routing option. */
  912.     if (pBootpParams->nonlocalSourceRoute != NULL)
  913.         {
  914.         length = 0;
  915.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NONLOCAL_SRCROUTE, 
  916.                            &length);
  917.         if (cp != NULL)
  918.             *pBootpParams->nonlocalSourceRoute = *cp;
  919.         else
  920.             *pBootpParams->nonlocalSourceRoute = 0;
  921.         }
  922.         /* Retrieve IP addresses and masks for policy filter option. */
  923.     if (pBootpParams->policyFilter != NULL && 
  924.         pBootpParams->policyFilter->addrlist != NULL)
  925.         {
  926.         length = 0;
  927.         limit = 0;
  928.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_POLICY_FILTER, &length);
  929.         if (cp != NULL)
  930.             {
  931.             /* Find number of pairs to retrieve. */
  932.             number = length / (2 * sizeof (struct in_addr));
  933.             limit = (pBootpParams->policyFilter->num < number) ?
  934.                      pBootpParams->policyFilter->num : number;
  935.             for (loop = 0; loop < limit; loop++)
  936.                 {
  937.                 bcopy ( (char *)cp,
  938.                        (char *)&pBootpParams->policyFilter->addrlist[2 * loop],
  939.                        2 * sizeof (struct in_addr));
  940.                 cp += 2 * sizeof (struct in_addr);
  941.                 }
  942.             }
  943.         pBootpParams->policyFilter->num = limit;
  944.         }
  945.         /* Retrieve size of maximum IP datagram. */
  946.     if (pBootpParams->maxDgramSize != NULL)
  947.         {
  948.         length = 0;
  949.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_MAX_DGRAM_SIZE, &length);
  950.         if (cp != NULL)
  951.             *pBootpParams->maxDgramSize = ntohs (*(unsigned short *)cp);
  952.         else
  953.             *pBootpParams->maxDgramSize = 0;
  954.         }
  955.         /* Retrieve default IP time-to-live value. */
  956.     if (pBootpParams->ipTTL != NULL)
  957.         {
  958.         length = 0;
  959.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_DEFAULT_IP_TTL, &length);
  960.         if (cp != NULL)
  961.             *pBootpParams->ipTTL = *cp;
  962.         else
  963.             *pBootpParams->ipTTL = 0;
  964.         }
  965.         /* Retrieve value for path MTU aging timeout. */
  966.     if (pBootpParams->mtuTimeout != NULL)
  967.         {
  968.         length = 0;
  969.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_MTU_AGING_TIMEOUT, 
  970.                            &length);
  971.         if (cp != NULL)
  972.             *pBootpParams->mtuTimeout = ntohs (*(unsigned long *)cp);
  973.         else
  974.             *pBootpParams->mtuTimeout = 0;
  975.         }
  976.         /* Retrieve table of MTU sizes. */
  977.     if (pBootpParams->mtuTable != NULL && 
  978.         pBootpParams->mtuTable->shortlist != NULL)
  979.         {
  980.         length = 0;
  981.         limit = 0;
  982.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_MTU_PLATEAU_TABLE, 
  983.                            &length);
  984.         if (cp != NULL)
  985.             {
  986.             number = length / sizeof (unsigned short);
  987.             limit = (pBootpParams->mtuTable->num < number) ?
  988.                      pBootpParams->mtuTable->num : number;
  989.             for (loop = 0; loop < limit; loop++)
  990.                 {
  991.                 pBootpParams->mtuTable->shortlist [loop] = 
  992.                     ntohs (*(unsigned short *)cp);
  993.                 cp += sizeof (unsigned short);
  994.                 }
  995.             }
  996.         pBootpParams->mtuTable->num = limit;
  997.         }
  998.         /* Retrieve interface MTU. */
  999.     if (pBootpParams->intfaceMTU != NULL)
  1000.         {
  1001.         length = 0;
  1002.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_IF_MTU, &length);
  1003.         if (cp != NULL)
  1004.             *pBootpParams->intfaceMTU = ntohs (*(unsigned short *)cp);
  1005.         else
  1006.             *pBootpParams->intfaceMTU = 0;
  1007.         }
  1008.         /* Retrieve all subnets local option. */
  1009.     if (pBootpParams->allSubnetsLocal != NULL)
  1010.         {
  1011.         length = 0;
  1012.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_ALL_SUBNET_LOCAL, 
  1013.                            &length);
  1014.         if (cp != NULL)
  1015.             *pBootpParams->allSubnetsLocal = *cp;
  1016.         else
  1017.             *pBootpParams->allSubnetsLocal = 0;
  1018.         }
  1019.         /* Retrieve broadcast IP address. */
  1020.     if (pBootpParams->broadcastAddr != NULL)
  1021.         {
  1022.         length = 0;
  1023.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_BRDCAST_ADDR, &length);
  1024.         if (cp != NULL)
  1025.             bcopy ( (char *) cp, (char *)pBootpParams->broadcastAddr, length);
  1026.         else
  1027.             bzero ( (char *)pBootpParams->broadcastAddr, 
  1028.                     sizeof (struct in_addr));
  1029.         }
  1030.         /* Retrieve mask discovery option. */
  1031.     if (pBootpParams->maskDiscover != NULL)
  1032.         {
  1033.         length = 0;
  1034.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_MASK_DISCOVER, &length);
  1035.         if (cp != NULL)
  1036.             *pBootpParams->maskDiscover = *cp;
  1037.         else
  1038.             *pBootpParams->maskDiscover = 0;
  1039.         }
  1040.         /* Retrieve mask supplier option. */
  1041.     if (pBootpParams->maskSupplier != NULL)
  1042.         {
  1043.         length = 0;
  1044.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_MASK_SUPPLIER, &length);
  1045.         if (cp != NULL)
  1046.             *pBootpParams->maskSupplier = *cp;
  1047.         else
  1048.             *pBootpParams->maskSupplier = 0;
  1049.         }
  1050.         /* Retrieve router discovery option. */
  1051.     if (pBootpParams->routerDiscover != NULL)
  1052.         {
  1053.         length = 0;
  1054.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_ROUTER_DISCOVER, &length);
  1055.         if (cp != NULL)
  1056.             *pBootpParams->routerDiscover = *cp;
  1057.         else
  1058.             *pBootpParams->routerDiscover = 0;
  1059.         }
  1060.         /* Retrieve IP address for router solicitation. */
  1061.     if (pBootpParams->routerDiscAddr != NULL)
  1062.         {
  1063.         length = 0;
  1064.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_ROUTER_SOLICIT, &length);
  1065.         if (cp != NULL)
  1066.             bcopy ( (char *) cp, (char *)pBootpParams->routerDiscAddr, length);
  1067.         else
  1068.             bzero ( (char *)pBootpParams->routerDiscAddr, 
  1069.                    sizeof (struct in_addr));
  1070.         }
  1071.         /* Retrieve static routing table. */
  1072.     if (pBootpParams->staticRoutes != NULL && 
  1073.         pBootpParams->staticRoutes->addrlist != NULL)
  1074.         {
  1075.         length = 0;
  1076.         limit = 0;
  1077.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_STATIC_ROUTE, &length);
  1078.         if (cp != NULL)
  1079.             {
  1080.             /* Find number of pairs to retrieve. */
  1081.             number = length / (2 * sizeof (struct in_addr));
  1082.             limit = (pBootpParams->staticRoutes->num < number) ?
  1083.                      pBootpParams->staticRoutes->num : number;
  1084.             for (loop = 0; loop < limit; loop++)
  1085.                 {
  1086.                 bcopy ( (char *)cp,
  1087.                        (char *)&pBootpParams->staticRoutes->addrlist[2 * loop],
  1088.                        2 * sizeof (struct in_addr));
  1089.                 cp += 2 * sizeof (struct in_addr);
  1090.                 }
  1091.             }
  1092.         pBootpParams->staticRoutes->num = limit;
  1093.         }
  1094.         /* Retrieve ARP trailer encapsulation option. */
  1095.     if (pBootpParams->arpTrailers != NULL)
  1096.         {
  1097.         length = 0;
  1098.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_TRAILER, &length);
  1099.         if (cp != NULL)
  1100.             *pBootpParams->arpTrailers = *cp;
  1101.         else
  1102.             *pBootpParams->arpTrailers = 0;
  1103.         }
  1104.         /* Retrieve value for ARP cache timeout. */
  1105.     if (pBootpParams->arpTimeout != NULL)
  1106.         {
  1107.         length = 0;
  1108.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_ARP_CACHE_TIMEOUT, 
  1109.                            &length);
  1110.         if (cp != NULL)
  1111.             *pBootpParams->arpTimeout = ntohs (*(unsigned long *)cp);
  1112.         else
  1113.             *pBootpParams->arpTimeout = 0;
  1114.         }
  1115.         /* Retrieve Ethernet encapsulation option. */
  1116.     if (pBootpParams->etherPacketType != NULL)
  1117.         {
  1118.         length = 0;
  1119.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_ETHER_ENCAP, &length);
  1120.         if (cp != NULL)
  1121.             *pBootpParams->etherPacketType = *cp;
  1122.         else
  1123.             *pBootpParams->etherPacketType = 0;
  1124.         }
  1125.         /* Retrieve default TCP time-to-live value. */
  1126.     if (pBootpParams->tcpTTL != NULL)
  1127.         {
  1128.         length = 0;
  1129.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_DEFAULT_TCP_TTL, &length);
  1130.         if (cp != NULL)
  1131.             *pBootpParams->tcpTTL = *cp;
  1132.         else
  1133.             *pBootpParams->tcpTTL = 0;
  1134.         }
  1135.         /* Retrieve value for TCP keepalive interval. */
  1136.     if (pBootpParams->tcpInterval != NULL)
  1137.         {
  1138.         length = 0;
  1139.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_KEEPALIVE_INTER, &length);
  1140.         if (cp != NULL)
  1141.             *pBootpParams->tcpInterval = ntohs (*(unsigned long *)cp);
  1142.         else
  1143.             *pBootpParams->tcpInterval = 0;
  1144.         }
  1145.         /* Retrieve value for TCP keepalive garbage option. */
  1146.     if (pBootpParams->tcpGarbage != NULL)
  1147.         {
  1148.         length = 0;
  1149.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_KEEPALIVE_GARBA, &length);
  1150.         if (cp != NULL)
  1151.             *pBootpParams->tcpGarbage = *cp;
  1152.         else
  1153.             *pBootpParams->tcpGarbage = 0;
  1154.         }
  1155.         /* Retrieve NIS domain name. */
  1156.     if (pBootpParams->nisDomain != NULL)
  1157.         {
  1158.         length = 0;
  1159.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NIS_DOMAIN, &length);
  1160.         if (cp != NULL)
  1161.             {
  1162.             bcopy ( (char *)cp, pBootpParams->nisDomain, length);
  1163.             pBootpParams->nisDomain [length] = EOS;
  1164.             }
  1165.         else
  1166.             pBootpParams->nisDomain[0] = EOS;
  1167.         }
  1168.         /* Retrieve IP addresses of NIS servers, up to number requested. */
  1169.     if (pBootpParams->nisServers != NULL && 
  1170.         pBootpParams->nisServers->addrlist != NULL)
  1171.         {
  1172.         length = 0;
  1173.         limit = 0;
  1174.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NIS_SERVER, &length);
  1175.         if (cp != NULL)
  1176.             {
  1177.             number = length / sizeof (struct in_addr);
  1178.             limit = (pBootpParams->nisServers->num < number) ?
  1179.                      pBootpParams->nisServers->num : number;
  1180.             for (loop = 0; loop < limit; loop++)
  1181.                 {
  1182.                 bcopy ( (char *)cp,
  1183.                        (char *)&pBootpParams->nisServers->addrlist[loop], 
  1184.                        sizeof (struct in_addr));
  1185.                 cp += sizeof (struct in_addr);
  1186.                 }
  1187.             }
  1188.         pBootpParams->nisServers->num = limit;
  1189.         }
  1190.         /* Retrieve IP addresses of NTP servers, up to number requested. */
  1191.     if (pBootpParams->ntpServers != NULL && 
  1192.         pBootpParams->ntpServers->addrlist != NULL)
  1193.         {
  1194.         length = 0;
  1195.         limit = 0;
  1196.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NTP_SERVER, &length);
  1197.         if (cp != NULL)
  1198.             {
  1199.             number = length / sizeof (struct in_addr);
  1200.             limit = (pBootpParams->ntpServers->num < number) ?
  1201.                      pBootpParams->ntpServers->num : number;
  1202.             for (loop = 0; loop < limit; loop++)
  1203.                 {
  1204.                 bcopy ( (char *)cp,
  1205.                        (char *)&pBootpParams->ntpServers->addrlist[loop], 
  1206.                        sizeof (struct in_addr));
  1207.                 cp += sizeof (struct in_addr);
  1208.                 }
  1209.             }
  1210.         pBootpParams->ntpServers->num = limit;
  1211.         }
  1212.         /* Retrieve vendor specific information. */
  1213.     if (pBootpParams->vendString != NULL)
  1214.         {
  1215.         length = 0;
  1216.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_VENDOR_SPEC, &length);
  1217.         if (cp != NULL)
  1218.             {
  1219.             bcopy ( (char *)cp, pBootpParams->vendString, length);
  1220.             pBootpParams->vendString [length] = EOS;
  1221.             }
  1222.         else
  1223.             pBootpParams->vendString[0] = EOS;
  1224.         }
  1225.         /* Retrieve IP addresses of NetBIOS name servers. */
  1226.     if (pBootpParams->nbnServers != NULL && 
  1227.         pBootpParams->nbnServers->addrlist != NULL)
  1228.         {
  1229.         length = 0;
  1230.         limit = 0;
  1231.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NBN_SERVER, &length);
  1232.         if (cp != NULL)
  1233.             {
  1234.             number = length / sizeof (struct in_addr);
  1235.             limit = (pBootpParams->nbnServers->num < number) ?
  1236.                      pBootpParams->nbnServers->num : number;
  1237.             for (loop = 0; loop < limit; loop++)
  1238.                 {
  1239.                 bcopy ( (char *)cp,
  1240.                        (char *)&pBootpParams->nbnServers->addrlist[loop], 
  1241.                        sizeof (struct in_addr));
  1242.                 cp += sizeof (struct in_addr);
  1243.                 }
  1244.             }
  1245.         pBootpParams->nbnServers->num = limit;
  1246.         }
  1247.         /* Retrieve IP addresses of NetBIOS datagram distribution servers. */
  1248.     if (pBootpParams->nbddServers != NULL && 
  1249.         pBootpParams->nbddServers->addrlist != NULL)
  1250.         {
  1251.         length = 0;
  1252.         limit = 0;
  1253.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NBDD_SERVER, &length);
  1254.         if (cp != NULL)
  1255.             {
  1256.             number = length / sizeof (struct in_addr);
  1257.             limit = (pBootpParams->nbddServers->num < number) ?
  1258.                      pBootpParams->nbddServers->num : number;
  1259.             for (loop = 0; loop < limit; loop++)
  1260.                 {
  1261.                 bcopy ( (char *)cp,
  1262.                        (char *)&pBootpParams->nbddServers->addrlist[loop], 
  1263.                        sizeof (struct in_addr));
  1264.                 cp += sizeof (struct in_addr);
  1265.                 }
  1266.             }
  1267.         pBootpParams->nbddServers->num = limit;
  1268.         }
  1269.         /* Retrieve value for NetBIOS Node Type option. */
  1270.     if (pBootpParams->nbNodeType != NULL)
  1271.         {
  1272.         length = 0;
  1273.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NB_NODETYPE, &length);
  1274.         if (cp != NULL)
  1275.             *pBootpParams->nbNodeType = *cp;
  1276.         else
  1277.             *pBootpParams->nbNodeType = 0;
  1278.         }
  1279.         /* Retrieve NetBIOS scope. */
  1280.     if (pBootpParams->nbScope != NULL)
  1281.         {
  1282.         length = 0;
  1283.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NB_SCOPE, &length);
  1284.         if (cp != NULL)
  1285.             {
  1286.             bcopy ( (char *)cp, pBootpParams->nbScope, length);
  1287.             pBootpParams->nbScope [length] = EOS;
  1288.             }
  1289.         else
  1290.             pBootpParams->nbScope[0] = EOS;
  1291.         }
  1292.         /* Retrieve IP addresses of X Window font servers. */
  1293.     if (pBootpParams->xFontServers != NULL && 
  1294.         pBootpParams->xFontServers->addrlist != NULL)
  1295.         {
  1296.         length = 0;
  1297.         limit = 0;
  1298.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_XFONT_SERVER, &length);
  1299.         if (cp != NULL)
  1300.             {
  1301.             number = length / sizeof (struct in_addr);
  1302.             limit = (pBootpParams->xFontServers->num < number) ?
  1303.                      pBootpParams->xFontServers->num : number;
  1304.             for (loop = 0; loop < limit; loop++)
  1305.                 {
  1306.                 bcopy ( (char *)cp,
  1307.                        (char *)&pBootpParams->xFontServers->addrlist[loop], 
  1308.                        sizeof (struct in_addr));
  1309.                 cp += sizeof (struct in_addr);
  1310.                 }
  1311.             }
  1312.         pBootpParams->xFontServers->num = limit;
  1313.         }
  1314.         /* Retrieve IP addresses of X Window Display Manager systems. */
  1315.     if (pBootpParams->xDisplayManagers != NULL && 
  1316.         pBootpParams->xDisplayManagers->addrlist != NULL)
  1317.         {
  1318.         length = 0;
  1319.         limit = 0;
  1320.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_XDISPLAY_MANAGER, 
  1321.                            &length);
  1322.         if (cp != NULL)
  1323.             {
  1324.             number = length / sizeof (struct in_addr);
  1325.             limit = (pBootpParams->xDisplayManagers->num < number) ?
  1326.                      pBootpParams->xDisplayManagers->num : number;
  1327.             for (loop = 0; loop < limit; loop++)
  1328.                 {
  1329.                 bcopy ( (char *)cp,
  1330.                        (char *)&pBootpParams->xDisplayManagers->addrlist[loop],
  1331.                        sizeof (struct in_addr));
  1332.                 cp += sizeof (struct in_addr);
  1333.                 }
  1334.             }
  1335.         pBootpParams->xDisplayManagers->num = limit;
  1336.         }
  1337.         /* Retrieve NIS+ domain name. */
  1338.     if (pBootpParams->nispDomain != NULL)
  1339.         {
  1340.         length = 0;
  1341.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NISP_DOMAIN, &length);
  1342.         if (cp != NULL)
  1343.             {
  1344.             bcopy ( (char *)cp, pBootpParams->nispDomain, length);
  1345.             pBootpParams->nispDomain [length] = EOS;
  1346.             }
  1347.         else
  1348.             pBootpParams->nispDomain[0] = EOS;
  1349.         }
  1350.         /* Retrieve IP addresses of NIS+ servers. */
  1351.     if (pBootpParams->nispServers != NULL && 
  1352.         pBootpParams->nispServers->addrlist != NULL)
  1353.         {
  1354.         length = 0;
  1355.         limit = 0;
  1356.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NISP_SERVER, &length);
  1357.         if (cp != NULL)
  1358.             {
  1359.             number = length / sizeof (struct in_addr);
  1360.             limit = (pBootpParams->nispServers->num < number) ?
  1361.                      pBootpParams->nispServers->num : number;
  1362.             for (loop = 0; loop < limit; loop++)
  1363.                 {
  1364.                 bcopy ( (char *)cp,
  1365.                        (char *)&pBootpParams->nispServers->addrlist[loop], 
  1366.                        sizeof (struct in_addr));
  1367.                 cp += sizeof (struct in_addr);
  1368.                 }
  1369.             }
  1370.         pBootpParams->nispServers->num = limit;
  1371.         }
  1372.         /* Retrieve IP addresses of Mobile IP Home Agents. */
  1373.     if (pBootpParams->ipAgents != NULL && 
  1374.         pBootpParams->ipAgents->addrlist != NULL)
  1375.         {
  1376.         length = 0;
  1377.         limit = 0;
  1378.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_MOBILEIP_HA, &length);
  1379.         if (cp != NULL)
  1380.             {
  1381.             number = length / sizeof (struct in_addr);
  1382.             limit = (pBootpParams->ipAgents->num < number) ?
  1383.                      pBootpParams->ipAgents->num : number;
  1384.             for (loop = 0; loop < limit; loop++)
  1385.                 {
  1386.                 bcopy ( (char *)cp,
  1387.                        (char *)&pBootpParams->ipAgents->addrlist[loop], 
  1388.                        sizeof (struct in_addr));
  1389.                 cp += sizeof (struct in_addr);
  1390.                 }
  1391.             }
  1392.         pBootpParams->ipAgents->num = limit;
  1393.         }
  1394.         /* Retrieve IP addresses of SMTP servers. */
  1395.     if (pBootpParams->smtpServers != NULL && 
  1396.         pBootpParams->smtpServers->addrlist != NULL)
  1397.         {
  1398.         length = 0;
  1399.         limit = 0;
  1400.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_SMTP_SERVER, &length);
  1401.         if (cp != NULL)
  1402.             {
  1403.             number = length / sizeof (struct in_addr);
  1404.             limit = (pBootpParams->smtpServers->num < number) ?
  1405.                      pBootpParams->smtpServers->num : number;
  1406.             for (loop = 0; loop < limit; loop++)
  1407.                 {
  1408.                 bcopy ( (char *)cp,
  1409.                        (char *)&pBootpParams->smtpServers->addrlist[loop], 
  1410.                        sizeof (struct in_addr));
  1411.                 cp += sizeof (struct in_addr);
  1412.                 }
  1413.             }
  1414.         pBootpParams->smtpServers->num = limit;
  1415.         }
  1416.         /* Retrieve IP addresses of POP3 servers. */
  1417.     if (pBootpParams->pop3Servers != NULL && 
  1418.         pBootpParams->pop3Servers->addrlist != NULL)
  1419.         {
  1420.         length = 0;
  1421.         limit = 0;
  1422.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_POP3_SERVER, &length);
  1423.         if (cp != NULL)
  1424.             {
  1425.             number = length / sizeof (struct in_addr);
  1426.             limit = (pBootpParams->pop3Servers->num < number) ?
  1427.                      pBootpParams->pop3Servers->num : number;
  1428.             for (loop = 0; loop < limit; loop++)
  1429.                 {
  1430.                 bcopy ( (char *)cp,
  1431.                        (char *)&pBootpParams->pop3Servers->addrlist[loop], 
  1432.                        sizeof (struct in_addr));
  1433.                 cp += sizeof (struct in_addr);
  1434.                 }
  1435.             }
  1436.         pBootpParams->pop3Servers->num = limit;
  1437.         }
  1438.         /* Retrieve IP addresses of NNTP servers. */
  1439.     if (pBootpParams->nntpServers != NULL && 
  1440.         pBootpParams->nntpServers->addrlist != NULL)
  1441.         {
  1442.         length = 0;
  1443.         limit = 0;
  1444.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_NNTP_SERVER, &length);
  1445.         if (cp != NULL)
  1446.             {
  1447.             number = length / sizeof (struct in_addr);
  1448.             limit = (pBootpParams->nntpServers->num < number) ?
  1449.                      pBootpParams->nntpServers->num : number;
  1450.             for (loop = 0; loop < limit; loop++)
  1451.                 {
  1452.                 bcopy ( (char *)cp,
  1453.                        (char *)&pBootpParams->nntpServers->addrlist[loop], 
  1454.                        sizeof (struct in_addr));
  1455.                 cp += sizeof (struct in_addr);
  1456.                 }
  1457.             }
  1458.         pBootpParams->nntpServers->num = limit;
  1459.         }
  1460.         /* Retrieve IP addresses of World Wide Web servers. */
  1461.     if (pBootpParams->wwwServers != NULL && 
  1462.         pBootpParams->wwwServers->addrlist != NULL)
  1463.         {
  1464.         length = 0;
  1465.         limit = 0;
  1466.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_WWW_SERVER, &length);
  1467.         if (cp != NULL)
  1468.             {
  1469.             number = length / sizeof (struct in_addr);
  1470.             limit = (pBootpParams->wwwServers->num < number) ?
  1471.                      pBootpParams->wwwServers->num : number;
  1472.             for (loop = 0; loop < limit; loop++)
  1473.                 {
  1474.                 bcopy ( (char *)cp,
  1475.                        (char *)&pBootpParams->wwwServers->addrlist[loop], 
  1476.                        sizeof (struct in_addr));
  1477.                 cp += sizeof (struct in_addr);
  1478.                 }
  1479.             }
  1480.         pBootpParams->wwwServers->num = limit;
  1481.         }
  1482.         /* Retrieve IP addresses of finger servers. */
  1483.     if (pBootpParams->fingerServers != NULL && 
  1484.         pBootpParams->fingerServers->addrlist != NULL)
  1485.         {
  1486.         length = 0;
  1487.         limit = 0;
  1488.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_FINGER_SERVER, &length);
  1489.         if (cp != NULL)
  1490.             {
  1491.             number = length / sizeof (struct in_addr);
  1492.             limit = (pBootpParams->fingerServers->num < number) ?
  1493.                      pBootpParams->fingerServers->num : number;
  1494.             for (loop = 0; loop < limit; loop++)
  1495.                 {
  1496.                 bcopy ( (char *)cp,
  1497.                        (char *)&pBootpParams->fingerServers->addrlist[loop], 
  1498.                        sizeof (struct in_addr));
  1499.                 cp += sizeof (struct in_addr);
  1500.                 }
  1501.             }
  1502.         pBootpParams->fingerServers->num = limit;
  1503.         }
  1504.         /* Retrieve IP addresses of Internet Relay Chat servers. */
  1505.     if (pBootpParams->ircServers != NULL && 
  1506.         pBootpParams->ircServers->addrlist != NULL)
  1507.         {
  1508.         length = 0;
  1509.         limit = 0;
  1510.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_IRC_SERVER, &length);
  1511.         if (cp != NULL)
  1512.             {
  1513.             number = length / sizeof (struct in_addr);
  1514.             limit = (pBootpParams->ircServers->num < number) ?
  1515.                      pBootpParams->ircServers->num : number;
  1516.             for (loop = 0; loop < limit; loop++)
  1517.                 {
  1518.                 bcopy ( (char *)cp,
  1519.                        (char *)&pBootpParams->ircServers->addrlist[loop], 
  1520.                        sizeof (struct in_addr));
  1521.                 cp += sizeof (struct in_addr);
  1522.                 }
  1523.             }
  1524.         pBootpParams->ircServers->num = limit;
  1525.         }
  1526.         /* Retrieve IP addresses of StreetTalk servers. */
  1527.     if (pBootpParams->stServers != NULL && 
  1528.         pBootpParams->stServers->addrlist != NULL)
  1529.         {
  1530.         length = 0;
  1531.         limit = 0;
  1532.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_ST_SERVER, &length);
  1533.         if (cp != NULL)
  1534.             {
  1535.             number = length / sizeof (struct in_addr);
  1536.             limit = (pBootpParams->stServers->num < number) ?
  1537.                      pBootpParams->stServers->num : number;
  1538.             for (loop = 0; loop < limit; loop++)
  1539.                 {
  1540.                 bcopy ( (char *)cp,
  1541.                        (char *)&pBootpParams->stServers->addrlist[loop], 
  1542.                        sizeof (struct in_addr));
  1543.                 cp += sizeof (struct in_addr);
  1544.                 }
  1545.             }
  1546.         pBootpParams->stServers->num = limit;
  1547.         }
  1548.         /* Retrieve IP addresses of STDA servers. */
  1549.     if (pBootpParams->stdaServers != NULL && 
  1550.         pBootpParams->stdaServers->addrlist != NULL)
  1551.         {
  1552.         length = 0;
  1553.         limit = 0;
  1554.         cp = bootpTagFind (pBootpReply->bp_vend, TAG_STDA_SERVER, &length);
  1555.         if (cp != NULL)
  1556.             {
  1557.             number = length / sizeof (struct in_addr);
  1558.             limit = (pBootpParams->stdaServers->num < number) ?
  1559.                      pBootpParams->stdaServers->num : number;
  1560.             for (loop = 0; loop < limit; loop++)
  1561.                 {
  1562.                 bcopy ( (char *)cp,
  1563.                        (char *)&pBootpParams->stdaServers->addrlist[loop], 
  1564.                        sizeof (struct in_addr));
  1565.                 cp += sizeof (struct in_addr);
  1566.                 }
  1567.             }
  1568.         pBootpParams->stdaServers->num = limit;
  1569.         }
  1570.     return;
  1571.     }
  1572. /******************************************************************************
  1573. *
  1574. * bootpMsgGet - send a BOOTP request message and retrieve reply
  1575. *
  1576. * This routine sends a BOOTP request using the network interface
  1577. * specified by <pIf> and waits for any reply. The <pIpDest> argument
  1578. * specifies the destination IP address.  It must be equal to either
  1579. * the broadcast address (255.255.255.255) or the IP address of a specific
  1580. * BOOTP server which is directly reachable using the given network interface.
  1581. * The given interface must support broadcasting in the first case.
  1582. *
  1583. * The <srcPort> and <dstPort> arguments support sending and receiving 
  1584. * BOOTP messages with arbitrary UDP ports. To receive replies, any BOOTP
  1585. * server must send those responses to the source port from the request.
  1586. * To comply with the RFC 1542 clarification, the request message must be
  1587. * sent to the reserved BOOTP server port (67) using the reserved BOOTP
  1588. * client port (68).
  1589. *
  1590. * Except for the UDP port numbers, this routine only sets the `bp_xid' and
  1591. * `bp_secs' fields in the outgoing BOOTP message. All other fields in that
  1592. * message use the values from the <pBootpMsg> argument, which later holds
  1593. * the contents of any BOOTP reply received.
  1594. *
  1595. * The <maxSends> parameter specifies the total number of requests to transmit
  1596. * if no reply is received. The retransmission interval starts at 4 seconds
  1597. * and doubles with each attempt up to a maximum of 64 seconds. Any subsequent
  1598. * retransmissions will occur at that maximum interval. To reduce the chances
  1599. * of network flooding, the timeout interval before each retransmission includes
  1600. * a randomized delay of plus or minus one second from the base value. After
  1601. * the final transmission, this routine will wait for the current interval to
  1602. * expire before returning a timeout error.
  1603. *
  1604. * NOTE: The target must be able to respond to an ARP request for any IP
  1605. *       address specified in the request template's `bp_ciaddr' field.
  1606. *
  1607. * RETURNS: OK, or ERROR.
  1608. *
  1609. * ERRNO
  1610. *  S_bootpLib_INVALID_ARGUMENT
  1611. *  S_bootpLib_NO_BROADCASTS
  1612. *  S_bootpLib_TIME_OUT
  1613. */
  1614. STATUS bootpMsgGet
  1615.     (
  1616.     struct ifnet *  pIf,          /* network device for message exchange */
  1617.     struct in_addr * pIpDest,      /* destination IP address for request */
  1618.     USHORT srcPort,      /* UDP source port for request */
  1619.     USHORT  dstPort,      /* UDP destination port for request */
  1620.     BOOTP_MSG * pBootpMsg,    /* request template and reply storage */
  1621.     u_int maxSends      /* maximum number of transmit attempts */
  1622.     )
  1623.     {
  1624.     int result;
  1625.     int maxSize;
  1626.     char bpfDevName [_BOOTP_MAX_DEVNAME];  /* "/bpf/bootpc0" */
  1627.     int bpfDev;
  1628.     struct ifreq ifr;
  1629.     BOOL  broadcastFlag;
  1630.     USHORT  xid1;  /* Hardware address portion of transaction ID. */
  1631.     USHORT  xid2;  /* Additional random portion of transaction ID. */
  1632.     int  baseDelay;  /* exponential backoff time (not randomized) */
  1633.     int  retransmitSecs; /* actual (randomized) timeout interval */
  1634.     struct in_addr ipSrc; /* source  */
  1635.     fd_set  readFds;
  1636.     struct bpf_hdr *    pMsgHdr;
  1637.     char *  pMsgData;
  1638.     struct ip * pIpHead;
  1639.     struct udphdr * pUdpHead;
  1640.     struct mbuf * pMbuf;
  1641.     struct sockaddr_in dest;
  1642.     int         totlen;         /* Amount of data in BPF buffer. */
  1643.     struct timeval timeout;
  1644.     int numSends = 0;
  1645.     int totalDelay = 0;
  1646.     int level;
  1647.     END_OBJ *  pEnd;
  1648.     if (!bootpInitialized)
  1649.         {
  1650.         errno = S_bootpLib_NOT_INITIALIZED;
  1651.         return (ERROR);
  1652.         }
  1653.     if (pIf == NULL)
  1654.         {
  1655.         errno = S_bootpLib_BAD_DEVICE;
  1656.         return (ERROR);
  1657.         }
  1658.     if (pBootpMsg == NULL)
  1659.         {
  1660.         errno = S_bootpLib_INVALID_ARGUMENT;
  1661.         return (ERROR);
  1662.         }
  1663.     pEnd = endFindByName (pIf->if_name, pIf->if_unit);
  1664.     if (pEnd == NULL)
  1665.         {
  1666.         errno = S_bootpLib_BAD_DEVICE;
  1667.         return (ERROR);
  1668.         }
  1669.     /* Verify interface data sizes are appropriate for message. */
  1670.     if (pIf->if_mtu == 0)
  1671.         {
  1672.         errno = S_bootpLib_BAD_DEVICE;
  1673.         return (ERROR);
  1674.         }
  1675.     maxSize = pIf->if_mtu;
  1676.     if (maxSize < BOOTPLEN + UDPHL + IPHL)
  1677.         {
  1678.         /*
  1679.          * Devices must accept messages equal to an IP datagram
  1680.          * of 328 bytes, which corresponds to the fixed-size BOOTP
  1681.          * message with the minimum headers.
  1682.          */
  1683.         errno = S_bootpLib_BAD_DEVICE;
  1684.         return (ERROR);
  1685.         }
  1686.     maxSize = pIf->if_hdrlen + BOOTPLEN + UDPHL + IPHL;
  1687.     if (maxSize > (bootpBufSize - sizeof (struct bpf_hdr)) )
  1688.         {
  1689.         /* Link level header exceeds maximum supported value. */
  1690.         errno = S_bootpLib_BAD_DEVICE;
  1691.         return (ERROR);
  1692.         }
  1693.     /* Get a BPF file descriptor to read/write BOOTP messages. */
  1694.     sprintf (bpfDevName, "/bpf/bootpc0");
  1695.     bpfDev = open (bpfDevName, 0, 0);
  1696.     if (bpfDev < 0)
  1697.         {
  1698.         errno = S_bootpLib_BAD_DEVICE;
  1699.         return (ERROR);
  1700.         }
  1701.     /* Enable immediate mode for reading messages. */
  1702.     result = 1;
  1703.     result = ioctl (bpfDev, BIOCIMMEDIATE, (int)&result);
  1704.     if (result != 0)
  1705.         {
  1706.         close (bpfDev);
  1707.         errno = S_bootpLib_BAD_DEVICE;
  1708.         return (ERROR);
  1709.         }
  1710.     /*
  1711.      * Add a filter for incoming BOOTP packets and assign the selected
  1712.      * interface to the BPF device.
  1713.      */
  1714.     bootpfilter [12].k = srcPort;
  1715.     result = ioctl (bpfDev, BIOCSETF, (int)&bootpread);
  1716.     if (result != 0)
  1717.         {
  1718.         close (bpfDev);
  1719.         errno = S_bootpLib_BAD_DEVICE;
  1720.         return (ERROR);
  1721.         }
  1722.     bzero ( (char *)&ifr, sizeof (struct ifreq));
  1723.     sprintf (ifr.ifr_name, "%s%d", pIf->if_name, pIf->if_unit);
  1724.     result = ioctl (bpfDev, BIOCSETIF, (int)&ifr);
  1725.     if (result != 0)
  1726.         {
  1727.         close (bpfDev);
  1728.         errno = S_bootpLib_BAD_DEVICE;
  1729.         return (ERROR);
  1730.         }
  1731.     /*
  1732.      * Select the transmission method and set the IP source and destination
  1733.      * addresses. Verify the interface is capable of broadcasts if needed.
  1734.      */
  1735.     if (pIpDest->s_addr == INADDR_BROADCAST)
  1736.         {
  1737.         if ( (pIf->if_flags & IFF_BROADCAST) == 0)
  1738.             {
  1739.             close (bpfDev);
  1740.             errno = S_bootpLib_NO_BROADCASTS;
  1741.             return (ERROR);
  1742.             }
  1743.         broadcastFlag = TRUE;
  1744.         }
  1745.     else
  1746.         {
  1747.         broadcastFlag = FALSE;
  1748.         }
  1749.     ipSrc.s_addr = pBootpMsg->bp_ciaddr.s_addr;
  1750.     /* Initialize timeout values. */
  1751.     baseDelay = INIT_BOOTP_DELAY;
  1752.     retransmitSecs = (baseDelay - 1) + (rand () % 3);
  1753.     /* Copy the provided BOOTP (request) message and set the transaction ID. */
  1754.     bzero ( (char *)&bootpMsg, sizeof (bootpMsg));
  1755.     bootpMsg.bp  = *pBootpMsg;
  1756.     xid1= checksum ( (u_short *)bootpMsg.bp.bp_chaddr, bootpMsg.bp.bp_hlen);
  1757.     xid2 = rand() & 0xffff;
  1758.     bootpMsg.bp.bp_xid = htonl ((xid1 << 16) + xid2);
  1759.     /* Fill in the UDP header. */
  1760.     bootpMsg.uh.uh_sport = htons ((u_short) srcPort);
  1761.     bootpMsg.uh.uh_dport = htons ((u_short) dstPort);
  1762.     bootpMsg.uh.uh_ulen = htons (sizeof (BOOTP_MSG) + UDPHL);
  1763.     bootpMsg.uh.uh_sum = 0;
  1764.     /* Fill in the IP header. */
  1765.     bootpMsg.ih.ip_v = IPVERSION;
  1766.     bootpMsg.ih.ip_hl = IPHL >> 2;
  1767.     bootpMsg.ih.ip_tos = 0;
  1768.     bootpMsg.ih.ip_len = htons (sizeof (bootpMsg));
  1769.     bootpMsg.ih.ip_id = htons ((u_short) (~ (bootpMsg.bp.bp_xid + xid1)));
  1770.     bootpMsg.ih.ip_off = 0;
  1771.     bootpMsg.ih.ip_ttl = MAXTTL;
  1772.     bootpMsg.ih.ip_p = IPPROTO_UDP;
  1773.     bootpMsg.ih.ip_src.s_addr = ipSrc.s_addr;
  1774.     bootpMsg.ih.ip_dst.s_addr = pIpDest->s_addr;
  1775.     bootpMsg.ih.ip_sum = 0;
  1776.     bootpMsg.ih.ip_sum = checksum ( (u_short *) &bootpMsg.ih,
  1777.                                    bootpMsg.ih.ip_hl << 2);
  1778.     /* Fill in the destination address structure and begin transmitting. */
  1779.     bzero ( (char *)&dest, sizeof (struct sockaddr_in));
  1780.     dest.sin_len = sizeof (struct sockaddr_in);
  1781.     dest.sin_family = AF_INET;
  1782.     dest.sin_addr.s_addr = pIpDest->s_addr;
  1783.     while (numSends < maxSends)
  1784.         {
  1785.         /* Update BPF filter to check for current transaction ID. */
  1786.         bootpfilter [20].k = ntohl (bootpMsg.bp.bp_xid);
  1787.         ioctl (bpfDev, BIOCSETF, (u_int)&bootpread);
  1788.         pMbuf = bcopy_to_mbufs ( (char *)&bootpMsg.ih, sizeof (bootpMsg),
  1789.                                 0, pIf, NONE);
  1790.         if (pMbuf == NULL)
  1791.             {
  1792.             result = ERROR;
  1793.             break;
  1794.             }
  1795.         if (broadcastFlag)
  1796.             pMbuf->mBlkHdr.mFlags |= M_BCAST;
  1797.         FD_ZERO (&readFds);
  1798.         level = splnet ();
  1799.         result = pIf->if_output (pIf, pMbuf, (struct sockaddr *)&dest, NULL);
  1800.         splx (level);
  1801.         if (result == ERROR)
  1802.             {
  1803.             break;
  1804.             }
  1805.         /* wait for a reply */
  1806.         FD_SET (bpfDev, &readFds);
  1807.         timeout.tv_sec = retransmitSecs;
  1808.         timeout.tv_usec = 0;
  1809.         result = select (bpfDev + 1, &readFds, NULL, NULL, &timeout);
  1810.         if (result == ERROR) 
  1811.             break;
  1812.         if (result)    /* got reply !! */
  1813.             {
  1814.             pMsgData = pMsgBuffer;
  1815.             totlen = read (bpfDev, pMsgData, bootpBufSize);
  1816.             pMsgHdr = (struct bpf_hdr *)pMsgData;
  1817.             /* Set the pointer to skip the BPF and link level headers. */
  1818.             pMsgData = pMsgData + pMsgHdr->bh_hdrlen + pMsgHdr->bh_linklen;
  1819.             /* Skip the IP and UDP headers and copy BOOTP message. */
  1820.             pIpHead = (struct ip *)pMsgData;
  1821.             pUdpHead = (struct udphdr *) (pMsgData + (pIpHead->ip_hl << 2));
  1822.             pMsgData = ( (u_char *)pUdpHead + sizeof (struct udphdr));
  1823.             bcopy (pMsgData, (char *)pBootpMsg, BOOTPLEN);
  1824.             result = OK;
  1825.  
  1826.             break;
  1827.             }
  1828.         else    /* Timeout - retransmit message if permitted. */
  1829.             {
  1830.             numSends++;
  1831.             totalDelay += retransmitSecs;
  1832.             if (baseDelay < MAX_BOOTP_DELAY)
  1833.                 baseDelay *= 2;
  1834.             retransmitSecs = (baseDelay - 1) + (rand () % 3);
  1835.             /*
  1836.              * Set new transaction ID and update 'secs' field. No other
  1837.              * work needed since the message does not include a UDP checksum.
  1838.              */
  1839.             xid2 = rand() & 0xffff;
  1840.             bootpMsg.bp.bp_xid = htonl ((xid1 << 16) + xid2);
  1841.             bootpMsg.bp.bp_secs = htons (totalDelay);
  1842.             /*
  1843.              * Set result to indicate failure
  1844.              * (in case retransmit limit reached).
  1845.              */
  1846.             result = ERROR;
  1847.             }
  1848.         }
  1849.     close (bpfDev);
  1850.     return (result);
  1851.     }
  1852. /*******************************************************************************
  1853. *
  1854. * bootpTagFind - find data for a BOOTP options tag
  1855. *
  1856. * This routine finds the data associated with tag <tag> in the 
  1857. * vendor-specific member of a BOOTP message.  The <tag> parameter must 
  1858. * be a valid 1533 vendor-tag value.  Only <tag> values that have data 
  1859. * associated with them are considered valid (for example, TAG_END 
  1860. * and TAG_PAD are not valid <tag> values because they have no data).
  1861. * The <pVend> parameter is a pointer to the beginning of the 
  1862. * vendor-specific member in the BOOTP message.  If <tag> is found 
  1863. * in <pVend>, the length of the associated data gets placed in <pSize> 
  1864. * and a pointer to the data is returned.
  1865. *
  1866. * INTERNAL
  1867. * The vendor information field is divided into extendable tagged subfields.
  1868. * Tags that have no data, consist of a single tag octet and are one octet
  1869. * in length.  All other tags have a one tag octet, a length octet and length
  1870. * octets of data.  For a more complete description of the tags and how they
  1871. * are parsed, please refer to RFC 1048 or its successors. All tags defined
  1872. * through RFC 1533 are supported.
  1873. *
  1874. * RETURNS: A pointer to tag data if successful, otherwise NULL.
  1875. *
  1876. * ERRNO
  1877. *  S_bootpLib_INVALID_ARGUMENT
  1878. *  S_bootpLib_INVALID_COOKIE
  1879. *  S_bootpLib_INVALID_TAG
  1880. *  S_bootpLib_PARSE_ERROR
  1881. *
  1882. * NOMANUAL
  1883. */
  1884. LOCAL u_char * bootpTagFind
  1885.     (
  1886.     u_char * pVend, /* vendor specific information  */
  1887.     int tag, /* tag to be located  */
  1888.     int * pSize /* return size of data */
  1889.     )
  1890.     {
  1891.     u_char * cp; /* character pointer  */
  1892.     u_char * pData; /* pointer to data */
  1893.     int  sizeData; /* size if data */
  1894.     if ( (pSize == NULL) || (pVend == NULL))  /* validate arguments */
  1895.         {
  1896.         errno = S_bootpLib_INVALID_ARGUMENT;
  1897.         return  (NULL);
  1898.         }
  1899.     if ( (tag <= TAG_PAD) || (tag >= TAG_END)) /* validate tag */
  1900.         {
  1901.         errno = S_bootpLib_INVALID_TAG;
  1902.         return (NULL);
  1903.         }
  1904.      /* validate RFC 1048 cookie */
  1905.     if (bcmp ( (char *)magicCookie1048, (char *)pVend,
  1906.                sizeof (magicCookie1048)) != 0)
  1907.         {
  1908.         errno = S_bootpLib_INVALID_COOKIE;
  1909.         return (NULL);
  1910.         }
  1911.     pData = pVend + sizeof (magicCookie1048); /* move past cookie */
  1912.     sizeData = SIZE_VEND - sizeof (magicCookie1048);
  1913.     /* loop to find tag */
  1914.     for (cp = pData; (*cp != (u_char)TAG_END) && (cp < pData + sizeData); cp++)
  1915.         {
  1916.         if (*cp == (u_char) TAG_PAD) /* do nothing -  pad */
  1917.             continue;
  1918.         if ( (cp + 1) >= (pData + sizeData)) /* no for length */
  1919.             {
  1920.             errno = S_bootpLib_PARSE_ERROR;
  1921.             break;
  1922.             }
  1923.         *pSize = *(cp + 1);
  1924.         /* no room for data */
  1925.         if ( (cp + 2 + *pSize) > (pData + sizeData))
  1926.             {
  1927.             errno = S_bootpLib_PARSE_ERROR;
  1928.             break;
  1929.             }
  1930.         if (*cp == (u_char)tag) /* found desired tag */
  1931.             return (cp + 2);
  1932.         cp += *pSize + 1; /* move past the data */
  1933.         }
  1934.     *pSize = 0;
  1935.     return (NULL);
  1936.     }
  1937. /*******************************************************************************
  1938. *
  1939. * bootpConvert - convert the hardware type from the MUX
  1940. *
  1941. * This routine converts the hardware type value which the MUX interface
  1942. * provides into the encoding that BOOTP uses. The MUX interface uses the
  1943. * RFC 1213 MIB values while BOOTP uses the interface encodings from the ARP
  1944. * section of the assigned numbers RFC (RFC 1700).
  1945. *
  1946. * NOMANUAL
  1947. *
  1948. * RETURNS: RFC 1700 encoding of type value, or ERROR if none.
  1949. *
  1950. */
  1951. LOCAL int bootpConvert
  1952.     (
  1953.     int muxType         /* RFC 1213 interface type value */
  1954.     )
  1955.     {
  1956.     int bootpType = 0;
  1957.     switch (muxType)
  1958.         {
  1959.         default:
  1960.             return (ERROR);
  1961.             break;
  1962.         case M2_ifType_ethernet_csmacd:
  1963.             bootpType = ETHER;
  1964.             break;
  1965.         case M2_ifType_ethernet3Mbit:
  1966.             bootpType = EXPETHER;
  1967.             break;
  1968.         case M2_ifType_proteon10Mbit:     /* fall-through */
  1969.         case M2_ifType_proteon80Mbit:
  1970.             bootpType = PRONET;
  1971.             break;
  1972.         case M2_ifType_iso88023_csmacd:    /* fall-through */
  1973.         case M2_ifType_iso88024_tokenBus:  /* fall-through */
  1974.         case M2_ifType_iso88025_tokenRing: /* fall-through */
  1975.         case M2_ifType_iso88026_man:
  1976.             bootpType = IEEE802;
  1977.             break;
  1978.         case M2_ifType_hyperchannel:
  1979.             bootpType = HYPERCH;
  1980.             break;
  1981.         case M2_ifType_starLan:
  1982.             bootpType = LANSTAR;
  1983.             break;
  1984.         case M2_ifType_ultra:
  1985.             bootpType = ULTRALINK;
  1986.             break;
  1987.         case M2_ifType_frameRelay:
  1988.             bootpType = FRAMERELAY;
  1989.             break;
  1990.         case M2_ifType_propPointToPointSerial:    /* fall-through */
  1991.         case M2_ifType_ppp:                       /* fall-through */
  1992.         case M2_ifType_slip:
  1993.             bootpType = SERIAL;
  1994.             break;
  1995.         }
  1996.     return (bootpType);
  1997.     }