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