Patch by Travis Sawyer, 30 Dec 2003:
[pandora-u-boot.git] / net / bootp.c
1 /*
2  *      Based on LiMon - BOOTP.
3  *
4  *      Copyright 1994, 1995, 2000 Neil Russell.
5  *      (See License)
6  *      Copyright 2000 Roland Borde
7  *      Copyright 2000 Paolo Scaffardi
8  *      Copyright 2000-2002 Wolfgang Denk, wd@denx.de
9  */
10
11 #if 0
12 #define DEBUG           1       /* general debug */
13 #define DEBUG_BOOTP_EXT 1       /* Debug received vendor fields */
14 #endif
15
16 #ifdef DEBUG_BOOTP_EXT
17 #define debug_ext(fmt,args...)  printf (fmt ,##args)
18 #else
19 #define debug_ext(fmt,args...)
20 #endif
21
22 #include <common.h>
23 #include <command.h>
24 #include <net.h>
25 #include "bootp.h"
26 #include "tftp.h"
27 #ifdef CONFIG_STATUS_LED
28 #include <status_led.h>
29 #endif
30
31 #define BOOTP_VENDOR_MAGIC      0x63825363      /* RFC1048 Magic Cookie         */
32
33 #if (CONFIG_COMMANDS & CFG_CMD_NET)
34
35 #define TIMEOUT         5               /* Seconds before trying BOOTP again    */
36 #ifndef CONFIG_NET_RETRY_COUNT
37 # define TIMEOUT_COUNT  5               /* # of timeouts before giving up  */
38 #else
39 # define TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT)
40 #endif
41
42 #define PORT_BOOTPS     67              /* BOOTP server UDP port                */
43 #define PORT_BOOTPC     68              /* BOOTP client UDP port                */
44
45 #ifndef CONFIG_DHCP_MIN_EXT_LEN         /* minimal length of extension list     */
46 #define CONFIG_DHCP_MIN_EXT_LEN 64
47 #endif
48
49 ulong           BootpID;
50 int             BootpTry;
51 #ifdef CONFIG_BOOTP_RANDOM_DELAY
52 ulong           seed1, seed2;
53 #endif
54
55 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
56 dhcp_state_t dhcp_state = INIT;
57 unsigned long dhcp_leasetime = 0;
58 IPaddr_t NetDHCPServerIP = 0;
59 static void DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len);
60
61 /* For Debug */
62 #if 0
63 static char *dhcpmsg2str(int type)
64 {
65         switch (type) {
66         case 1:  return "DHCPDISCOVER"; break;
67         case 2:  return "DHCPOFFER";    break;
68         case 3:  return "DHCPREQUEST";  break;
69         case 4:  return "DHCPDECLINE";  break;
70         case 5:  return "DHCPACK";      break;
71         case 6:  return "DHCPNACK";     break;
72         case 7:  return "DHCPRELEASE";  break;
73         default: return "UNKNOWN/INVALID MSG TYPE"; break;
74         }
75 }
76 #endif
77
78 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
79 extern u8 *dhcp_vendorex_prep (u8 *e); /*rtn new e after add own opts. */
80 extern u8 *dhcp_vendorex_proc (u8 *e); /*rtn next e if mine,else NULL  */
81 #endif
82
83 #endif  /* CFG_CMD_DHCP */
84
85 static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
86 {
87         Bootp_t *bp = (Bootp_t *) pkt;
88         int retval = 0;
89
90         if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
91                 retval = -1;
92         else if (len < sizeof (Bootp_t) - OPT_SIZE)
93                 retval = -2;
94         else if (bp->bp_op != OP_BOOTREQUEST &&
95             bp->bp_op != OP_BOOTREPLY &&
96             bp->bp_op != DHCP_OFFER &&
97             bp->bp_op != DHCP_ACK &&
98             bp->bp_op != DHCP_NAK ) {
99                 retval = -3;
100         }
101         else if (bp->bp_htype != HWT_ETHER)
102                 retval = -4;
103         else if (bp->bp_hlen != HWL_ETHER)
104                 retval = -5;
105         else if (NetReadLong((ulong*)&bp->bp_id) != BootpID) {
106                 retval = -6;
107         }
108
109         debug ("Filtering pkt = %d\n", retval);
110
111         return retval;
112 }
113
114 /*
115  * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
116  */
117 static void BootpCopyNetParams(Bootp_t *bp)
118 {
119         NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
120         NetCopyIP(&NetServerIP, &bp->bp_siaddr);
121         memcpy (NetServerEther, ((Ethernet_t *)NetRxPkt)->et_src, 6);
122         copy_filename (BootFile, bp->bp_file, sizeof(BootFile));
123
124         debug ("Bootfile: %s\n", BootFile);
125
126         /* Propagate to environment:
127          * don't delete exising entry when BOOTP / DHCP reply does
128          * not contain a new value
129          */
130         if (*BootFile) {
131                 setenv ("bootfile", BootFile);
132         }
133 }
134
135 static int truncate_sz (const char *name, int maxlen, int curlen)
136 {
137         if (curlen >= maxlen) {
138                 printf("*** WARNING: %s is too long (%d - max: %d) - truncated\n",
139                         name, curlen, maxlen);
140                 curlen = maxlen - 1;
141         }
142         return (curlen);
143 }
144
145 #if !(CONFIG_COMMANDS & CFG_CMD_DHCP)
146
147 static void BootpVendorFieldProcess(u8 *ext)
148 {
149     int size = *(ext+1) ;
150
151     debug_ext ("[BOOTP] Processing extension %d... (%d bytes)\n", *ext, *(ext+1));
152
153     NetBootFileSize = 0;
154
155     switch (*ext) {
156     /* Fixed length fields */
157         case 1:         /* Subnet mask                                  */
158                 if (NetOurSubnetMask == 0)
159                         NetCopyIP(&NetOurSubnetMask, (IPaddr_t*)(ext+2));
160                 break;
161         case 2:         /* Time offset - Not yet supported              */
162                 break;
163     /* Variable length fields */
164         case 3:         /* Gateways list                                */
165                 if (NetOurGatewayIP == 0) {
166                         NetCopyIP(&NetOurGatewayIP, (IPaddr_t*)(ext+2));
167                 }
168                 break;
169         case 4:         /* Time server - Not yet supported              */
170                 break;
171         case 5:         /* IEN-116 name server - Not yet supported      */
172                 break;
173         case 6:
174                 if (NetOurDNSIP == 0) {
175                         NetCopyIP(&NetOurDNSIP, (IPaddr_t*)(ext+2));
176                 }
177 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
178                 if ((NetOurDNS2IP == 0) && (size > 4)) {
179                         NetCopyIP(&NetOurDNS2IP, (IPaddr_t*)(ext+2+4));
180                 }
181 #endif
182                 break;
183         case 7:         /* Log server - Not yet supported               */
184                 break;
185         case 8:         /* Cookie/Quote server - Not yet supported      */
186                 break;
187         case 9:         /* LPR server - Not yet supported               */
188                 break;
189         case 10:        /* Impress server - Not yet supported           */
190                 break;
191         case 11:        /* RPL server - Not yet supported               */
192                 break;
193         case 12:        /* Host name                                    */
194                 if (NetOurHostName[0] == 0) {
195                     size = truncate_sz("Host Name", sizeof(NetOurHostName), size);
196                     memcpy(&NetOurHostName, ext+2, size);
197                     NetOurHostName[size] = 0 ;
198                 }
199                 break;
200         case 13:        /* Boot file size                               */
201                 if (size == 2)
202                         NetBootFileSize = ntohs(*(ushort*)(ext+2));
203                 else if (size == 4)
204                         NetBootFileSize = ntohl(*(ulong*)(ext+2));
205                 break;
206         case 14:        /* Merit dump file - Not yet supported          */
207                 break;
208         case 15:        /* Domain name - Not yet supported              */
209                 break;
210         case 16:        /* Swap server - Not yet supported              */
211                 break;
212         case 17:        /* Root path                                    */
213                 if (NetOurRootPath[0] == 0) {
214                     size = truncate_sz("Root Path", sizeof(NetOurRootPath), size);
215                     memcpy(&NetOurRootPath, ext+2, size);
216                     NetOurRootPath[size] = 0 ;
217                 }
218                 break;
219         case 18:        /* Extension path - Not yet supported           */
220                 /*
221                  * This can be used to send the information of the
222                  * vendor area in another file that the client can
223                  * access via TFTP.
224                  */
225                 break;
226     /* IP host layer fields */
227         case 40:        /* NIS Domain name                              */
228                 if (NetOurNISDomain[0] == 0) {
229                     size = truncate_sz ("NIS Domain Name",
230                                         sizeof(NetOurNISDomain),
231                                         size);
232                     memcpy(&NetOurNISDomain, ext+2, size);
233                     NetOurNISDomain[size] = 0 ;
234                 }
235                 break;
236     /* Application layer fields */
237         case 43:        /* Vendor specific info - Not yet supported     */
238                 /*
239                  * Binary information to exchange specific
240                  * product information.
241                  */
242                 break;
243     /* Reserved (custom) fields (128..254) */
244     }
245 }
246
247 static void BootpVendorProcess(u8 *ext, int size)
248 {
249     u8 *end = ext + size ;
250
251     debug_ext ("[BOOTP] Checking extension (%d bytes)...\n", size);
252
253     while ((ext < end) && (*ext != 0xff)) {
254         if (*ext == 0) {
255             ext ++ ;
256         } else {
257                 u8 *opt = ext ;
258                 ext += ext[1] + 2 ;
259                 if (ext <= end)
260                     BootpVendorFieldProcess (opt) ;
261         }
262     }
263
264 #ifdef DEBUG_BOOTP_EXT
265     printf("[BOOTP] Received fields: \n");
266     if (NetOurSubnetMask) {
267         puts ("NetOurSubnetMask : ");
268         print_IPaddr (NetOurSubnetMask);
269         putc('\n');
270     }
271
272     if (NetOurGatewayIP) {
273         puts ("NetOurGatewayIP  : ");
274         print_IPaddr (NetOurGatewayIP);
275         putc('\n');
276     }
277
278     if (NetBootFileSize) {
279         printf("NetBootFileSize : %d\n", NetBootFileSize);
280     }
281
282     if (NetOurHostName[0]) {
283         printf("NetOurHostName  : %s\n", NetOurHostName);
284     }
285
286     if (NetOurRootPath[0]) {
287         printf("NetOurRootPath  : %s\n", NetOurRootPath);
288     }
289
290     if (NetOurNISDomain[0]) {
291         printf("NetOurNISDomain : %s\n", NetOurNISDomain);
292     }
293
294     if (NetBootFileSize) {
295         printf("NetBootFileSize: %d\n", NetBootFileSize);
296     }
297 #endif  /* DEBUG_BOOTP_EXT */
298 }
299
300 /*
301  *      Handle a BOOTP received packet.
302  */
303 static void
304 BootpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
305 {
306         Bootp_t *bp;
307         char    *s;
308
309         debug ("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%d)\n",
310                 src, dest, len, sizeof (Bootp_t));
311
312         bp = (Bootp_t *)pkt;
313
314         if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
315                 return;
316
317         /*
318          *      Got a good BOOTP reply.  Copy the data into our variables.
319          */
320 #ifdef CONFIG_STATUS_LED
321         status_led_set (STATUS_LED_BOOT, STATUS_LED_OFF);
322 #endif
323
324         BootpCopyNetParams(bp);         /* Store net parameters from reply */
325
326         /* Retrieve extended information (we must parse the vendor area) */
327         if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
328                 BootpVendorProcess(&bp->bp_vend[4], len);
329
330         NetSetTimeout(0, (thand_f *)0);
331
332         debug ("Got good BOOTP\n");
333
334         if (((s = getenv("autoload")) != NULL) && (*s == 'n')) {
335                 /*
336                  * Just use BOOTP to configure system;
337                  * Do not use TFTP to load the bootfile.
338                  */
339                 NetState = NETLOOP_SUCCESS;
340                 return;
341         }
342
343         TftpStart();
344 }
345 #endif  /* !CFG_CMD_DHCP */
346
347 /*
348  *      Timeout on BOOTP/DHCP request.
349  */
350 static void
351 BootpTimeout(void)
352 {
353         if (BootpTry >= TIMEOUT_COUNT) {
354                 puts ("\nRetry count exceeded; starting again\n");
355                 NetStartAgain ();
356         } else {
357                 NetSetTimeout (TIMEOUT * CFG_HZ, BootpTimeout);
358                 BootpRequest ();
359         }
360 }
361
362 /*
363  *      Initialize BOOTP extension fields in the request.
364  */
365 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
366 static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)
367 {
368     u8 *start = e ;
369     u8 *cnt;
370 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
371     u8 *x;
372 #endif
373 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME)
374     uchar *hostname;
375 #endif
376
377     *e++ =  99;         /* RFC1048 Magic Cookie */
378     *e++ = 130;
379     *e++ =  83;
380     *e++ =  99;
381
382     *e++ = 53;          /* DHCP Message Type */
383     *e++ = 1;
384     *e++ = message_type;
385
386     *e++ = 57;          /* Maximum DHCP Message Size */
387     *e++ = 2;
388     *e++ = (576-312+OPT_SIZE) >> 8;
389     *e++ = (576-312+OPT_SIZE) & 0xff;
390
391     if ( ServerID ) {
392             int tmp = ntohl(ServerID);
393
394             *e++ = 54;  /* ServerID */
395             *e++ = 4;
396             *e++ = tmp >> 24;
397             *e++ = tmp >> 16;
398             *e++ = tmp >> 8;
399             *e++ = tmp & 0xff;
400     }
401
402     if ( RequestedIP ) {
403             int tmp = ntohl(RequestedIP);
404
405             *e++ = 50;  /* Requested IP */
406             *e++ = 4;
407             *e++ = tmp >> 24;
408             *e++ = tmp >> 16;
409             *e++ = tmp >> 8;
410             *e++ = tmp & 0xff;
411     }
412
413 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME)
414     if ( (hostname = getenv("hostname")) ) {
415             int hostnamelen = strlen(hostname);
416             *e++ = 12;        /* Hostname */
417             *e++ = hostnamelen;
418             memcpy(e,hostname,hostnamelen);
419             e += hostnamelen;
420     }
421 #endif
422
423 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
424     if ((x = dhcp_vendorex_prep (e)))
425         return x - start ;
426 #endif
427
428     *e++ = 55;          /* Parameter Request List */
429     cnt  = e++;         /* Pointer to count of requested items */
430     *cnt = 0;
431 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
432     *e++ = 1;           /* Subnet Mask */
433     *cnt += 1;
434 #endif
435 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
436     *e++ = 3;           /* Router Option */
437     *cnt += 1;
438 #endif
439 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
440     *e++ = 6;           /* DNS Server(s) */
441     *cnt += 1;
442 #endif
443 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
444     *e++ = 12;          /* Hostname */
445     *cnt += 1;
446 #endif
447 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
448     *e++ = 13;          /* Boot File Size */
449     *cnt += 1;
450 #endif
451 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
452     *e++ = 17;          /* Boot path */
453     *cnt += 1;
454 #endif
455 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
456     *e++ = 40;          /* NIS Domain name request */
457     *cnt += 1;
458 #endif
459     *e++ = 255;         /* End of the list */
460
461     /* Pad to minimal length */
462 #ifdef  CONFIG_DHCP_MIN_EXT_LEN
463     while ((e - start) <= CONFIG_DHCP_MIN_EXT_LEN)
464         *e++ = 0;
465 #endif
466
467     return e - start ;
468 }
469
470 #else   /* CFG_CMD_DHCP */
471 /*
472  *      Warning: no field size check - change CONFIG_BOOTP_MASK at your own risk!
473  */
474 static int BootpExtended (u8 *e)
475 {
476     u8 *start = e ;
477
478     *e++ =  99;         /* RFC1048 Magic Cookie */
479     *e++ = 130;
480     *e++ =  83;
481     *e++ =  99;
482
483 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
484     *e++ = 53;          /* DHCP Message Type */
485     *e++ = 1;
486     *e++ = DHCP_DISCOVER;
487
488     *e++ = 57;          /* Maximum DHCP Message Size */
489     *e++ = 2;
490     *e++ = (576-312+OPT_SIZE) >> 16;
491     *e++ = (576-312+OPT_SIZE) & 0xff;
492 #endif  /* CFG_CMD_DHCP */
493
494 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
495     *e++ =  1;          /* Subnet mask request */
496     *e++ =  4;
497      e  +=  4;
498 #endif
499
500 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
501     *e++ =  3;          /* Default gateway request */
502     *e++ =  4;
503      e  +=  4;
504 #endif
505
506 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
507     *e++ =  6;          /* Domain Name Server */
508     *e++ =  4;
509      e  +=  4;
510 #endif
511
512 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
513     *e++ = 12;          /* Host name request */
514     *e++ = 32;
515      e  += 32;
516 #endif
517
518 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
519     *e++ = 13;          /* Boot file size */
520     *e++ =  2;
521      e  +=  2;
522 #endif
523
524 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
525     *e++ = 17;          /* Boot path */
526     *e++ = 32;
527      e  += 32;
528 #endif
529
530 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
531     *e++ = 40;          /* NIS Domain name request */
532     *e++ = 32;
533      e  += 32;
534 #endif
535
536     *e++ = 255;         /* End of the list */
537
538     return e - start ;
539 }
540 #endif  /* CFG_CMD_DHCP */
541
542 void
543 BootpRequest (void)
544 {
545         volatile uchar *pkt, *iphdr;
546         Bootp_t *bp;
547         int ext_len, pktlen, iplen;
548
549 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
550         dhcp_state = INIT;
551 #endif
552
553 #ifdef CONFIG_BOOTP_RANDOM_DELAY                /* Random BOOTP delay */
554         unsigned char bi_enetaddr[6];
555         int   reg;
556         char  *e,*s;
557         uchar tmp[64];
558         ulong tst1, tst2, sum, m_mask, m_value = 0;
559
560         if (BootpTry ==0) {
561                 /* get our mac */
562                 reg = getenv_r ("ethaddr", tmp, sizeof(tmp));
563                 s = (reg > 0) ? tmp : NULL;
564
565                 for (reg=0; reg<6; ++reg) {
566                         bi_enetaddr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
567                         if (s) {
568                                 s = (*e) ? e+1 : e;
569                         }
570                 }
571 #ifdef DEBUG
572                 printf("BootpRequest => Our Mac: ");
573                 for (reg=0; reg<6; reg++) {
574                         printf ("%x%c",
575                                 bi_enetaddr[reg],
576                                 reg==5 ? '\n' : ':');
577                 }
578 #endif /* DEBUG */
579
580                 /* Mac-Manipulation 2 get seed1 */
581                 tst1=0;
582                 tst2=0;
583                 for (reg=2; reg<6; reg++) {
584                         tst1 = tst1 << 8;
585                         tst1 = tst1 | bi_enetaddr[reg];
586                 }
587                 for (reg=0; reg<2; reg++) {
588                         tst2 = tst2 | bi_enetaddr[reg];
589                         tst2 = tst2 << 8;
590                 }
591
592                 seed1 = tst1^tst2;
593
594                 /* Mirror seed1*/
595                 m_mask=0x1;
596                 for (reg=1;reg<=32;reg++) {
597                         m_value |= (m_mask & seed1);
598                         seed1 = seed1 >> 1;
599                         m_value = m_value << 1;
600                 }
601                 seed1 = m_value;
602                 seed2 = 0xB78D0945;
603         }
604
605         /* Random Number Generator */
606
607         for (reg=0;reg<=0;reg++) {
608                 sum = seed1 + seed2;
609                 if (sum < seed1 || sum < seed2)
610                         sum++;
611                 seed2 = seed1;
612                 seed1 = sum;
613
614                 if (BootpTry<=2) {      /* Start with max 1024 * 1ms */
615                         sum = sum >> (22-BootpTry);
616                 } else {                /*After 3rd BOOTP request max 8192 * 1ms */
617                         sum = sum >> 19;
618                 }
619         }
620
621         printf ("Random delay: %ld ms...\n", sum);
622         for (reg=0; reg <sum; reg++) {
623                 udelay(1000); /*Wait 1ms*/
624         }
625 #endif  /* CONFIG_BOOTP_RANDOM_DELAY */
626
627         printf("BOOTP broadcast %d\n", ++BootpTry);
628         pkt = NetTxPacket;
629         memset ((void*)pkt, 0, PKTSIZE);
630
631         NetSetEther(pkt, NetBcastAddr, PROT_IP);
632         pkt += ETHER_HDR_SIZE;
633
634         /*
635          * Next line results in incorrect packet size being transmitted, resulting
636          * in errors in some DHCP servers, reporting missing bytes.  Size must be
637          * set in packet header after extension length has been determined.
638          * C. Hallinan, DS4.COM, Inc.
639          */
640         /* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (Bootp_t)); */
641         iphdr = pkt;    /* We need this later for NetSetIP() */
642         pkt += IP_HDR_SIZE;
643
644         bp = (Bootp_t *)pkt;
645         bp->bp_op = OP_BOOTREQUEST;
646         bp->bp_htype = HWT_ETHER;
647         bp->bp_hlen = HWL_ETHER;
648         bp->bp_hops = 0;
649         bp->bp_secs = htons(get_timer(0) / CFG_HZ);
650         NetWriteIP(&bp->bp_ciaddr, 0);
651         NetWriteIP(&bp->bp_yiaddr, 0);
652         NetWriteIP(&bp->bp_siaddr, 0);
653         NetWriteIP(&bp->bp_giaddr, 0);
654         memcpy (bp->bp_chaddr, NetOurEther, 6);
655         copy_filename (bp->bp_file, BootFile, sizeof(bp->bp_file));
656
657         /* Request additional information from the BOOTP/DHCP server */
658 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
659         ext_len = DhcpExtended(bp->bp_vend, DHCP_DISCOVER, 0, 0);
660 #else
661         ext_len = BootpExtended(bp->bp_vend);
662 #endif  /* CFG_CMD_DHCP */
663
664         /*
665          *      Bootp ID is the lower 4 bytes of our ethernet address
666          *      plus the current time in HZ.
667          */
668         BootpID = ((ulong)NetOurEther[2] << 24)
669                 | ((ulong)NetOurEther[3] << 16)
670                 | ((ulong)NetOurEther[4] << 8)
671                 | (ulong)NetOurEther[5];
672         BootpID += get_timer(0);
673         BootpID  = htonl(BootpID);
674         NetCopyLong(&bp->bp_id, &BootpID);
675
676         /*
677          * Calculate proper packet lengths taking into account the
678          * variable size of the options field
679          */
680         pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + ext_len;
681         iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
682         NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
683         NetSetTimeout(SELECT_TIMEOUT * CFG_HZ, BootpTimeout);
684
685 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
686         dhcp_state = SELECTING;
687         NetSetHandler(DhcpHandler);
688 #else
689         NetSetHandler(BootpHandler);
690 #endif  /* CFG_CMD_DHCP */
691         NetSendPacket(NetTxPacket, pktlen);
692 }
693
694 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
695 static void DhcpOptionsProcess(uchar *popt)
696 {
697         uchar *end = popt + BOOTP_HDR_SIZE;
698         int oplen, size;
699
700         while ( popt < end && *popt != 0xff ) {
701                 oplen = *(popt + 1);
702                 switch(*popt) {
703                         case  1:
704                                 NetCopyIP(&NetOurSubnetMask, (popt+2));
705                                 break;
706                         case  3:
707                                 NetCopyIP(&NetOurGatewayIP, (popt+2));
708                                 break;
709                         case  6:
710                                 NetCopyIP(&NetOurDNSIP, (popt+2));
711 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
712                                 if ( *(popt+1) > 4 ) {
713                                         NetCopyIP(&NetOurDNS2IP, (popt+2+4));
714                                 }
715 #endif
716                                 break;
717                         case 12:
718                                 size = truncate_sz ("Host Name",
719                                                     sizeof(NetOurHostName),
720                                                     oplen);
721                                 memcpy(&NetOurHostName, popt+2, size);
722                                 NetOurHostName[size] = 0 ;
723                                 break;
724                         case 15:                /* Ignore Domain Name Option */
725                                 break;
726                         case 17:
727                                 size = truncate_sz ("Root Path",
728                                                     sizeof(NetOurRootPath),
729                                                     oplen);
730                                 memcpy(&NetOurRootPath, popt+2, size);
731                                 NetOurRootPath[size] = 0 ;
732                                 break;
733                         case 51:
734                                 NetCopyLong (&dhcp_leasetime, (ulong *)(popt + 2));
735                                 break;
736                         case 53:                /* Ignore Message Type Option */
737                                 break;
738                         case 54:
739                                 NetCopyIP(&NetDHCPServerIP, (popt+2));
740                                 break;
741                         case 58:                /* Ignore Renewal Time Option */
742                                 break;
743                         case 59:                /* Ignore Rebinding Time Option */
744                                 break;
745                         default:
746 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
747                             if (dhcp_vendorex_proc(popt))
748                                 break;
749 #endif
750                                 printf("*** Unhandled DHCP Option in OFFER/ACK: %d\n",
751                                         *popt);
752                                 break;
753                 }
754                 popt += oplen + 2;      /* Process next option */
755         }
756 }
757
758 static int DhcpMessageType(unsigned char *popt)
759 {
760         if (NetReadLong((ulong*)popt) != htonl(BOOTP_VENDOR_MAGIC))
761                 return -1;
762
763         popt += 4;
764         while ( *popt != 0xff ) {
765                 if ( *popt == 53 )      /* DHCP Message Type */
766                         return *(popt + 2);
767                 popt += *(popt + 1) + 2;        /* Scan through all options */
768         }
769         return -1;
770 }
771
772 static void DhcpSendRequestPkt(Bootp_t *bp_offer)
773 {
774         volatile uchar *pkt, *iphdr;
775         Bootp_t *bp;
776         int pktlen, iplen, extlen;
777         IPaddr_t OfferedIP;
778
779         debug ("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
780         pkt = NetTxPacket;
781         memset ((void*)pkt, 0, PKTSIZE);
782
783         NetSetEther(pkt, NetBcastAddr, PROT_IP);
784         pkt += ETHER_HDR_SIZE;
785
786         iphdr = pkt;            /* We'll need this later to set proper pkt size */
787         pkt += IP_HDR_SIZE;
788
789         bp = (Bootp_t *)pkt;
790         bp->bp_op = OP_BOOTREQUEST;
791         bp->bp_htype = HWT_ETHER;
792         bp->bp_hlen = HWL_ETHER;
793         bp->bp_hops = 0;
794         bp->bp_secs = htons(get_timer(0) / CFG_HZ);
795         NetCopyIP(&bp->bp_ciaddr, &bp_offer->bp_ciaddr); /* both in network byte order */
796         NetCopyIP(&bp->bp_yiaddr, &bp_offer->bp_yiaddr);
797         NetCopyIP(&bp->bp_siaddr, &bp_offer->bp_siaddr);
798         NetCopyIP(&bp->bp_giaddr, &bp_offer->bp_giaddr);
799         memcpy (bp->bp_chaddr, NetOurEther, 6);
800
801         /*
802          * ID is the id of the OFFER packet
803          */
804
805         NetCopyLong(&bp->bp_id, &bp_offer->bp_id);
806
807         /*
808          * Copy options from OFFER packet if present
809          */
810         NetCopyIP(&OfferedIP, &bp->bp_yiaddr);
811         extlen = DhcpExtended(bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP);
812
813         pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + extlen;
814         iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
815         NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
816
817         debug ("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
818         NetSendPacket(NetTxPacket, pktlen);
819 }
820
821 /*
822  *      Handle DHCP received packets.
823  */
824 static void
825 DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
826 {
827         Bootp_t *bp = (Bootp_t *)pkt;
828
829         debug ("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
830                 src, dest, len, dhcp_state);
831
832         if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
833                 return;
834
835         debug ("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n",
836                 src, dest, len, dhcp_state);
837
838         switch (dhcp_state) {
839         case SELECTING:
840                 /*
841                  * Wait an appropriate time for any potential DHCPOFFER packets
842                  * to arrive.  Then select one, and generate DHCPREQUEST response.
843                  * If filename is in format we recognize, assume it is a valid
844                  * OFFER from a server we want.
845                  */
846                 debug ("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
847 #ifdef CFG_BOOTFILE_PREFIX
848                 if (strncmp(bp->bp_file,
849                             CFG_BOOTFILE_PREFIX,
850                             strlen(CFG_BOOTFILE_PREFIX)) == 0 ) {
851 #endif  /* CFG_BOOTFILE_PREFIX */
852
853                         debug ("TRANSITIONING TO REQUESTING STATE\n");
854                         dhcp_state = REQUESTING;
855
856                         if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
857                                 DhcpOptionsProcess(&bp->bp_vend[4]);
858
859                         BootpCopyNetParams(bp); /* Store net params from reply */
860
861                         NetSetTimeout(TIMEOUT * CFG_HZ, BootpTimeout);
862                         DhcpSendRequestPkt(bp);
863 #ifdef CFG_BOOTFILE_PREFIX
864                 }
865 #endif  /* CFG_BOOTFILE_PREFIX */
866
867                 return;
868                 break;
869         case REQUESTING:
870                 debug ("DHCP State: REQUESTING\n");
871
872                 if ( DhcpMessageType(bp->bp_vend) == DHCP_ACK ) {
873                         char *s;
874
875                         if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
876                                 DhcpOptionsProcess(&bp->bp_vend[4]);
877                         BootpCopyNetParams(bp); /* Store net params from reply */
878                         dhcp_state = BOUND;
879                         printf("DHCP client bound to address ");
880                         print_IPaddr(NetOurIP);
881                         printf("\n");
882
883                         /* Obey the 'autoload' setting */
884                         if (((s = getenv("autoload")) != NULL) && (*s == 'n')) {
885                                 NetState = NETLOOP_SUCCESS;
886                                 return;
887                         }
888                         TftpStart();
889                         return;
890                 }
891                 break;
892         default:
893                 printf("DHCP: INVALID STATE\n");
894                 break;
895         }
896
897 }
898
899 void DhcpRequest(void)
900 {
901         BootpRequest();
902 }
903 #endif  /* CFG_CMD_DHCP */
904
905 #endif /* CFG_CMD_NET */