* Patch by Pierre Aubert, 26 Feb 2004
[platform/kernel/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) {
335                 if (*s == 'n') {
336                         /*
337                          * Just use BOOTP to configure system;
338                          * Do not use TFTP to load the bootfile.
339                          */
340                         NetState = NETLOOP_SUCCESS;
341                         return;
342                 } else if (strcmp(s, "NFS") == 0) {
343                         /*
344                          * Use NFS to load the bootfile.
345                          */
346                         NfsStart();
347                         return;
348                 }
349         }
350
351         TftpStart();
352 }
353 #endif  /* !CFG_CMD_DHCP */
354
355 /*
356  *      Timeout on BOOTP/DHCP request.
357  */
358 static void
359 BootpTimeout(void)
360 {
361         if (BootpTry >= TIMEOUT_COUNT) {
362                 puts ("\nRetry count exceeded; starting again\n");
363                 NetStartAgain ();
364         } else {
365                 NetSetTimeout (TIMEOUT * CFG_HZ, BootpTimeout);
366                 BootpRequest ();
367         }
368 }
369
370 /*
371  *      Initialize BOOTP extension fields in the request.
372  */
373 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
374 static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)
375 {
376     u8 *start = e ;
377     u8 *cnt;
378 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
379     u8 *x;
380 #endif
381 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME)
382     uchar *hostname;
383 #endif
384
385     *e++ =  99;         /* RFC1048 Magic Cookie */
386     *e++ = 130;
387     *e++ =  83;
388     *e++ =  99;
389
390     *e++ = 53;          /* DHCP Message Type */
391     *e++ = 1;
392     *e++ = message_type;
393
394     *e++ = 57;          /* Maximum DHCP Message Size */
395     *e++ = 2;
396     *e++ = (576-312+OPT_SIZE) >> 8;
397     *e++ = (576-312+OPT_SIZE) & 0xff;
398
399     if ( ServerID ) {
400             int tmp = ntohl(ServerID);
401
402             *e++ = 54;  /* ServerID */
403             *e++ = 4;
404             *e++ = tmp >> 24;
405             *e++ = tmp >> 16;
406             *e++ = tmp >> 8;
407             *e++ = tmp & 0xff;
408     }
409
410     if ( RequestedIP ) {
411             int tmp = ntohl(RequestedIP);
412
413             *e++ = 50;  /* Requested IP */
414             *e++ = 4;
415             *e++ = tmp >> 24;
416             *e++ = tmp >> 16;
417             *e++ = tmp >> 8;
418             *e++ = tmp & 0xff;
419     }
420
421 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME)
422     if ( (hostname = getenv("hostname")) ) {
423             int hostnamelen = strlen(hostname);
424             *e++ = 12;        /* Hostname */
425             *e++ = hostnamelen;
426             memcpy(e,hostname,hostnamelen);
427             e += hostnamelen;
428     }
429 #endif
430
431 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
432     if ((x = dhcp_vendorex_prep (e)))
433         return x - start ;
434 #endif
435
436     *e++ = 55;          /* Parameter Request List */
437     cnt  = e++;         /* Pointer to count of requested items */
438     *cnt = 0;
439 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
440     *e++ = 1;           /* Subnet Mask */
441     *cnt += 1;
442 #endif
443 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
444     *e++ = 3;           /* Router Option */
445     *cnt += 1;
446 #endif
447 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
448     *e++ = 6;           /* DNS Server(s) */
449     *cnt += 1;
450 #endif
451 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
452     *e++ = 12;          /* Hostname */
453     *cnt += 1;
454 #endif
455 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
456     *e++ = 13;          /* Boot File Size */
457     *cnt += 1;
458 #endif
459 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
460     *e++ = 17;          /* Boot path */
461     *cnt += 1;
462 #endif
463 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
464     *e++ = 40;          /* NIS Domain name request */
465     *cnt += 1;
466 #endif
467     *e++ = 255;         /* End of the list */
468
469     /* Pad to minimal length */
470 #ifdef  CONFIG_DHCP_MIN_EXT_LEN
471     while ((e - start) <= CONFIG_DHCP_MIN_EXT_LEN)
472         *e++ = 0;
473 #endif
474
475     return e - start ;
476 }
477
478 #else   /* CFG_CMD_DHCP */
479 /*
480  *      Warning: no field size check - change CONFIG_BOOTP_MASK at your own risk!
481  */
482 static int BootpExtended (u8 *e)
483 {
484     u8 *start = e ;
485
486     *e++ =  99;         /* RFC1048 Magic Cookie */
487     *e++ = 130;
488     *e++ =  83;
489     *e++ =  99;
490
491 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
492     *e++ = 53;          /* DHCP Message Type */
493     *e++ = 1;
494     *e++ = DHCP_DISCOVER;
495
496     *e++ = 57;          /* Maximum DHCP Message Size */
497     *e++ = 2;
498     *e++ = (576-312+OPT_SIZE) >> 16;
499     *e++ = (576-312+OPT_SIZE) & 0xff;
500 #endif  /* CFG_CMD_DHCP */
501
502 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
503     *e++ =  1;          /* Subnet mask request */
504     *e++ =  4;
505      e  +=  4;
506 #endif
507
508 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
509     *e++ =  3;          /* Default gateway request */
510     *e++ =  4;
511      e  +=  4;
512 #endif
513
514 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
515     *e++ =  6;          /* Domain Name Server */
516     *e++ =  4;
517      e  +=  4;
518 #endif
519
520 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
521     *e++ = 12;          /* Host name request */
522     *e++ = 32;
523      e  += 32;
524 #endif
525
526 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
527     *e++ = 13;          /* Boot file size */
528     *e++ =  2;
529      e  +=  2;
530 #endif
531
532 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
533     *e++ = 17;          /* Boot path */
534     *e++ = 32;
535      e  += 32;
536 #endif
537
538 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
539     *e++ = 40;          /* NIS Domain name request */
540     *e++ = 32;
541      e  += 32;
542 #endif
543
544     *e++ = 255;         /* End of the list */
545
546     return e - start ;
547 }
548 #endif  /* CFG_CMD_DHCP */
549
550 void
551 BootpRequest (void)
552 {
553         volatile uchar *pkt, *iphdr;
554         Bootp_t *bp;
555         int ext_len, pktlen, iplen;
556
557 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
558         dhcp_state = INIT;
559 #endif
560
561 #ifdef CONFIG_BOOTP_RANDOM_DELAY                /* Random BOOTP delay */
562         unsigned char bi_enetaddr[6];
563         int   reg;
564         char  *e,*s;
565         uchar tmp[64];
566         ulong tst1, tst2, sum, m_mask, m_value = 0;
567
568         if (BootpTry ==0) {
569                 /* get our mac */
570                 reg = getenv_r ("ethaddr", tmp, sizeof(tmp));
571                 s = (reg > 0) ? tmp : NULL;
572
573                 for (reg=0; reg<6; ++reg) {
574                         bi_enetaddr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
575                         if (s) {
576                                 s = (*e) ? e+1 : e;
577                         }
578                 }
579 #ifdef DEBUG
580                 printf("BootpRequest => Our Mac: ");
581                 for (reg=0; reg<6; reg++) {
582                         printf ("%x%c",
583                                 bi_enetaddr[reg],
584                                 reg==5 ? '\n' : ':');
585                 }
586 #endif /* DEBUG */
587
588                 /* Mac-Manipulation 2 get seed1 */
589                 tst1=0;
590                 tst2=0;
591                 for (reg=2; reg<6; reg++) {
592                         tst1 = tst1 << 8;
593                         tst1 = tst1 | bi_enetaddr[reg];
594                 }
595                 for (reg=0; reg<2; reg++) {
596                         tst2 = tst2 | bi_enetaddr[reg];
597                         tst2 = tst2 << 8;
598                 }
599
600                 seed1 = tst1^tst2;
601
602                 /* Mirror seed1*/
603                 m_mask=0x1;
604                 for (reg=1;reg<=32;reg++) {
605                         m_value |= (m_mask & seed1);
606                         seed1 = seed1 >> 1;
607                         m_value = m_value << 1;
608                 }
609                 seed1 = m_value;
610                 seed2 = 0xB78D0945;
611         }
612
613         /* Random Number Generator */
614
615         for (reg=0;reg<=0;reg++) {
616                 sum = seed1 + seed2;
617                 if (sum < seed1 || sum < seed2)
618                         sum++;
619                 seed2 = seed1;
620                 seed1 = sum;
621
622                 if (BootpTry<=2) {      /* Start with max 1024 * 1ms */
623                         sum = sum >> (22-BootpTry);
624                 } else {                /*After 3rd BOOTP request max 8192 * 1ms */
625                         sum = sum >> 19;
626                 }
627         }
628
629         printf ("Random delay: %ld ms...\n", sum);
630         for (reg=0; reg <sum; reg++) {
631                 udelay(1000); /*Wait 1ms*/
632         }
633 #endif  /* CONFIG_BOOTP_RANDOM_DELAY */
634
635         printf("BOOTP broadcast %d\n", ++BootpTry);
636         pkt = NetTxPacket;
637         memset ((void*)pkt, 0, PKTSIZE);
638
639         NetSetEther(pkt, NetBcastAddr, PROT_IP);
640         pkt += ETHER_HDR_SIZE;
641
642         /*
643          * Next line results in incorrect packet size being transmitted, resulting
644          * in errors in some DHCP servers, reporting missing bytes.  Size must be
645          * set in packet header after extension length has been determined.
646          * C. Hallinan, DS4.COM, Inc.
647          */
648         /* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (Bootp_t)); */
649         iphdr = pkt;    /* We need this later for NetSetIP() */
650         pkt += IP_HDR_SIZE;
651
652         bp = (Bootp_t *)pkt;
653         bp->bp_op = OP_BOOTREQUEST;
654         bp->bp_htype = HWT_ETHER;
655         bp->bp_hlen = HWL_ETHER;
656         bp->bp_hops = 0;
657         bp->bp_secs = htons(get_timer(0) / CFG_HZ);
658         NetWriteIP(&bp->bp_ciaddr, 0);
659         NetWriteIP(&bp->bp_yiaddr, 0);
660         NetWriteIP(&bp->bp_siaddr, 0);
661         NetWriteIP(&bp->bp_giaddr, 0);
662         memcpy (bp->bp_chaddr, NetOurEther, 6);
663         copy_filename (bp->bp_file, BootFile, sizeof(bp->bp_file));
664
665         /* Request additional information from the BOOTP/DHCP server */
666 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
667         ext_len = DhcpExtended(bp->bp_vend, DHCP_DISCOVER, 0, 0);
668 #else
669         ext_len = BootpExtended(bp->bp_vend);
670 #endif  /* CFG_CMD_DHCP */
671
672         /*
673          *      Bootp ID is the lower 4 bytes of our ethernet address
674          *      plus the current time in HZ.
675          */
676         BootpID = ((ulong)NetOurEther[2] << 24)
677                 | ((ulong)NetOurEther[3] << 16)
678                 | ((ulong)NetOurEther[4] << 8)
679                 | (ulong)NetOurEther[5];
680         BootpID += get_timer(0);
681         BootpID  = htonl(BootpID);
682         NetCopyLong(&bp->bp_id, &BootpID);
683
684         /*
685          * Calculate proper packet lengths taking into account the
686          * variable size of the options field
687          */
688         pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + ext_len;
689         iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
690         NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
691         NetSetTimeout(SELECT_TIMEOUT * CFG_HZ, BootpTimeout);
692
693 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
694         dhcp_state = SELECTING;
695         NetSetHandler(DhcpHandler);
696 #else
697         NetSetHandler(BootpHandler);
698 #endif  /* CFG_CMD_DHCP */
699         NetSendPacket(NetTxPacket, pktlen);
700 }
701
702 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
703 static void DhcpOptionsProcess(uchar *popt)
704 {
705         uchar *end = popt + BOOTP_HDR_SIZE;
706         int oplen, size;
707
708         while ( popt < end && *popt != 0xff ) {
709                 oplen = *(popt + 1);
710                 switch(*popt) {
711                         case  1:
712                                 NetCopyIP(&NetOurSubnetMask, (popt+2));
713                                 break;
714                         case  3:
715                                 NetCopyIP(&NetOurGatewayIP, (popt+2));
716                                 break;
717                         case  6:
718                                 NetCopyIP(&NetOurDNSIP, (popt+2));
719 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
720                                 if ( *(popt+1) > 4 ) {
721                                         NetCopyIP(&NetOurDNS2IP, (popt+2+4));
722                                 }
723 #endif
724                                 break;
725                         case 12:
726                                 size = truncate_sz ("Host Name",
727                                                     sizeof(NetOurHostName),
728                                                     oplen);
729                                 memcpy(&NetOurHostName, popt+2, size);
730                                 NetOurHostName[size] = 0 ;
731                                 break;
732                         case 15:                /* Ignore Domain Name Option */
733                                 break;
734                         case 17:
735                                 size = truncate_sz ("Root Path",
736                                                     sizeof(NetOurRootPath),
737                                                     oplen);
738                                 memcpy(&NetOurRootPath, popt+2, size);
739                                 NetOurRootPath[size] = 0 ;
740                                 break;
741                         case 51:
742                                 NetCopyLong (&dhcp_leasetime, (ulong *)(popt + 2));
743                                 break;
744                         case 53:                /* Ignore Message Type Option */
745                                 break;
746                         case 54:
747                                 NetCopyIP(&NetDHCPServerIP, (popt+2));
748                                 break;
749                         case 58:                /* Ignore Renewal Time Option */
750                                 break;
751                         case 59:                /* Ignore Rebinding Time Option */
752                                 break;
753                         default:
754 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
755                             if (dhcp_vendorex_proc(popt))
756                                 break;
757 #endif
758                                 printf("*** Unhandled DHCP Option in OFFER/ACK: %d\n",
759                                         *popt);
760                                 break;
761                 }
762                 popt += oplen + 2;      /* Process next option */
763         }
764 }
765
766 static int DhcpMessageType(unsigned char *popt)
767 {
768         if (NetReadLong((ulong*)popt) != htonl(BOOTP_VENDOR_MAGIC))
769                 return -1;
770
771         popt += 4;
772         while ( *popt != 0xff ) {
773                 if ( *popt == 53 )      /* DHCP Message Type */
774                         return *(popt + 2);
775                 popt += *(popt + 1) + 2;        /* Scan through all options */
776         }
777         return -1;
778 }
779
780 static void DhcpSendRequestPkt(Bootp_t *bp_offer)
781 {
782         volatile uchar *pkt, *iphdr;
783         Bootp_t *bp;
784         int pktlen, iplen, extlen;
785         IPaddr_t OfferedIP;
786
787         debug ("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
788         pkt = NetTxPacket;
789         memset ((void*)pkt, 0, PKTSIZE);
790
791         NetSetEther(pkt, NetBcastAddr, PROT_IP);
792         pkt += ETHER_HDR_SIZE;
793
794         iphdr = pkt;            /* We'll need this later to set proper pkt size */
795         pkt += IP_HDR_SIZE;
796
797         bp = (Bootp_t *)pkt;
798         bp->bp_op = OP_BOOTREQUEST;
799         bp->bp_htype = HWT_ETHER;
800         bp->bp_hlen = HWL_ETHER;
801         bp->bp_hops = 0;
802         bp->bp_secs = htons(get_timer(0) / CFG_HZ);
803         NetCopyIP(&bp->bp_ciaddr, &bp_offer->bp_ciaddr); /* both in network byte order */
804         NetCopyIP(&bp->bp_yiaddr, &bp_offer->bp_yiaddr);
805         NetCopyIP(&bp->bp_siaddr, &bp_offer->bp_siaddr);
806         NetCopyIP(&bp->bp_giaddr, &bp_offer->bp_giaddr);
807         memcpy (bp->bp_chaddr, NetOurEther, 6);
808
809         /*
810          * ID is the id of the OFFER packet
811          */
812
813         NetCopyLong(&bp->bp_id, &bp_offer->bp_id);
814
815         /*
816          * Copy options from OFFER packet if present
817          */
818         NetCopyIP(&OfferedIP, &bp->bp_yiaddr);
819         extlen = DhcpExtended(bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP);
820
821         pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + extlen;
822         iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
823         NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
824
825         debug ("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
826         NetSendPacket(NetTxPacket, pktlen);
827 }
828
829 /*
830  *      Handle DHCP received packets.
831  */
832 static void
833 DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
834 {
835         Bootp_t *bp = (Bootp_t *)pkt;
836
837         debug ("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
838                 src, dest, len, dhcp_state);
839
840         if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
841                 return;
842
843         debug ("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n",
844                 src, dest, len, dhcp_state);
845
846         switch (dhcp_state) {
847         case SELECTING:
848                 /*
849                  * Wait an appropriate time for any potential DHCPOFFER packets
850                  * to arrive.  Then select one, and generate DHCPREQUEST response.
851                  * If filename is in format we recognize, assume it is a valid
852                  * OFFER from a server we want.
853                  */
854                 debug ("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
855 #ifdef CFG_BOOTFILE_PREFIX
856                 if (strncmp(bp->bp_file,
857                             CFG_BOOTFILE_PREFIX,
858                             strlen(CFG_BOOTFILE_PREFIX)) == 0 ) {
859 #endif  /* CFG_BOOTFILE_PREFIX */
860
861                         debug ("TRANSITIONING TO REQUESTING STATE\n");
862                         dhcp_state = REQUESTING;
863
864                         if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
865                                 DhcpOptionsProcess(&bp->bp_vend[4]);
866
867                         BootpCopyNetParams(bp); /* Store net params from reply */
868
869                         NetSetTimeout(TIMEOUT * CFG_HZ, BootpTimeout);
870                         DhcpSendRequestPkt(bp);
871 #ifdef CFG_BOOTFILE_PREFIX
872                 }
873 #endif  /* CFG_BOOTFILE_PREFIX */
874
875                 return;
876                 break;
877         case REQUESTING:
878                 debug ("DHCP State: REQUESTING\n");
879
880                 if ( DhcpMessageType(bp->bp_vend) == DHCP_ACK ) {
881                         char *s;
882
883                         if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
884                                 DhcpOptionsProcess(&bp->bp_vend[4]);
885                         BootpCopyNetParams(bp); /* Store net params from reply */
886                         dhcp_state = BOUND;
887                         printf("DHCP client bound to address ");
888                         print_IPaddr(NetOurIP);
889                         printf("\n");
890
891                         /* Obey the 'autoload' setting */
892                         if ((s = getenv("autoload")) != NULL) {
893                                 if (*s == 'n') {
894                                         /*
895                                          * Just use BOOTP to configure system;
896                                          * Do not use TFTP to load the bootfile.
897                                          */
898                                         NetState = NETLOOP_SUCCESS;
899                                         return;
900                                 } else if (strcmp(s, "NFS") == 0) {
901                                         /*
902                                          * Use NFS to load the bootfile.
903                                          */
904                                         NfsStart();
905                                         return;
906                                 }
907                         }
908                         TftpStart();
909                         return;
910                 }
911                 break;
912         default:
913                 printf("DHCP: INVALID STATE\n");
914                 break;
915         }
916
917 }
918
919 void DhcpRequest(void)
920 {
921         BootpRequest();
922 }
923 #endif  /* CFG_CMD_DHCP */
924
925 #endif /* CFG_CMD_NET */