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