import of upstream version 1.17
[mw/micromonitor-lm32.git] / umon_main / target / common / dhcpboot.c
1 /* dhcpboot.c:
2  *      This code implements a subset of the DHCP client protocol.
3  *      Based on RFC2131 spec, the "automatic allocation" mode, in which DHCP
4  *      assigns a permanent IP address to a client, is the only mode supported.
5  *
6  *      The idea is that the monitor boots up, and if IPADD is set to DHCP, then
7  *      DHCP is used to populate shell variables with a server-supplied IP
8  *      address, NetMask and Gateway IP address. Then, when the application
9  *      is launched (probably via TFS), it can retrieve the content of those
10  *      shell variables for use by the application.
11  *
12  *      Sequence of events for this limited implementation of DHCP...
13  *      Client issues a DHCP_DISCOVER, server responds with a DHCP_OFFER,
14  *      client issues a DHCP_REQUEST and server responds with a DHCP_ACK.
15  *      DISCOVER: request by the client to broadcast the fact that it is looking
16  *      for a DHCP server.
17  *      OFFER: reply from the server when it receives a DISCOVER request from 
18  *              a client.  The offer may contain all the information that the DHCP
19  *              client needs to bootup, but this is dependent on the configuration of
20  *              the server.
21  *      REQUEST: request by the client for the server (now known because an OFFER
22  *              was received) to send it the information it needs.
23  *      ACK: reply from the server with the information requested.
24  *
25  *      NOTE: this file contains a generic DHCP client supporting "automatic
26  *      allocation mode" (infinite lease time).  There are several different
27  *      application-specific enhancements that can be added and hopefully
28  *      they have been isolated through the use of the dhcp_00.c file.
29  *      I've attempted to isolate as much of the non-generic code to
30  *      the file dhcp_XX.c (where dhcp_00.c is the default code).  If non-default
31  *      code is necessary, then limit the changes to a new dhcp_XX.c file.  This
32  *      will allow the code in this file to stay generic; hence, the user of this
33  *      code will be able to accept monitor upgrades without the need to touch
34  *      this file.  The makefile must link in some additional dhcp_XX.c file
35  *      (default is dhcp_00.c).  Bottom line... there should be no need to modify
36  *      this file for application-specific stuff; if there is, please let me know.
37  *
38  *      NOTE1: the shell variable IPADD can also be set to DHCPV or DHCPv to 
39  *      enable different levels of verbosity during DHCP transactions... 'V'
40  *      is full DHCP verbosity and 'v' only prints the DhcpSetEnv() calls.
41  *
42  *      NOTE2: this file supports DHCP and BOOTP.  Most of the function names
43  *      refer to DHCP even though their functionality is shared by both DHCP 
44  *      and BOOTP.  This is because I wrote this originally for DHCP, then added
45  *      the hooks for BOOTP... Bottom line: don't let the names confuse you!
46  *
47  *      General notice:
48  *      This code is part of a boot-monitor package developed as a generic base
49  *      platform for embedded system designs.  As such, it is likely to be
50  *      distributed to various projects beyond the control of the original
51  *      author.  Please notify the author of any enhancements made or bugs found
52  *      so that all may benefit from the changes.  In addition, notification back
53  *      to the author will allow the new user to pick up changes that may have
54  *      been made by other users after this version of the code was distributed.
55  *
56  *      Note1: the majority of this code was edited with 4-space tabs.
57  *      Note2: as more and more contributions are accepted, the term "author"
58  *                 is becoming a mis-representation of credit.
59  *
60  *      Original author:        Ed Sutter
61  *      Email:                          esutter@lucent.com
62  *      Phone:                          908-582-2351
63  */
64
65 #include "config.h"
66 #include "endian.h"
67 #include "cpuio.h"
68 #include "ether.h"
69 #include "tfs.h"
70 #include "tfsprivate.h"
71 #include "genlib.h"
72 #include "stddefs.h"
73 #include "cli.h"
74 #include "timer.h"
75
76 int     DHCPStartup(short), BOOTPStartup(short);
77 int DhcpSetEnv(char *,char *);
78 int SendDHCPDiscover(int,short);
79 void dhcpDumpVsa(void), printDhcpOptions(uchar *);
80
81 unsigned short  DHCPState;
82
83 #if INCLUDE_DHCPBOOT
84
85 static struct elapsed_tmr dhcpTmr;
86 static int              DHCPCommandIssued;
87 static ulong    DHCPTransactionId;
88
89 /* Variables used for DHCP Class ID specification: */
90 static char     *DHCPClassId;
91 static int      DHCPClassIdSize;
92
93 /* Variables used for DHCP Client ID specification: */
94 static char     DHCPClientId[32];
95 static int      DHCPClientIdSize, DHCPClientIdType;
96
97 /* Variables used for setting up a DHCP Parameter Request List: */
98 static uchar    DHCPRequestList[32];
99 static int              DHCPRqstListSize;
100
101 /* Variable to keep track of elapsed seconds since DHCP started: */
102 static short    DHCPElapsedSecs;
103
104 char *DhcpHelp[] = {
105         "Issue a DHCP discover",
106         "-[brvV] [vsa]",
107 #if INCLUDE_VERBOSEHELP
108         "Options...",
109         " -b      use bootp",
110         " -r      retry",
111         " -v|V    verbosity",
112 #endif
113                 0,
114 };
115
116 int
117 Dhcp(int argc,char *argv[])
118 {
119         int     opt, bootp;
120
121         bootp = 0;
122         DHCPCommandIssued = 1;
123         while ((opt=getopt(argc,argv,"brvV")) != -1) {
124                 switch(opt) {
125                 case 'b':
126                         bootp = 1;
127                         break;
128                 case 'r':
129                         DHCPCommandIssued = 0;
130                         break;
131 #if INCLUDE_ETHERVERBOSE
132                 case 'v':
133                         EtherVerbose = SHOW_DHCP;
134                         break;
135                 case 'V':
136                         EtherVerbose = DHCP_VERBOSE;
137                         break;
138 #endif
139                 default:
140                         return(CMD_PARAM_ERROR);
141                 }
142         }
143
144         if (argc == optind+1)  {
145                 if (!strcmp(argv[optind],"vsa")) {
146                         dhcpDumpVsa();
147                         return(CMD_SUCCESS);
148                 }
149                 else
150                         return(CMD_PARAM_ERROR);
151         }
152         else if (argc != optind)
153                 return(CMD_PARAM_ERROR);
154
155         startElapsedTimer(&dhcpTmr,RetransmitDelay(DELAY_INIT_DHCP)*1000);
156
157         if (bootp) {
158                 DHCPState = BOOTPSTATE_INITIALIZE;
159                 if (DHCPCommandIssued)
160                         BOOTPStartup(0);
161         }
162         else {
163                 DHCPState = DHCPSTATE_INITIALIZE;
164                 if (DHCPCommandIssued)
165                         DHCPStartup(0);
166         }
167         return(CMD_SUCCESS);
168 }
169
170 /* dhcpDumpVsa():
171  *      Simply dump the content of the VSA shell variable in DHCP format.
172  *      The variable content is stored in ascii and must be converted to binary
173  *      prior to calling printDhcpOptions().
174  */
175 void
176 dhcpDumpVsa(void)
177 {
178         int             i;
179         char    tmp[3],  *vsa_b, *vsa_a, len;
180
181         vsa_a = getenv("DHCPVSA");
182         if ((!vsa_a) || (!strcmp(vsa_a,"TRUE")))
183                 return;
184         len = strlen(vsa_a);
185         vsa_b = malloc(len);
186         if (!vsa_b)
187                 return;
188
189         len >>= 1;
190         tmp[2] = 0;
191         for(i=0;i<len;i++) {
192                 tmp[0] = *vsa_a++;      
193                 tmp[1] = *vsa_a++;      
194                 vsa_b[i] = (char)strtol(tmp,0,16);
195         }
196         /* First 4 bytes of DHCPVSA is the cookie, so skip over that. */
197         printDhcpOptions((unsigned char *)vsa_b+4);
198         free(vsa_b);
199 }
200
201 void
202 dhcpDisable()
203 {
204         DHCPState = DHCPSTATE_NOTUSED;
205 }
206
207 /* DHCPStartup():
208  *      This function is called at the point in which the ethernet interface is
209  *      started if, and only if, the IPADD shell variable is set to DHCP.
210  *      In older version of DHCP, the default was to use  "LUCENT.PPA.1.1" as
211  *      the default vcid.  Now it is only used if specified in the shell variable
212  *      DHCPCLASSID.  The same strategy applies to DHCPCLIENTID.
213 */
214 int
215 DHCPStartup(short seconds)
216 {
217         char    *id, *colon, *rlist;
218
219 #if !INCLUDE_TFTP
220         printf("WARNING: DHCP can't load bootfile, TFTP not built into monitor.\n");
221 #endif
222
223         /* The format of DHCPCLASSID is simply a string of characters. */
224         id = getenv("DHCPCLASSID");
225         if (id)
226                 DHCPClassId = id;
227         else
228                 DHCPClassId = "";
229         DHCPClassIdSize = strlen(DHCPClassId);
230
231         /* The format of DHCPCLIENTID is "TYPE:ClientID" where 'TYPE is a
232          * decimal number ranging from 1-255 used as the "type" portion of
233          * the option, and ClientID is a string of ascii-coded hex pairs
234          * that are converted to binary and used as the client identifier.
235          */
236         id = getenv("DHCPCLIENTID");
237         if (id) {
238                 colon = strchr(id,':');
239                 if ((colon) && (!(strlen(colon+1) & 1))) {
240                         DHCPClientIdType = atoi(id);
241                         colon++;
242                         for(DHCPClientIdSize=0;*colon;DHCPClientIdSize++) {
243                                 uchar tmp;
244
245                                 tmp = colon[2];
246                                 colon[2] = 0;
247                                 DHCPClientId[DHCPClientIdSize] = (uchar)strtol(colon,0,16);
248                                 colon[2] = tmp;
249                                 colon+=2;
250                         }
251                 }
252         }
253         else
254                 DHCPClientIdSize = 0;
255
256         /* The format of DHCPRQSTLIST is #:#:#:#:# where each '#' is a decimal
257          * number representing a parameter to be requested via the Parameter
258          * Request List option...
259          */
260         rlist = getenv("DHCPRQSTLIST");
261         if (rlist) {
262                 DHCPRqstListSize = 0;
263                 colon = rlist;
264                 while(*colon) {
265                         if (*colon++ == ':')
266                                 DHCPRqstListSize++;
267                 }
268                 if (DHCPRqstListSize > sizeof(DHCPRequestList)) {
269                         printf("DHCPRQSTLIST too big.\n");
270                         DHCPRqstListSize = 0;
271                 }
272                 else {
273                         char *rqst;
274
275                         DHCPRqstListSize = 0;
276                         rqst = rlist;
277                         while(1) {
278                                 DHCPRequestList[DHCPRqstListSize++] = strtol(rqst,&colon,0);
279                                 if (*colon != ':')
280                                         break;
281                                 rqst = colon+1;
282                         }
283                         DHCPRequestList[DHCPRqstListSize] = 0;
284                 }
285         }
286         else
287                 DHCPRqstListSize = 0;
288
289         return(SendDHCPDiscover(0,seconds));
290 }
291
292 int
293 BOOTPStartup(short seconds)
294 {
295         return(SendDHCPDiscover(1,seconds));
296 }
297
298 uchar *
299 dhcpLoadShellVarOpts(uchar *options)
300 {
301         if (DHCPClassIdSize) {
302                 *options++ = DHCPOPT_CLASSID;
303                 *options++ = DHCPClassIdSize;
304                 memcpy((char *)options, (char *)DHCPClassId, DHCPClassIdSize);
305                 options += DHCPClassIdSize;
306         }
307         if (DHCPClientIdSize) {
308                 *options++ = DHCPOPT_CLIENTID;
309                 *options++ = DHCPClientIdSize+1;
310                 *options++ = DHCPClientIdType;
311                 memcpy((char *)options, (char *)DHCPClientId, DHCPClientIdSize);
312                 options += DHCPClientIdSize;
313         }
314         if (DHCPRqstListSize) {
315                 *options++ = DHCPOPT_PARMRQSTLIST;
316                 *options++ = DHCPRqstListSize;
317                 memcpy((char *)options, (char *)DHCPRequestList, DHCPRqstListSize);
318                 options += DHCPRqstListSize;
319         }
320         return(options);
321 }
322
323 /* SendDHCPDiscover()
324  *      The DHCPDISCOVER is issued as an ethernet broadcast.  IF the bootp
325  *      flag is non-zero then just do a bootp request (a subset of the 
326  *      DHCPDISCOVER stuff).
327  */
328 int
329 SendDHCPDiscover(int bootp,short seconds)
330 {
331         struct  dhcphdr *dhcpdata;
332         struct  bootphdr *bootpdata;
333         struct  ether_header *te;
334         struct  ip *ti;
335         struct  Udphdr *tu;
336         ushort  uh_ulen;
337         int             optlen;
338         char    *dhcpflags;
339         ulong   cookie;
340         uchar   *dhcpOptions, *dhcpOptionsBase;
341
342         /* Retrieve an ethernet buffer from the driver and populate the
343          * ethernet level of packet:
344          */
345         te = (struct ether_header *) getXmitBuffer();
346         memcpy((char *)&te->ether_shost, (char *)BinEnetAddr,6);
347         memcpy((char *)&te->ether_dhost, (char *)BroadcastAddr,6);
348         te->ether_type = ecs(ETHERTYPE_IP);
349
350         /* Move to the IP portion of the packet and populate it appropriately: */
351         ti = (struct ip *) (te + 1);
352         ti->ip_vhl = IP_HDR_VER_LEN;
353         ti->ip_tos = 0;
354         ti->ip_id = 0;
355         ti->ip_off = ecs(0x4000);       /* No fragmentation allowed */
356         ti->ip_ttl = UDP_TTL;
357         ti->ip_p = IP_UDP;
358         memset((char *)&ti->ip_src.s_addr,0,4);
359         memset((char *)&ti->ip_dst.s_addr,0xff,4);
360
361         /* Now udp... */
362         tu = (struct Udphdr *) (ti + 1);
363         tu->uh_sport = ecs(DhcpClientPort);
364         tu->uh_dport = ecs(DhcpServerPort);
365
366         /* First the stuff that is the same for BOOTP or DHCP... */
367         bootpdata = (struct bootphdr *)(tu+1);
368         dhcpdata = (struct dhcphdr *)(tu+1);
369         dhcpdata->op = DHCPBOOTP_REQUEST;
370         dhcpdata->htype = 1;
371         dhcpdata->hlen = 6;
372         dhcpdata->hops = 0;
373         dhcpdata->seconds = ecs(seconds);
374         memset((char *)dhcpdata->bootfile,0,sizeof(dhcpdata->bootfile));
375         memset((char *)dhcpdata->server_hostname,0,sizeof(dhcpdata->server_hostname));
376
377         /* For the first DHCPDISCOVER issued, establish a transaction id based
378          * on a crc32 of the mac address.  For each DHCPDISCOVER after that,
379          * just increment.
380          */
381         if (!DHCPTransactionId)
382                 DHCPTransactionId = crc32(BinEnetAddr,6);
383         else
384                 DHCPTransactionId++;
385
386         memcpy((char *)&dhcpdata->transaction_id,(char *)&DHCPTransactionId,4);
387         memset((char *)&dhcpdata->client_ip,0,4);
388         memset((char *)&dhcpdata->your_ip,0,4);
389         memset((char *)&dhcpdata->server_ip,0,4);
390         memset((char *)&dhcpdata->router_ip,0,4);
391         memcpy((char *)dhcpdata->client_macaddr, (char *)BinEnetAddr,6);
392         dhcpflags = getenv("DHCPFLAGS");
393         if (dhcpflags)          /* 0x8000 is the only bit used currently. */
394                 dhcpdata->flags = (ushort)strtoul(dhcpflags,0,0);
395         else
396                 dhcpdata->flags = 0;
397
398         self_ecs(dhcpdata->flags);
399
400         /* Finally, the DHCP or BOOTP specific stuff...
401          * Based on RFC1534 (Interoperation Between DHCP and BOOTP), any message
402          * received by a DHCP server that contains a 'DHCP_MESSAGETYPE' option
403          * is assumed to have been sent by a DHCP client.  A message without the
404          * DHCP_MESSAGETYPE option is assumed to have been sent by a BOOTP
405          * client.
406          */
407         uh_ulen = optlen = 0;
408         if (bootp) {
409                 memset((char *)bootpdata->vsa,0,sizeof(bootpdata->vsa));
410                 uh_ulen = sizeof(struct Udphdr) + sizeof(struct bootphdr);
411                 tu->uh_ulen = ecs(uh_ulen);
412         }
413         else {
414                 if (!buildDhcpHdr(dhcpdata)) {
415                         /* The cookie should only be loaded at the start of the
416                          * vendor specific area if vendor-specific options are present.
417                          */
418                         cookie = ecl(STANDARD_MAGIC_COOKIE);
419                         memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4);
420                         dhcpOptionsBase = (uchar *)(dhcpdata+1);
421                         dhcpOptions = dhcpOptionsBase;
422                         *dhcpOptions++ = DHCPOPT_MESSAGETYPE;
423                         *dhcpOptions++ = 1;
424                         *dhcpOptions++ = DHCPDISCOVER;
425                         dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions);
426                         *dhcpOptions++ = 0xff;
427         
428                         /* Calculate ip and udp lengths after all DHCP options are loaded
429                          * so that the size is easily computed based on the value of the
430                          * dhcpOptions pointer.  Apparently, the minimum size of the
431                          * options space is 64 bytes, we determined this simply because
432                          * the DHCP     server we are using complains if the size is smaller.
433                          * Also, NULL out the space that is added to get a minimum option
434                          * size of 64 bytes, 
435                          */
436                         optlen = dhcpOptions - dhcpOptionsBase;
437                         if (optlen < 64) {
438                                 memset((char *)dhcpOptions,0,64-optlen);
439                                 optlen = 64;
440                         }
441                         uh_ulen = sizeof(struct Udphdr)+sizeof(struct dhcphdr)+optlen;
442                         tu->uh_ulen = ecs(uh_ulen);
443                 }
444         }
445         ti->ip_len = ecs((sizeof(struct ip) + uh_ulen));
446
447         ipChksum(ti);   /* Compute checksum of ip hdr */
448         udpChksum(ti);  /* Compute UDP checksum */
449
450         if (bootp) {
451                 DHCPState = BOOTPSTATE_REQUEST;
452                 sendBuffer(BOOTPSIZE);
453         }
454         else {
455                 DHCPState = DHCPSTATE_SELECT;
456                 sendBuffer(DHCPSIZE+optlen);
457         }
458 #if INCLUDE_ETHERVERBOSE
459         if (EtherVerbose & SHOW_DHCP)
460                 printf("  %s startup (%d elapsed secs)\n",
461                         bootp ? "BOOTP" : "DHCP",seconds);
462 #endif
463         return(0);
464 }
465
466 /* SendDHCPRequest()
467  *      The DHCP request is broadcast back with the "server identifier" option
468  *      set to indicate which server has been selected (in case more than one
469  *      has offered).
470  */
471 int
472 SendDHCPRequest(struct dhcphdr *dhdr)
473 {
474         uchar   *op;
475         struct  dhcphdr *dhcpdata;
476         struct  ether_header *te;
477         struct  ip *ti;
478         struct  Udphdr *tu;
479         int             optlen;
480         uchar   *dhcpOptions, *dhcpOptionsBase;
481         ushort  uh_ulen;
482         ulong   cookie;
483
484 #if INCLUDE_ETHERVERBOSE
485         if (EtherVerbose & SHOW_DHCP)
486                 printf("  DHCP request\n");
487 #endif
488
489         te = (struct ether_header *) getXmitBuffer();
490         memcpy((char *)&te->ether_shost, (char *)BinEnetAddr,6);
491         memcpy((char *)&te->ether_dhost, (char *)BroadcastAddr,6);
492         te->ether_type = ecs(ETHERTYPE_IP);
493
494         ti = (struct ip *) (te + 1);
495         ti->ip_vhl = IP_HDR_VER_LEN;
496         ti->ip_tos = 0;
497         ti->ip_id = 0;
498         ti->ip_off = ecs(0x4000);       /* No fragmentation allowed */
499         ti->ip_ttl = UDP_TTL;
500         ti->ip_p = IP_UDP;
501         memset((char *)&ti->ip_src.s_addr,0,4);
502         memset((char *)&ti->ip_dst.s_addr,0xff,4);
503
504         tu = (struct Udphdr *) (ti + 1);
505         tu->uh_sport = ecs(DhcpClientPort);
506         tu->uh_dport = ecs(DhcpServerPort);
507
508         dhcpdata = (struct dhcphdr *)(tu+1);
509         dhcpdata->op = DHCPBOOTP_REQUEST;
510         dhcpdata->htype = 1;
511         dhcpdata->hlen = 6;
512         dhcpdata->hops = 0;
513         dhcpdata->seconds = ecs(DHCPElapsedSecs);
514         /* Use the same xid for the request as was used for the discover...
515          * (rfc2131 section 4.4.1)
516          */
517         memcpy((char *)&dhcpdata->transaction_id,(char *)&dhdr->transaction_id,4);
518
519         dhcpdata->flags = dhdr->flags;
520         memset((char *)&dhcpdata->client_ip,0,4);
521         memcpy((char *)&dhcpdata->your_ip,(char *)&dhdr->your_ip,4);
522         memset((char *)&dhcpdata->server_ip,0,4);
523         memset((char *)&dhcpdata->router_ip,0,4);
524         cookie = ecl(STANDARD_MAGIC_COOKIE);
525         memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4);
526         memcpy((char *)dhcpdata->client_macaddr, (char *)BinEnetAddr,6);
527
528         dhcpOptionsBase = (uchar *)(dhcpdata+1);
529         dhcpOptions = dhcpOptionsBase;
530         *dhcpOptions++ = DHCPOPT_MESSAGETYPE;
531         *dhcpOptions++ = 1;
532         *dhcpOptions++ = DHCPREQUEST;
533
534         *dhcpOptions++ = DHCPOPT_SERVERID;              /* Server id ID */
535         *dhcpOptions++ = 4;
536         op = DhcpGetOption(DHCPOPT_SERVERID,(uchar *)(dhdr+1));
537         if (op)
538                 memcpy((char *)dhcpOptions, (char *)op+2,4);
539         else
540                 memset((char *)dhcpOptions, (char)0,4);
541         dhcpOptions+=4;
542
543         *dhcpOptions++ = DHCPOPT_REQUESTEDIP;           /* Requested IP */
544         *dhcpOptions++ = 4;
545         memcpy((char *)dhcpOptions,(char *)&dhdr->your_ip,4);
546         dhcpOptions += 4;
547         dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions);
548         *dhcpOptions++ = 0xff;
549
550         /* See note in SendDHCPDiscover() regarding the computation of the
551          * ip and udp lengths.
552          */
553         optlen = dhcpOptions - dhcpOptionsBase;
554         if (optlen < 64)
555                 optlen = 64;
556         uh_ulen = sizeof(struct Udphdr) + sizeof(struct dhcphdr) + optlen;
557         tu->uh_ulen = ecs(uh_ulen);
558         ti->ip_len = ecs((sizeof(struct ip) + uh_ulen));
559
560         ipChksum(ti);           /* Compute checksum of ip hdr */
561         udpChksum(ti);          /* Compute UDP checksum */
562
563         DHCPState = DHCPSTATE_REQUEST;
564         sendBuffer(DHCPSIZE+optlen);
565         return(0);
566 }
567
568 /* randomDhcpStartupDelay():
569  *      Randomize the startup for DHCP/BOOTP (see RFC2131 Sec 4.4.1)...
570  *      Return a value between 1 and 10 based on the last 4 bits of the 
571  *      board's MAC address.
572  *      The presence of the DHCPSTARTUPDELAY shell variable overrides
573  *      this random value.
574  */
575 int
576 randomDhcpStartupDelay()
577 {
578         char *env;
579         int     randomsec;
580
581         env = getenv("DHCPSTARTUPDELAY");
582         if (env) {
583                 randomsec = (int)strtol(env,0,0);
584         }
585         else {
586                 randomsec = (BinEnetAddr[5] & 0xf);
587                 if (randomsec > 10)
588                         randomsec -= 7;
589                 else if (randomsec == 0)
590                         randomsec = 10;
591         }
592         return(randomsec);
593 }
594
595 /* dhcpStateCheck():
596  *      Called by pollethernet() to monitor the progress of DHCPState.
597  *      The retry rate is "almost" what is specified in the RFC...
598  *      Refer to the RetransmitDelay() function for details.
599  *
600  *      Regarding timing...
601  *      The DHCP startup may be running without an accurate measure of elapsed
602  *      time.  The value of LoopsPerMillisecond is used as an approximation of
603  *      the number of times this function must be called for one second to 
604  *      pass (dependent on network traffic, etc...).  RetransmitDelay() is
605  *      called to retrieve the number of seconds that must elapse prior to 
606  *      retransmitting the last DHCP message.  The static variables in this
607  *      function are used to keep track of that timeout.
608  */
609 void
610 dhcpStateCheck(void)
611 {
612         int delaysecs;
613
614         /* If the DHCP command has been issued, it is assumed that the script
615          * is handling retries...
616          */
617         if (DHCPCommandIssued)
618                 return;
619
620         /* Return, restart or fall through; depending on DHCPState... */
621         switch(DHCPState) {
622                 case DHCPSTATE_NOTUSED:
623                 case BOOTPSTATE_COMPLETE:
624                 case DHCPSTATE_BOUND:
625                         return;
626                 case DHCPSTATE_RESTART:
627                         DHCPStartup(0);
628                         return;
629                 case BOOTPSTATE_RESTART:
630                         BOOTPStartup(0);
631                         return;
632                 case DHCPSTATE_INITIALIZE:
633                 case BOOTPSTATE_INITIALIZE:
634                         delaysecs = randomDhcpStartupDelay();
635                         startElapsedTimer(&dhcpTmr,delaysecs * 1000);
636 #if INCLUDE_ETHERVERBOSE
637                         if (EtherVerbose & SHOW_DHCP)
638                                 printf("\nDHCP/BOOTP %d sec startup delay...\n",delaysecs);
639 #endif
640                         if (DHCPState & BOOTP_MODE)
641                                 DHCPState = BOOTPSTATE_INITDELAY;
642                         else
643                                 DHCPState = DHCPSTATE_INITDELAY;
644                         return;
645                 case DHCPSTATE_INITDELAY:
646                 case BOOTPSTATE_INITDELAY:
647                         if (msecElapsed(&dhcpTmr) || (gotachar())) {
648                                 DHCPElapsedSecs = 0;
649                                 startElapsedTimer(&dhcpTmr,
650                                         RetransmitDelay(DELAY_INIT_DHCP)*1000);
651                                 if (DHCPState & BOOTP_MODE)
652                                         BOOTPStartup(0);
653                                 else
654                                         DHCPStartup(0);
655                         }
656                         return;
657                 default:
658                         break;
659         }
660
661         if (msecElapsed(&dhcpTmr)) {
662                 int lastdelay;
663                 
664                 lastdelay = RetransmitDelay(DELAY_RETURN);
665                 delaysecs = RetransmitDelay(DELAY_INCREMENT);
666                 
667                 if (delaysecs != RETRANSMISSION_TIMEOUT) {
668                         DHCPElapsedSecs += delaysecs;
669                         startElapsedTimer(&dhcpTmr,delaysecs*1000);
670
671                         if (DHCPState & BOOTP_MODE)
672                                 BOOTPStartup(DHCPElapsedSecs);
673                         else
674                                 DHCPStartup(DHCPElapsedSecs);
675 #if INCLUDE_ETHERVERBOSE
676                         if (EtherVerbose & SHOW_DHCP)
677                                 printf("  DHCP/BOOTP retry (%d secs)\n",lastdelay);
678 #endif
679                 }
680                 else {
681 #if INCLUDE_ETHERVERBOSE
682                         if (EtherVerbose & SHOW_DHCP)
683                                 printf("  DHCP/BOOTP giving up\n");
684 #endif
685                 }
686         }
687 }
688
689 /* xidCheck():
690  *      Common function used for DHCP and BOOTP to verify incoming transaction
691  *      id...
692  */
693 int
694 xidCheck(char *id,int bootp)
695 {
696         if (memcmp(id,(char *)&DHCPTransactionId,4)) {
697 #if INCLUDE_ETHERVERBOSE
698                 if (EtherVerbose & SHOW_DHCP) {
699                         printf("%s ignored: unexpected transaction id.\n",
700                                 bootp ? "BOOTP":"DHCP");
701                 }
702 #endif
703                 return(-1);
704         }
705         return(0);
706 }
707
708 int
709 loadBootFile(int bootp)
710 {
711 #if INCLUDE_TFTP
712         ulong   addr;
713         char    bfile[TFSNAMESIZE+TFSINFOSIZE+32];
714         char    *tfsfile, *bootfile, *tftpsrvr, *flags, *info;
715
716         /* If the DHCPDONTBOOT variable is present, then don't put
717          * the file in TFS and don't run it.  Just complete the TFTP
718          * transfer, and allow the user to deal with the downloaded
719          * data using APPRAMBASE and TFTPGET shell variables (probably
720          * through some boot script).
721          */
722         if (getenv("DHCPDONTBOOT"))
723                 tfsfile = (char *)0;
724         else
725                 tfsfile = bfile;
726
727         /* If both bootfile and server-ip are specified, then boot it.
728          * The name of the file must contain information that tells the monitor
729          * what type of file it is, so the first 'comma' extension is used as
730          * the flag field (if it is a valid flag set) and the second 'comma'
731          * extension is used as the info field.
732          */
733         bootfile = getenv("BOOTFILE");
734         tftpsrvr = getenv("BOOTSRVR");
735
736         if (bootfile && tftpsrvr) {
737                 int     tftpworked;
738
739                 addr = getAppRamStart();
740                 info = "";
741                 flags = "e";
742                 strncpy(bfile,bootfile,sizeof(bfile));
743
744                 if (tfsfile) {
745                         char *icomma, *fcomma;
746
747                         fcomma = strchr(bfile,',');
748                         if (fcomma) {
749                                 icomma = strchr(fcomma+1,',');
750                                 if (icomma) {
751                                         *icomma = 0;
752                                         info = icomma+1;
753                                 }
754                                 *fcomma = 0;
755                                 if (tfsctrl(TFS_FATOB,(long)(fcomma+1),0) != 0)
756                                         flags = fcomma+1;
757                         }
758                 }
759
760                 /* Since we are about to transition to TFTP, match TFTP's
761                  * verbosity to the verbosity currently set for DHCP...
762                  */
763 #if INCLUDE_ETHERVERBOSE
764                 if (EtherVerbose & SHOW_DHCP)
765                         EtherVerbose |= SHOW_TFTP_STATE;
766 #endif
767
768                 /* If the TFTP transfer succeeds, attempt to run the boot file;
769                  * if the TFTP transfer fails, then re-initialize the tftp state
770                  * and set the DHCP state such that dhcpStateCheck() will
771                  * cause the handshake to start over again...
772                  */
773                 tftpworked = tftpGet(addr,tftpsrvr,"octet",bfile,tfsfile,flags,info);
774                 if (tftpworked) {
775 #if INCLUDE_ETHERVERBOSE
776                         EtherVerbose = 0;
777 #endif
778                         if (tfsfile) {
779                                 int     err;
780                                 char *argv[2];
781
782                                 argv[0] = bfile;
783                                 argv[1] = 0;
784                                 err = tfsrun(argv,0);
785                                 if (err != TFS_OKAY) 
786                                         printf("DHCP-invoked tfsrun(%s) failed: %s\n",
787                                                 bfile,tfserrmsg(err));
788                         }
789                 }
790                 else {
791                         tftpInit();
792                         RetransmitDelay(DELAY_INIT_TFTP);
793 #if INCLUDE_ETHERVERBOSE
794                         EtherVerbose &= ~SHOW_TFTP_STATE;
795 #endif
796                         if (bootp)
797                                 DHCPState = BOOTPSTATE_RESTART;
798                         else
799                                 DHCPState = DHCPSTATE_RESTART;
800                 }
801         }
802 #if INCLUDE_ETHERVERBOSE
803         else
804                 EtherVerbose &= ~(SHOW_DHCP|DHCP_VERBOSE);
805 #endif
806 #endif
807         return(0);
808 }
809
810 /* processBOOTP():
811  *      A subset of processDHCP().
812  *      We get here from processDHCP, because it detects that the current
813  *      value of DHCPState is BOOTPSTATE_REQUEST.
814  */
815 int
816 processBOOTP(ehdr,size)
817 struct ether_header *ehdr;
818 ushort size;
819 {
820         struct  ip *ihdr;
821         struct  Udphdr *uhdr;
822         struct  bootphdr *bhdr;
823         ulong   ip, temp_ip, cookie;
824         uchar   buf[16], *op;
825
826 #if INCLUDE_ETHERVERBOSE
827         if (EtherVerbose & SHOW_HEX)
828                 printMem((uchar *)ehdr,size,EtherVerbose & SHOW_ASCII);
829 #endif
830
831         ihdr = (struct ip *)(ehdr + 1);
832         uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));
833         bhdr = (struct bootphdr *)(uhdr+1);
834
835         /* Verify incoming transaction id matches the previous outgoing value: */
836         if (xidCheck((char *)&bhdr->transaction_id,1) < 0)
837                 return(-1);
838
839         /* If bootfile is nonzero, store it into BOOTFILE shell var: */
840         if (bhdr->bootfile[0])
841                 DhcpSetEnv("BOOTFILE", (char *)bhdr->bootfile);
842
843         /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */
844         memcpy((char *)&temp_ip,(char *)&bhdr->server_ip,4);
845         if (temp_ip)
846                 DhcpSetEnv("BOOTSRVR",(char *)IpToString(temp_ip,(char *)buf));
847
848         /* Assign IP "router_ip" to the RLYAGNT shell var (if non-zero): */
849         memcpy((char *)&temp_ip,(char *)&bhdr->router_ip,4);
850         if (temp_ip)
851                 DhcpSetEnv("RLYAGNT",(char *)IpToString(temp_ip,(char *)buf));
852
853         /* Assign IP address loaded in "your_ip" to the IPADD shell var: */
854         memcpy((char *)BinIpAddr,(char *)&bhdr->your_ip,4);
855         memcpy((char *)&temp_ip,(char *)&bhdr->your_ip,4);
856         DhcpSetEnv("IPADD",(char *)IpToString(temp_ip,(char *)buf));
857
858         /* If STANDARD_MAGIC_COOKIE exists, then process options... */
859         memcpy((char *)&cookie,(char *)bhdr->vsa,4);
860         if (cookie == ecl(STANDARD_MAGIC_COOKIE)) {
861                 /* Assign subnet mask option to NETMASK shell var (if found): */
862                 op = DhcpGetOption(DHCPOPT_SUBNETMASK,&bhdr->vsa[4]);
863                 if (op) {
864                         memcpy((char *)&ip,(char *)op+2,4);
865                         DhcpSetEnv("NETMASK",(char *)IpToString(ip,(char *)buf));
866                 }
867                 /* Assign first router option to GIPADD shell var (if found): */
868                 /* (the router option can have multiple entries, and they are */
869                 /* supposed to be in order of preference, so use the first one) */
870                 op = DhcpGetOption(DHCPOPT_ROUTER,&bhdr->vsa[4]);
871                 if (op) {
872                         memcpy((char *)&ip, (char *)op+2,4);
873                         DhcpSetEnv("GIPADD",(char *)IpToString(ip,(char *)buf));
874                 }
875         }
876
877         DhcpBootpDone(1,(struct dhcphdr *)bhdr,
878                 size - ((int)((int)&bhdr->vsa - (int)ehdr)));
879
880         DHCPState = BOOTPSTATE_COMPLETE;
881
882         /* Call loadBootFile() which will then kick off a tftp client
883          * transfer if both BOOTFILE and BOOTSRVR shell variables are
884          * loaded; otherwise, we are done.
885          */
886         loadBootFile(1);
887
888         return(0);
889 }
890
891 int
892 processDHCP(struct ether_header *ehdr,ushort size)
893 {
894         struct  ip *ihdr;
895         struct  Udphdr *uhdr;
896         struct  dhcphdr *dhdr;
897         uchar   buf[16], *op, msgtype;
898         ulong   ip, temp_ip, leasetime;
899
900         if (DHCPState == BOOTPSTATE_REQUEST)
901                 return(processBOOTP(ehdr,size));
902
903 #if INCLUDE_ETHERVERBOSE
904         if (EtherVerbose & SHOW_HEX)
905                 printMem((uchar *)ehdr,size,EtherVerbose & SHOW_ASCII);
906 #endif
907
908         ihdr = (struct ip *)(ehdr + 1);
909         uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));
910         dhdr = (struct dhcphdr *)(uhdr+1);
911
912         /* Verify incoming transaction id matches the previous outgoing value: */
913         if (xidCheck((char *)&dhdr->transaction_id,0) < 0)
914                 return(-1);
915
916         op = DhcpGetOption(DHCPOPT_MESSAGETYPE,(uchar *)(dhdr+1));
917         if (op)
918                 msgtype = *(op+2);
919         else
920                 msgtype = DHCPUNKNOWN;
921
922         if ((DHCPState == DHCPSTATE_SELECT) && (msgtype == DHCPOFFER)) {
923                 /* Target issued the DISCOVER, the incoming packet is the server's
924                  * OFFER reply.  The function "ValidDHCPOffer() will return
925                  * non-zero if the request is to be sent.
926                  */
927                 if (ValidDHCPOffer(dhdr))
928                         SendDHCPRequest(dhdr);
929 #if INCLUDE_ETHERVERBOSE
930                 else if (EtherVerbose & SHOW_DHCP) {
931                         char ip[4];
932                         memcpy(ip,(char *)&ihdr->ip_src,4);
933                         printf("  DHCP offer from %d.%d.%d.%d ignored\n",
934                                 ip[0],ip[1],ip[2],ip[3]);
935                 }
936 #endif
937         }
938         else if ((DHCPState == DHCPSTATE_REQUEST) && (msgtype == DHCPACK)) {
939                 ulong   cookie;
940                 char    ipsrc[4];
941
942                 /* Target issued the REQUEST, the incoming packet is the server's
943                  * ACK reply.  We're done so load the environment now.
944                  */
945                 memcpy(ipsrc,(char *)&ihdr->ip_src,4);
946                 shell_sprintf("DHCPOFFERFROM","%d.%d.%d.%d",
947                         ipsrc[0],ipsrc[1],ipsrc[2],ipsrc[3]);
948
949                 /* If bootfile is nonzero, store it into BOOTFILE shell var: */
950                 if (dhdr->bootfile[0])
951                         DhcpSetEnv("BOOTFILE",(char *)dhdr->bootfile);
952
953                 /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */
954                 memcpy((char *)&temp_ip,(char *)&dhdr->server_ip,4);
955                 if (temp_ip)
956                         DhcpSetEnv("BOOTSRVR",(char *)IpToString(temp_ip,(char *)buf));
957
958                 /* Assign IP "router_ip" to the RLYAGNT shell var (if non-zero): */
959                 memcpy((char *)&temp_ip,(char *)&dhdr->router_ip,4);
960                 if (temp_ip)
961                         DhcpSetEnv("RLYAGNT",(char *)IpToString(temp_ip,(char *)buf));
962
963                 /* Assign IP address loaded in "your_ip" to the IPADD shell var: */
964                 memcpy((char *)BinIpAddr,(char *)&dhdr->your_ip,4);
965                 memcpy((char *)&temp_ip,(char *)&dhdr->your_ip,4);
966                 DhcpSetEnv("IPADD",IpToString(temp_ip,(char *)buf));
967
968                 op = DhcpGetOption(DHCPOPT_ROOTPATH,(uchar *)(dhdr+1));
969                 if (op) 
970                         DhcpSetEnv("ROOTPATH",(char *)op+2);
971
972                 /* If STANDARD_MAGIC_COOKIE exists, process options... */
973                 memcpy((char *)&cookie,(char *)&dhdr->magic_cookie,4);
974                 if (cookie == ecl(STANDARD_MAGIC_COOKIE)) {
975                         /* Assign subnet mask to NETMASK shell var (if found): */
976                         op = DhcpGetOption(DHCPOPT_SUBNETMASK,(uchar *)(dhdr+1));
977                         if (op) {
978                                 memcpy((char *)&ip,(char *)op+2,4);
979                                 DhcpSetEnv("NETMASK",(char *)IpToString(ip,(char *)buf));
980                         }
981
982                         /* Assign gateway IP to GIPADD shell var (if found):
983                          * (the router option can have multiple entries, and they are
984                          * supposed to be in order of preference, so use the first one).
985                          */
986                         op = DhcpGetOption(DHCPOPT_ROUTER,(uchar *)(dhdr+1));
987                         if (op) {
988                                 memcpy((char *)&ip,(char *)op+2,4);
989                                 DhcpSetEnv("GIPADD",(char *)IpToString(ip,(char *)buf));
990                         }
991                         /* Process DHCPOPT_LEASETIME option as follows...
992                          * If not set, assume infinite and clear DHCPLEASETIME shellvar.
993                          * If set, then look for the presence of the DHCPLEASETIME shell
994                          * variable and use it as a minimum.  If the incoming value is
995                          * >= what is in the shell variable, accept it and load the shell
996                          * variable with this value. If incoming lease time is less than
997                          * what is stored in DHCPLEASETIME, ignore the request.
998                          * If DHCPLEASETIME is not set, then just load the incoming lease
999                          * into the DHCPLEASETIME shell variable and accept the offer.
1000                          */
1001                         op = DhcpGetOption(DHCPOPT_LEASETIME,(uchar *)(dhdr+1));
1002                         if (op) {
1003                                 memcpy((char *)&leasetime,(char *)op+2,4);
1004                                 leasetime = ecl(leasetime);
1005                                 if (getenv("DHCPLEASETIME")) {
1006                                         ulong   minleasetime;
1007                                         minleasetime = strtol(getenv("DHCPLEASETIME"),0,0);
1008                                         if (leasetime < minleasetime) {
1009                                                 printf("DHCP: incoming lease time 0x%lx too small.\n",
1010                                                         leasetime);
1011                                                 return(-1);
1012                                         }
1013                                 }
1014                                 sprintf((char *)buf,"0x%lx",leasetime);
1015                                 setenv("DHCPLEASETIME",(char *)buf);
1016                         }
1017                         else
1018                                 setenv("DHCPLEASETIME",(char *)0);
1019                 }
1020
1021                 /* Check for vendor specific stuff... */
1022                 DhcpVendorSpecific(dhdr);
1023
1024                 DhcpBootpDone(0,dhdr,
1025                         size - ((int)((int)&dhdr->magic_cookie - (int)ehdr)));
1026
1027                 DHCPState = DHCPSTATE_BOUND;
1028
1029                 /* Call loadBootFile() which will then kick off a tftp client
1030                  * transfer if both BOOTFILE and BOOTSRVR shell variables are
1031                  * loaded; otherwise, we are done.
1032                  */
1033                 loadBootFile(0);
1034         }
1035         return(0);
1036 }
1037
1038 char *
1039 DHCPop(op)
1040 int     op;
1041 {
1042         switch(op) {
1043         case DHCPBOOTP_REQUEST:
1044                 return("REQUEST");
1045         case DHCPBOOTP_REPLY:
1046                 return("REPLY");
1047         default:
1048                 return("???");
1049         }
1050 }
1051
1052 char *
1053 DHCPmsgtype(int msg)
1054 {
1055         char *type;
1056
1057         switch(msg) {
1058         case DHCPDISCOVER:
1059                 type = "DISCOVER";
1060                 break;
1061         case DHCPOFFER:
1062                 type = "OFFER";
1063                 break;
1064         case DHCPREQUEST:
1065                 type = "REQUEST";
1066                 break;
1067         case DHCPDECLINE:
1068                 type = "DECLINE";
1069                 break;
1070         case DHCPACK:
1071                 type = "ACK";
1072                 break;
1073         case DHCPNACK:
1074                 type = "NACK";
1075                 break;
1076         case DHCPRELEASE:
1077                 type = "RELEASE";
1078                 break;
1079         case DHCPINFORM:
1080                 type = "INFORM";
1081                 break;
1082         case DHCPFORCERENEW:
1083                 type = "FORCERENEW";
1084                 break;
1085         case DHCPLEASEQUERY:
1086                 type = "LEASEQUERY";
1087                 break;
1088         case DHCPLEASEUNASSIGNED:
1089                 type = "LEASEUNASSIGNED";
1090                 break;
1091         case DHCPLEASEUNKNOWN:
1092                 type = "LEASEUNKNOWN";
1093                 break;
1094         case DHCPLEASEACTIVE:
1095                 type = "LEASEACTIVE";
1096                 break;
1097         default:
1098                 type = "???";
1099                 break;
1100         }
1101         return(type);
1102 }
1103
1104 /* printDhcpOptions():
1105  *      Verbosely display the DHCP options pointed to by the incoming
1106  *      options pointer.
1107  */
1108 void
1109 printDhcpOptions(uchar *options)
1110 {
1111         int     i, safety, opt, optlen;
1112
1113         safety = 0;
1114         while(*options != 0xff) {
1115                 if (safety++ > 10000) {
1116                         printf("Aborting, overflow likely\n");
1117                         break;
1118                 }
1119                 opt = (int)*options++;
1120                 if (opt == 0)   /* padding */
1121                         continue;
1122                 printf("    option %3d: ",opt);
1123                 optlen = (int)*options++;
1124                 if (opt==DHCPOPT_MESSAGETYPE) {
1125                         printf("DHCP_%s",DHCPmsgtype(*options++));
1126                 }
1127                 else if ((opt < DHCPOPT_HOSTNAME) ||
1128                     (opt == DHCPOPT_BROADCASTADDRESS) ||
1129                     (opt == DHCPOPT_REQUESTEDIP) ||
1130                     (opt == DHCPOPT_SERVERID) ||
1131                     (opt == DHCPOPT_NISSERVER)) {
1132                         for(i=0;i<optlen;i++)
1133                                 printf("%d ",*options++);
1134                 }
1135                 else if ((opt == DHCPOPT_NISDOMAINNAME) || (opt == DHCPOPT_CLASSID)) {
1136                         for(i=0;i<optlen;i++)
1137                                 printf("%c",*options++);
1138                 }
1139                 else if (opt == DHCPOPT_CLIENTID) {
1140                         printf("%d 0x",(int)*options++);
1141                         for(i=1;i<optlen;i++)
1142                                 printf("%02x",*options++);
1143                 }
1144                 else {
1145                         printf("0x");
1146                         for(i=0;i<optlen;i++)
1147                                 printf("%02x",*options++);
1148                 }
1149                 printf("\n");
1150         }
1151 }
1152
1153 /* printDhcp():
1154  *      Try to format the DHCP stuff...
1155  */
1156 void
1157 printDhcp(struct Udphdr *p)
1158 {
1159         struct  dhcphdr *d;
1160         uchar   *client_ip, *your_ip, *server_ip, *router_ip;
1161         ulong   cookie, xid;
1162
1163         d = (struct dhcphdr *)(p+1);
1164
1165         client_ip = (uchar *)&(d->client_ip);
1166         your_ip = (uchar *)&(d->your_ip);
1167         server_ip = (uchar *)&(d->server_ip);
1168         router_ip = (uchar *)&(d->router_ip);
1169         memcpy((char *)&xid,(char *)&d->transaction_id,4);
1170         /* xid = ecl(xid) */
1171
1172         printf("  DHCP: sport dport ulen  sum\n");
1173         printf("        %4d  %4d %4d %4d\n",
1174                 ecs(p->uh_sport), ecs(p->uh_dport), ecs(p->uh_ulen),ecs(p->uh_sum));
1175         printf("    op = %s, htype = %d, hlen = %d, hops = %d\n",
1176             DHCPop(d->op),d->htype,d->hlen,d->hops);
1177         printf("    seconds = %d, flags = 0x%x, xid= 0x%lx\n",
1178                 ecs(d->seconds),ecs(d->flags),xid);
1179         printf("    client_macaddr = %02x:%02x:%02x:%02x:%02x:%02x\n",
1180             d->client_macaddr[0], d->client_macaddr[1],
1181             d->client_macaddr[2], d->client_macaddr[3],
1182             d->client_macaddr[4], d->client_macaddr[5]);
1183         printf("    client_ip = %d.%d.%d.%d\n",
1184             client_ip[0],client_ip[1],client_ip[2],client_ip[3]);
1185         printf("    your_ip =   %d.%d.%d.%d\n",
1186             your_ip[0],your_ip[1],your_ip[2],your_ip[3]);
1187         printf("    server_ip = %d.%d.%d.%d\n",
1188             server_ip[0],server_ip[1],server_ip[2],server_ip[3]);
1189         printf("    router_ip = %d.%d.%d.%d\n",
1190             router_ip[0],router_ip[1],router_ip[2],router_ip[3]);
1191         if (d->bootfile[0])
1192                 printf("    bootfile: %s\n", d->bootfile);
1193         if (d->server_hostname[0])
1194                 printf("    server_hostname: %s\n", d->server_hostname);
1195
1196         /* If STANDARD_MAGIC_COOKIE doesn't exist, then don't process options... */
1197         memcpy((char *)&cookie,(char *)&d->magic_cookie,4);
1198         if (cookie != ecl(STANDARD_MAGIC_COOKIE))
1199                 return;
1200
1201         printDhcpOptions((uchar *)(d+1));
1202 }
1203
1204 /* DhcpGetOption():
1205  *      Based on the incoming option pointer and a specified option value,
1206  *      search through the options list for the value and return a pointer
1207  *      to that option.
1208  */
1209 uchar *
1210 DhcpGetOption(unsigned char optval,unsigned char *options)
1211 {
1212         int             safety;
1213
1214         safety = 0;
1215         while(*options != 0xff) {
1216                 if (safety++ > 1000)
1217                         break;
1218                 if (*options == 0) {    /* Skip over padding. */
1219                         options++;
1220                         continue;
1221                 }
1222                 if (*options == optval)
1223                         return(options);
1224                 options += ((*(options+1)) + 2);
1225         }
1226         return((uchar *)0);
1227 }
1228
1229 int
1230 DhcpSetEnv(char *name,char *value)
1231 {
1232 #if INCLUDE_ETHERVERBOSE
1233         if (EtherVerbose & SHOW_DHCP)
1234                 printf("  Dhcp/Bootp SetEnv: %s = %s\n",name,value);
1235 #endif
1236         return(setenv(name,value));
1237 }
1238
1239 int
1240 DhcpIPCheck(char *ipadd)
1241 {
1242         char    verbose;
1243
1244         if (!memcmp(ipadd,"DHCP",4)) {
1245                 verbose = ipadd[4];
1246                 DHCPState = DHCPSTATE_INITIALIZE;
1247         }
1248         else if (!memcmp(ipadd,"BOOTP",5)) {
1249                 verbose = ipadd[5];
1250                 DHCPState = BOOTPSTATE_INITIALIZE;
1251         }
1252         else {
1253                 if (IpToBin(ipadd,BinIpAddr) < 0) {
1254                         verbose = 0;
1255                         DHCPState = BOOTPSTATE_INITIALIZE;
1256                 }
1257                 else {
1258                         DHCPState = DHCPSTATE_NOTUSED;
1259                         return(0);
1260                 }
1261         }
1262
1263         BinIpAddr[0] = 0; 
1264         BinIpAddr[1] = 0;
1265         BinIpAddr[2] = 0; 
1266         BinIpAddr[3] = 0;
1267 #if INCLUDE_ETHERVERBOSE
1268         if (verbose == 'V')
1269                 EtherVerbose = DHCP_VERBOSE;
1270         else if (verbose == 'v')
1271                 EtherVerbose = SHOW_DHCP;
1272 #endif
1273         return(0);
1274 }
1275
1276 char *
1277 dhcpStringState(int state)
1278 {
1279         switch(state) {
1280                 case DHCPSTATE_INITIALIZE:
1281                         return("DHCP_INITIALIZE");
1282                 case DHCPSTATE_SELECT:
1283                         return("DHCP_SELECT");
1284                 case DHCPSTATE_REQUEST:
1285                         return("DHCP_REQUEST");
1286                 case DHCPSTATE_BOUND:
1287                         return("DHCP_BOUND");
1288                 case DHCPSTATE_RENEW:
1289                         return("DHCP_RENEW");
1290                 case DHCPSTATE_REBIND:
1291                         return("DHCP_REBIND");
1292                 case DHCPSTATE_NOTUSED:
1293                         return("DHCP_NOTUSED");
1294                 case DHCPSTATE_RESTART:
1295                         return("DHCP_RESTART");
1296                 case BOOTPSTATE_INITIALIZE:
1297                         return("BOOTP_INITIALIZE");
1298                 case BOOTPSTATE_REQUEST:
1299                         return("BOOTP_REQUEST");
1300                 case BOOTPSTATE_RESTART:
1301                         return("BOOTP_RESTART");
1302                 case BOOTPSTATE_COMPLETE:
1303                         return("BOOTP_COMPLETE");
1304                 default:
1305                         return("???");
1306         }
1307 }
1308
1309 void
1310 ShowDhcpStats()
1311 {
1312         printf("Current DHCP State: %s\n",dhcpStringState(DHCPState));
1313 }
1314
1315 #endif