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