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