treewide: drop executable file attrib for non-executable files
[oweals/u-boot_mod.git] / u-boot / 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-2004 Wolfgang Denk, wd@denx.de
9  */
10
11 //#define DEBUG 1
12
13 #include <common.h>
14 #include <command.h>
15 #include <net.h>
16 #include "bootp.h"
17 #include "tftp.h"
18 #include "nfs.h"
19
20 #define CONFIG_BOOTP_RANDOM_DELAY
21 #define BOOTP_VENDOR_MAGIC      0x63825363      /* RFC1048 Magic Cookie */
22
23 #if (CONFIG_COMMANDS & CFG_CMD_NET)
24
25 DECLARE_GLOBAL_DATA_PTR;
26
27 #define TIMEOUT                         5               /* Seconds before trying BOOTP again */
28
29 #ifndef CONFIG_NET_RETRY_COUNT
30         #define TIMEOUT_COUNT   5               /* # of timeouts before giving up */
31 #else
32         #define TIMEOUT_COUNT   (CONFIG_NET_RETRY_COUNT)
33 #endif
34
35 #define PORT_BOOTPS                     67              /* BOOTP server UDP port */
36 #define PORT_BOOTPC                     68              /* BOOTP client UDP port */
37
38 #ifndef CONFIG_DHCP_MIN_EXT_LEN         /* minimal length of extension list     */
39         #define CONFIG_DHCP_MIN_EXT_LEN 64
40 #endif
41
42 ulong BootpID;
43 int BootpTry;
44
45 #ifdef CONFIG_BOOTP_RANDOM_DELAY
46 ulong seed1, seed2;
47 #endif
48
49 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
50 dhcp_state_t dhcp_state = INIT;
51 unsigned long dhcp_leasetime = 0;
52 IPaddr_t NetDHCPServerIP = 0;
53 static void DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len);
54
55 /* For Debug */
56 #if 0
57 static char *dhcpmsg2str(int type){
58         switch(type){
59                 case 1:
60                         return("DHCPDISCOVER");
61                         break;
62                 case 2:
63                         return("DHCPOFFER");
64                         break;
65                 case 3:
66                         return("DHCPREQUEST");
67                         break;
68                 case 4:
69                         return("DHCPDECLINE");
70                         break;
71                 case 5:
72                         return("DHCPACK");
73                         break;
74                 case 6:
75                         return("DHCPNACK");
76                         break;
77                 case 7:
78                         return("DHCPRELEASE");
79                         break;
80                 default:
81                         return("UNKNOWN/INVALID MSG TYPE");
82                         break;
83         }
84 }
85 #endif
86
87 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
88 extern u8 *dhcp_vendorex_prep (u8 *e); /*rtn new e after add own opts. */
89 extern u8 *dhcp_vendorex_proc (u8 *e); /*rtn next e if mine,else NULL  */
90 #endif
91
92 #endif  /* CFG_CMD_DHCP */
93
94 static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len){
95         Bootp_t *bp = (Bootp_t *) pkt;
96         int retval = 0;
97
98         if(dest != PORT_BOOTPC || src != PORT_BOOTPS){
99                 retval = -1;
100         } else if(len < sizeof (Bootp_t) - OPT_SIZE){
101                 retval = -2;
102         } else if(bp->bp_op != OP_BOOTREQUEST   &&
103                           bp->bp_op != OP_BOOTREPLY             &&
104                           bp->bp_op != DHCP_OFFER               &&
105                           bp->bp_op != DHCP_ACK                 &&
106                           bp->bp_op != DHCP_NAK){
107                 retval = -3;
108         } else if(bp->bp_htype != HWT_ETHER){
109                 retval = -4;
110         } else if(bp->bp_hlen != HWL_ETHER){
111                 retval = -5;
112         } else if(NetReadLong((ulong*)&bp->bp_id) != BootpID){
113                 retval = -6;
114         }
115
116 #ifdef DEBUG
117         printf("Filtering pkt = %d\n", retval);
118 #endif
119
120         return(retval);
121 }
122
123 /*
124  * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
125  */
126 static void BootpCopyNetParams(Bootp_t *bp){
127         IPaddr_t tmp_ip;
128
129         NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
130         NetCopyIP(&tmp_ip, &bp->bp_siaddr);
131
132         if(tmp_ip != 0){
133                 NetCopyIP(&NetServerIP, &bp->bp_siaddr);
134         }
135
136         memcpy(NetServerEther, ((Ethernet_t *)NetRxPkt)->et_src, 6);
137
138         if(strlen(bp->bp_file) > 0){
139                 copy_filename(BootFile, bp->bp_file, sizeof(BootFile));
140         }
141
142 #ifdef DEBUG
143         printf("Bootfile: %s\n", BootFile);
144 #endif
145
146         /*
147          * Propagate to environment:
148          * don't delete exising entry when BOOTP / DHCP reply does
149          * not contain a new value
150          */
151         if(*BootFile){
152                 setenv("bootfile", BootFile);
153         }
154 }
155
156 static int truncate_sz(const char *name, int maxlen, int curlen){
157         if(curlen >= maxlen){
158                 printf("** Warning: %s is too long (%d - max: %d) - truncated\n", name, curlen, maxlen);
159                 curlen = maxlen - 1;
160         }
161
162         return(curlen);
163 }
164
165 #if !(CONFIG_COMMANDS & CFG_CMD_DHCP)
166
167 static void BootpVendorFieldProcess(u8 * ext){
168         int size = *(ext + 1);
169
170         NetBootFileSize = 0;
171
172         switch(*ext){
173                 /* Fixed length fields */
174                 case 1: /* Subnet mask */
175                         if (NetOurSubnetMask == 0){
176                                 NetCopyIP(&NetOurSubnetMask, (IPaddr_t *)(ext + 2));
177                         }
178                         break;
179
180                 case 2: /* Time offset - Not yet supported */
181                         break;
182
183                 /* Variable length fields */
184                 case 3: /* Gateways list */
185                         if(NetOurGatewayIP == 0){
186                                 NetCopyIP(&NetOurGatewayIP, (IPaddr_t *)(ext + 2));
187                         }
188                         break;
189
190                 case 4: /* Time server - Not yet supported */
191                         break;
192
193                 case 5: /* IEN-116 name server - Not yet supported */
194                         break;
195
196                 case 6:
197                         if(NetOurDNSIP == 0){
198                                 NetCopyIP(&NetOurDNSIP, (IPaddr_t *)(ext + 2));
199                         }
200 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
201                         if((NetOurDNS2IP == 0) && (size > 4)){
202                                 NetCopyIP(&NetOurDNS2IP, (IPaddr_t *)(ext + 2 + 4));
203                         }
204 #endif
205                         break;
206
207                 case 7: /* Log server - Not yet supported */
208                         break;
209
210                 case 8: /* Cookie/Quote server - Not yet supported */
211                         break;
212
213                 case 9: /* LPR server - Not yet supported */
214                         break;
215
216                 case 10: /* Impress server - Not yet supported */
217                         break;
218
219                 case 11: /* RPL server - Not yet supported */
220                         break;
221
222                 case 12: /* Host name */
223                         if(NetOurHostName[0] == 0){
224                                 size = truncate_sz("Host Name", sizeof(NetOurHostName), size);
225                                 memcpy(&NetOurHostName, ext + 2, size);
226                                 NetOurHostName[size] = 0;
227                         }
228                         break;
229
230                 case 13: /* Boot file size */
231                         if(size == 2){
232                                 NetBootFileSize = ntohs(*(ushort *)(ext + 2));
233                         } else if(size == 4){
234                                 NetBootFileSize = ntohl(*(ulong *)(ext + 2));
235                         }
236                         break;
237
238                 case 14: /* Merit dump file - Not yet supported */
239                         break;
240
241                 case 15: /* Domain name - Not yet supported */
242                         break;
243
244                 case 16: /* Swap server - Not yet supported */
245                         break;
246
247                 case 17: /* Root path */
248                         if(NetOurRootPath[0] == 0){
249                                 size = truncate_sz("Root Path", sizeof(NetOurRootPath), size);
250                                 memcpy(&NetOurRootPath, ext + 2, size);
251                                 NetOurRootPath[size] = 0;
252                         }
253                         break;
254
255                 case 18: /* Extension path - Not yet supported */
256                         /*
257                          * This can be used to send the information of the
258                          * vendor area in another file that the client can
259                          * access via TFTP.
260                          */
261                         break;
262
263                 /* IP host layer fields */
264                 case 40: /* NIS Domain name */
265                         if(NetOurNISDomain[0] == 0){
266                                 size = truncate_sz("NIS Domain Name", sizeof(NetOurNISDomain), size);
267                                 memcpy(&NetOurNISDomain, ext + 2, size);
268                                 NetOurNISDomain[size] = 0;
269                         }
270                         break;
271
272                 /* Application layer fields */
273                 case 43: /* Vendor specific info - Not yet supported */
274                         /*
275                          * Binary information to exchange specific
276                          * product information.
277                          */
278                         break;
279                         /* Reserved (custom) fields (128..254) */
280         }
281
282 }
283
284 static void BootpVendorProcess(u8 * ext, int size){
285         u8 *end = ext + size;
286
287         while((ext < end) && (*ext != 0xff)){
288                 if(*ext == 0){
289                         ext++;
290                 } else {
291                         u8 *opt = ext;
292
293                         ext += ext[1] + 2;
294                         if(ext <= end){
295                                 BootpVendorFieldProcess(opt);
296                         }
297                 }
298         }
299
300 #ifdef DEBUG
301         puts("[BOOTP] Received fields: \n");
302
303         if(NetOurSubnetMask){
304                 puts("NetOurSubnetMask : ");
305                 print_IPaddr(NetOurSubnetMask);
306                 putc('\n');
307         }
308
309         if(NetOurGatewayIP){
310                 puts("NetOurGatewayIP   : ");
311                 print_IPaddr(NetOurGatewayIP);
312                 putc('\n');
313         }
314
315         if(NetBootFileSize){
316                 printf("NetBootFileSize : %d\n", NetBootFileSize);
317         }
318
319         if(NetOurHostName[0]){
320                 printf("NetOurHostName  : %s\n", NetOurHostName);
321         }
322
323         if(NetOurRootPath[0]){
324                 printf("NetOurRootPath  : %s\n", NetOurRootPath);
325         }
326
327         if(NetOurNISDomain[0]){
328                 printf("NetOurNISDomain : %s\n", NetOurNISDomain);
329         }
330
331         if(NetBootFileSize){
332                 printf("NetBootFileSize: %d\n", NetBootFileSize);
333         }
334 #endif /* DEBUG_BOOTP_EXT */
335 }
336
337 /*
338  *      Handle a BOOTP received packet.
339  */
340 static void BootpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len){
341         Bootp_t *bp;
342         char *s;
343
344 #ifdef DEBUG
345         printf("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%d)\n", src, dest, len, sizeof(Bootp_t));
346 #endif
347
348         bp = (Bootp_t *)pkt;
349
350         if(BootpCheckPkt(pkt, dest, src, len)){ /* Filter out pkts we don't want */
351                 return;
352         }
353
354         /*
355          *      Got a good BOOTP reply.  Copy the data into our variables.
356          */
357         BootpCopyNetParams(bp); /* Store net parameters from reply */
358
359         /* Retrieve extended information (we must parse the vendor area) */
360         if(NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC)){
361                 BootpVendorProcess((uchar *)&bp->bp_vend[4], len);
362         }
363
364         NetSetTimeout(0, (thand_f *)0);
365
366 #ifdef DEBUG
367         printf("Got good BOOTP\n");
368 #endif
369
370         if((s = getenv("autoload")) != NULL){
371                 if(*s == 'n'){
372                         /*
373                          * Just use BOOTP to configure system;
374                          * Do not use TFTP to load the bootfile.
375                          */
376                         NetState = NETLOOP_SUCCESS;
377                         return;
378 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
379                 } else if(strcmp(s, "NFS") == 0){
380                         /*
381                          * Use NFS to load the bootfile.
382                          */
383                         NfsStart();
384                         return;
385 #endif
386                 }
387         }
388
389         TftpStart();
390 }
391 #endif  /* !CFG_CMD_DHCP */
392
393 /*
394  *      Timeout on BOOTP/DHCP request.
395  */
396 static void BootpTimeout(void){
397         bd_t *bd = gd->bd;
398
399         if(BootpTry >= TIMEOUT_COUNT){
400                 puts("\n## Error: retry count exceeded, starting again!\n\n");
401                 NetStartAgain();
402         } else {
403                 NetSetTimeout(TIMEOUT * CFG_HZ, BootpTimeout);
404                 BootpRequest();
405         }
406 }
407
408 /*
409  *      Initialize BOOTP extension fields in the request.
410  */
411 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
412 static int DhcpExtended(u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP){
413         u8 *start = e;
414         u8 *cnt;
415
416 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
417         u8 *x;
418 #endif
419
420 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME)
421         char *hostname;
422 #endif
423
424         *e++ = 99;              /* RFC1048 Magic Cookie */
425         *e++ = 130;
426         *e++ = 83;
427         *e++ = 99;
428
429         *e++ = 53;              /* DHCP Message Type */
430         *e++ = 1;
431         *e++ = message_type;
432
433         *e++ = 57;              /* Maximum DHCP Message Size */
434         *e++ = 2;
435         *e++ = (576 - 312 + OPT_SIZE) >> 8;
436         *e++ = (576 - 312 + OPT_SIZE) & 0xff;
437
438         if(ServerID){
439                 int tmp = ntohl(ServerID);
440
441                 *e++ = 54;      /* ServerID */
442                 *e++ = 4;
443                 *e++ = tmp >> 24;
444                 *e++ = tmp >> 16;
445                 *e++ = tmp >> 8;
446                 *e++ = tmp & 0xff;
447         }
448
449         if(RequestedIP){
450                 int tmp = ntohl(RequestedIP);
451
452                 *e++ = 50;      /* Requested IP */
453                 *e++ = 4;
454                 *e++ = tmp >> 24;
455                 *e++ = tmp >> 16;
456                 *e++ = tmp >> 8;
457                 *e++ = tmp & 0xff;
458         }
459
460 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME)
461         if((hostname = getenv("hostname"))){
462                 int hostnamelen = strlen (hostname);
463
464                 *e++ = 12;      /* Hostname */
465                 *e++ = hostnamelen;
466
467                 memcpy(e, hostname, hostnamelen);
468                 e += hostnamelen;
469         }
470 #endif
471
472 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
473         if((x = dhcp_vendorex_prep (e))){
474                 return(x - start);
475         }
476 #endif
477
478         *e++ = 55;              /* Parameter Request List */
479          cnt = e++;             /* Pointer to count of requested items */
480         *cnt = 0;
481
482 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
483         *e++  = 1;              /* Subnet Mask */
484         *cnt += 1;
485 #endif
486
487 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_TIMEOFFSET)
488         *e++  = 2;
489         *cnt += 1;
490 #endif
491
492 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
493         *e++  = 3;              /* Router Option */
494         *cnt += 1;
495 #endif
496
497 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
498         *e++  = 6;              /* DNS Server(s) */
499         *cnt += 1;
500 #endif
501
502 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
503         *e++  = 12;             /* Hostname */
504         *cnt += 1;
505 #endif
506
507 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
508         *e++  = 13;             /* Boot File Size */
509         *cnt += 1;
510 #endif
511
512 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
513         *e++  = 17;             /* Boot path */
514         *cnt += 1;
515 #endif
516
517 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
518         *e++  = 40;             /* NIS Domain name request */
519         *cnt += 1;
520 #endif
521
522 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NTPSERVER)
523         *e++  = 42;
524         *cnt += 1;
525 #endif
526         *e++  = 255;            /* End of the list */
527
528         /* Pad to minimal length */
529 #ifdef  CONFIG_DHCP_MIN_EXT_LEN
530         while((e - start) <= CONFIG_DHCP_MIN_EXT_LEN){
531                 *e++ = 0;
532         }
533 #endif
534
535         return(e - start);
536 }
537
538 #else   /* CFG_CMD_DHCP */
539
540 /*
541  *      Warning: no field size check - change CONFIG_BOOTP_MASK at your own risk!
542  */
543 static int BootpExtended(u8 * e){
544         u8 *start = e;
545
546         *e++ = 99;              /* RFC1048 Magic Cookie */
547         *e++ = 130;
548         *e++ = 83;
549         *e++ = 99;
550
551 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
552         *e++ = 53;              /* DHCP Message Type */
553         *e++ = 1;
554         *e++ = DHCP_DISCOVER;
555
556         *e++ = 57;              /* Maximum DHCP Message Size */
557         *e++ = 2;
558         *e++ = (576 - 312 + OPT_SIZE) >> 16;
559         *e++ = (576 - 312 + OPT_SIZE) & 0xff;
560 #endif /* CFG_CMD_DHCP */
561
562 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
563         *e++ = 1;               /* Subnet mask request */
564         *e++ = 4;
565         e   += 4;
566 #endif
567
568 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
569         *e++ = 3;               /* Default gateway request */
570         *e++ = 4;
571         e   += 4;
572 #endif
573
574 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
575         *e++ = 6;               /* Domain Name Server */
576         *e++ = 4;
577         e   += 4;
578 #endif
579
580 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
581         *e++ = 12;              /* Host name request */
582         *e++ = 32;
583         e   += 32;
584 #endif
585
586 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
587         *e++ = 13;              /* Boot file size */
588         *e++ = 2;
589         e   += 2;
590 #endif
591
592 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
593         *e++ = 17;              /* Boot path */
594         *e++ = 32;
595         e   += 32;
596 #endif
597
598 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
599         *e++ = 40;              /* NIS Domain name request */
600         *e++ = 32;
601         e   += 32;
602 #endif
603
604         *e++ = 255;             /* End of the list */
605
606         return(e - start);
607 }
608 #endif  /* CFG_CMD_DHCP */
609
610 void BootpRequest(void){
611         bd_t *bd = gd->bd;
612         volatile uchar *pkt, *iphdr;
613         Bootp_t *bp;
614         int ext_len, pktlen, iplen;
615
616 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
617         dhcp_state = INIT;
618 #endif
619
620 #ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */
621         unsigned char bi_enetaddr[6];
622         int reg;
623         ulong tst1, tst2, sum, m_mask, m_value = 0;
624
625         if(BootpTry == 0){
626                 /* get our mac */
627                 memcpy(bi_enetaddr, NetOurEther, 6);
628
629 #ifdef DEBUG
630                 puts("BootpRequest => Our Mac: ");
631
632                 for(reg = 0; reg < 6; reg++){
633                         printf("%x%c", bi_enetaddr[reg], reg == 5 ? '\n' : ':');
634                 }
635 #endif /* DEBUG */
636
637                 /* Mac-Manipulation 2 get seed1 */
638                 tst1 = 0;
639                 tst2 = 0;
640
641                 for(reg = 2; reg < 6; reg++){
642                         tst1 = tst1 << 8;
643                         tst1 = tst1 | bi_enetaddr[reg];
644                 }
645
646                 for(reg = 0; reg < 2; reg++){
647                         tst2 = tst2 | bi_enetaddr[reg];
648                         tst2 = tst2 << 8;
649                 }
650
651                 seed1 = tst1^tst2;
652
653                 /* Mirror seed1*/
654                 m_mask = 0x1;
655
656                 for(reg = 1;reg <= 32; reg++){
657                         m_value |= (m_mask & seed1);
658                         seed1 = seed1 >> 1;
659                         m_value = m_value << 1;
660                 }
661
662                 seed1 = m_value;
663                 seed2 = 0xB78D0945;
664         }
665
666         /* Random Number Generator */
667         for(reg = 0; reg <= 0; reg++){
668                 sum = seed1 + seed2;
669
670                 if(sum < seed1 || sum < seed2){
671                         sum++;
672                 }
673
674                 seed2 = seed1;
675                 seed1 = sum;
676
677                 if(BootpTry<=2){        /* Start with max 1024 * 1ms */
678                         sum = sum >> (22-BootpTry);
679                 } else {                        /*After 3rd BOOTP request max 8192 * 1ms */
680                         sum = sum >> 19;
681                 }
682         }
683
684         printf("\nRandom delay: %ld ms...\n", sum);
685
686         for(reg = 0; reg < sum; reg++){
687                 udelay(1000); /* Wait 1ms */
688         }
689 #endif  /* CONFIG_BOOTP_RANDOM_DELAY */
690
691         printf("Sending DHCP discover... %d\n", ++BootpTry);
692
693         pkt = NetTxPacket;
694         memset((void*)pkt, 0, PKTSIZE);
695
696         pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
697
698         /*
699          * Next line results in incorrect packet size being transmitted, resulting
700          * in errors in some DHCP servers, reporting missing bytes.  Size must be
701          * set in packet header after extension length has been determined.
702          * C. Hallinan, DS4.COM, Inc.
703          */
704         /* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (Bootp_t)); */
705         iphdr = pkt;    /* We need this later for NetSetIP() */
706         pkt += IP_HDR_SIZE;
707
708         bp = (Bootp_t *)pkt;
709
710         bp->bp_op               = OP_BOOTREQUEST;
711         bp->bp_htype    = HWT_ETHER;
712         bp->bp_hlen             = HWL_ETHER;
713         bp->bp_hops             = 0;
714         bp->bp_secs             = htons(get_timer(0) / CFG_HZ);
715
716         NetWriteIP(&bp->bp_ciaddr, 0);
717         NetWriteIP(&bp->bp_yiaddr, 0);
718         NetWriteIP(&bp->bp_siaddr, 0);
719         NetWriteIP(&bp->bp_giaddr, 0);
720
721         memcpy(bp->bp_chaddr, NetOurEther, 6);
722
723         copy_filename(bp->bp_file, BootFile, sizeof(bp->bp_file));
724
725         /* Request additional information from the BOOTP/DHCP server */
726 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
727         ext_len = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
728 #else
729         ext_len = BootpExtended((u8 *)bp->bp_vend);
730 #endif  /* CFG_CMD_DHCP */
731
732         /*
733          *      Bootp ID is the lower 4 bytes of our ethernet address
734          *      plus the current time in HZ.
735          */
736         BootpID = ((ulong)NetOurEther[2] << 24)
737                 | ((ulong)NetOurEther[3] << 16)
738                 | ((ulong)NetOurEther[4] << 8)
739                 | (ulong)NetOurEther[5];
740
741         BootpID += get_timer(0);
742         BootpID  = htonl(BootpID);
743
744         NetCopyLong(&bp->bp_id, &BootpID);
745
746         /*
747          * Calculate proper packet lengths taking into account the
748          * variable size of the options field
749          */
750         pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + ext_len;
751         iplen  = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
752
753         NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
754         NetSetTimeout(SELECT_TIMEOUT * CFG_HZ, BootpTimeout);
755
756 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
757         dhcp_state = SELECTING;
758         NetSetHandler(DhcpHandler);
759 #else
760         NetSetHandler(BootpHandler);
761 #endif  /* CFG_CMD_DHCP */
762
763         NetSendPacket(NetTxPacket, pktlen);
764 }
765
766 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
767 static void DhcpOptionsProcess(uchar * popt, Bootp_t *bp){
768         uchar *end = popt + BOOTP_HDR_SIZE;
769         int oplen, size;
770
771         while(popt < end && *popt != 0xff){
772                 oplen = *(popt + 1);
773
774                 switch(*popt){
775                         case 1:
776                                 NetCopyIP(&NetOurSubnetMask, (popt + 2));
777                                 break;
778
779 #if (CONFIG_COMMANDS & CFG_CMD_SNTP) && (CONFIG_BOOTP_MASK & CONFIG_BOOTP_TIMEOFFSET)
780                         case 2: /* Time offset */
781                                 NetCopyLong(&NetTimeOffset, (ulong *)(popt + 2));
782                                 NetTimeOffset = ntohl(NetTimeOffset);
783                                 break;
784 #endif
785
786                         case 3:
787                                 NetCopyIP(&NetOurGatewayIP, (popt + 2));
788                                 break;
789
790                         case 6:
791                                 NetCopyIP(&NetOurDNSIP, (popt + 2));
792 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
793                                 if(*(popt + 1) > 4){
794                                         NetCopyIP(&NetOurDNS2IP, (popt + 2 + 4));
795                                 }
796 #endif
797                                 break;
798
799                         case 12:
800                                 size = truncate_sz("Host Name", sizeof(NetOurHostName), oplen);
801                                 memcpy(&NetOurHostName, popt + 2, size);
802                                 NetOurHostName[size] = 0;
803                                 break;
804
805                         case 15: /* Ignore Domain Name Option */
806                                 break;
807
808                         case 17:
809                                 size = truncate_sz("Root Path", sizeof(NetOurRootPath), oplen);
810                                 memcpy(&NetOurRootPath, popt + 2, size);
811                                 NetOurRootPath[size] = 0;
812                                 break;
813
814                         case 28: /* Ignore Broadcast Address Option */
815                                 break;
816
817 #if (CONFIG_COMMANDS & CFG_CMD_SNTP) && (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NTPSERVER)
818                         case 42: /* NTP server IP */
819                                 NetCopyIP(&NetNtpServerIP, (popt + 2));
820                                 break;
821 #endif
822
823                         case 51:
824                                 NetCopyLong(&dhcp_leasetime, (ulong *)(popt + 2));
825                                 break;
826
827                         case 53: /* Ignore Message Type Option */
828                                 break;
829
830                         case 54:
831                                 NetCopyIP(&NetDHCPServerIP, (popt + 2));
832                                 break;
833
834                         case 58: /* Ignore Renewal Time Option */
835                                 break;
836
837                         case 59: /* Ignore Rebinding Time Option */
838                                 break;
839
840                         case 66: /* Ignore TFTP server name */
841                                 break;
842
843                         case 67: /* vendor opt bootfile */
844                                 /*
845                                  * I can't use dhcp_vendorex_proc here because I need
846                                  * to write into the bootp packet - even then I had to
847                                  * pass the bootp packet pointer into here as the
848                                  * second arg
849                                  */
850                                 size = truncate_sz("Opt Boot File", sizeof(bp->bp_file), oplen);
851
852                                 if(bp->bp_file[0] == '\0' && size > 0){
853                                         /*
854                                          * only use vendor boot file if we didn't
855                                          * receive a boot file in the main non-vendor
856                                          * part of the packet - god only knows why
857                                          * some vendors chose not to use this perfectly
858                                          * good spot to store the boot file (join on
859                                          * Tru64 Unix) it seems mind bogglingly crazy
860                                          * to me
861                                          */
862                                         printf("** Warning: using vendor optional boot file\n");
863                                         memcpy(bp->bp_file, popt + 2, size);
864                                         bp->bp_file[size] = '\0';
865                                 }
866                                 break;
867
868                         default:
869 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
870                                 if(dhcp_vendorex_proc(popt)){
871                                         break;
872                                 }
873 #endif
874                                 printf("** Warning: unhandled DHCP option in OFFER/ACK: %d\n", *popt);
875                                 break;
876                 }
877
878                 popt += oplen + 2; /* Process next option */
879         }
880 }
881
882 static int DhcpMessageType(unsigned char *popt){
883         if(NetReadLong((ulong*)popt) != htonl(BOOTP_VENDOR_MAGIC)){
884                 return(-1);
885         }
886
887         popt += 4;
888
889         while(*popt != 0xff){
890                 if(*popt == 53){ /* DHCP Message Type */
891                         return(*(popt + 2));
892                 }
893
894                 popt += *(popt + 1) + 2; /* Scan through all options */
895         }
896
897         return(-1);
898 }
899
900 static void DhcpSendRequestPkt(Bootp_t *bp_offer){
901         bd_t *bd = gd->bd;
902         volatile uchar *pkt, *iphdr;
903         Bootp_t *bp;
904         int pktlen, iplen, extlen;
905         IPaddr_t OfferedIP;
906
907 #ifdef DEBUG
908         puts("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
909 #endif
910
911         pkt = NetTxPacket;
912         memset((void*)pkt, 0, PKTSIZE);
913
914         pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
915
916         iphdr = pkt; /* We'll need this later to set proper pkt size */
917         pkt += IP_HDR_SIZE;
918
919         bp = (Bootp_t *)pkt;
920
921         bp->bp_op               = OP_BOOTREQUEST;
922         bp->bp_htype    = HWT_ETHER;
923         bp->bp_hlen             = HWL_ETHER;
924         bp->bp_hops             = 0;
925         bp->bp_secs     = htons(get_timer(0) / CFG_HZ);
926
927         NetCopyIP(&bp->bp_ciaddr, &bp_offer->bp_ciaddr); /* both in network byte order */
928         NetCopyIP(&bp->bp_yiaddr, &bp_offer->bp_yiaddr);
929         NetCopyIP(&bp->bp_siaddr, &bp_offer->bp_siaddr);
930         NetCopyIP(&bp->bp_giaddr, &bp_offer->bp_giaddr);
931
932         memcpy(bp->bp_chaddr, NetOurEther, 6);
933
934         /*
935          * ID is the id of the OFFER packet
936          */
937         NetCopyLong(&bp->bp_id, &bp_offer->bp_id);
938
939         /*
940          * Copy options from OFFER packet if present
941          */
942         NetCopyIP(&OfferedIP, &bp->bp_yiaddr);
943         extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP);
944
945         pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + extlen;
946         iplen  = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
947
948         NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
949
950 #ifdef DEBUG
951         printf("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
952 #endif
953
954         NetSendPacket(NetTxPacket, pktlen);
955 }
956
957 /*
958  *      Handle DHCP received packets.
959  */
960 static void DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len){
961         bd_t *bd = gd->bd;
962         Bootp_t *bp = (Bootp_t *)pkt;
963         char tmp[22];
964
965 #ifdef DEBUG
966         printf("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n", src, dest, len, dhcp_state);
967 #endif
968
969         if(BootpCheckPkt(pkt, dest, src, len)){ /* Filter out pkts we don't want */
970                 return;
971         }
972
973 #ifdef DEBUG
974         printf("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n", src, dest, len, dhcp_state);
975 #endif
976
977         switch(dhcp_state){
978                 case SELECTING:
979                         /*
980                          * Wait an appropriate time for any potential DHCPOFFER packets
981                          * to arrive.  Then select one, and generate DHCPREQUEST response.
982                          * If filename is in format we recognize, assume it is a valid
983                          * OFFER from a server we want.
984                          */
985 #ifdef DEBUG
986                         printf("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
987 #endif
988
989 #ifdef CFG_BOOTFILE_PREFIX
990                         if(strncmp(bp->bp_file, CFG_BOOTFILE_PREFIX, strlen(CFG_BOOTFILE_PREFIX)) == 0 ){
991 #endif  /* CFG_BOOTFILE_PREFIX */
992
993 #ifdef DEBUG
994                                 puts("TRANSITIONING TO REQUESTING STATE\n");
995 #endif
996
997                                 dhcp_state = REQUESTING;
998
999                                 if(NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC)){
1000                                         DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
1001                                 }
1002
1003                                 BootpCopyNetParams(bp); /* Store net params from reply */
1004
1005                                 NetSetTimeout(TIMEOUT * CFG_HZ, BootpTimeout);
1006                                 DhcpSendRequestPkt(bp);
1007
1008 #ifdef CFG_BOOTFILE_PREFIX
1009                         }
1010 #endif  /* CFG_BOOTFILE_PREFIX */
1011
1012                         return;
1013                         break;
1014
1015                 case REQUESTING:
1016 #ifdef DEBUG
1017                         puts("DHCP State: REQUESTING\n");
1018 #endif
1019
1020                         if(DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK ){
1021                                 char *s;
1022
1023                                 if(NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC)){
1024                                         DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
1025                                 }
1026
1027                                 BootpCopyNetParams(bp); /* Store net params from reply */
1028
1029                                 dhcp_state = BOUND;
1030
1031                                 puts("\nReceived DHCP offer!\n      New IP: ");
1032                                 print_IPaddr(NetOurIP);
1033                                 putc('\n');
1034
1035                                 // save our new IP to env
1036                                 if(NetOurIP){
1037                                         ip_to_string(NetOurIP, tmp);
1038                                         setenv("ipaddr", tmp);
1039                                 }
1040
1041                                 puts("   Server IP: ");
1042                                 print_IPaddr(NetServerIP);
1043                                 putc('\n');
1044
1045                                 // save new server IP to env
1046                                 if(NetServerIP){
1047                                         ip_to_string(NetServerIP, tmp);
1048                                         setenv("serverip", tmp);
1049                                 }
1050
1051                                 /* Obey the 'autoload' setting */
1052                                 if((s = getenv("autoload")) != NULL){
1053                                         if(*s == 'n'){
1054                                                 /*
1055                                                  * Just use BOOTP to configure system;
1056                                                  * Do not use TFTP to load the bootfile.
1057                                                  */
1058                                                 NetState = NETLOOP_SUCCESS;
1059                                                 return;
1060 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
1061                                         } else if(strcmp(s, "NFS") == 0){
1062                                                 /*
1063                                                  * Use NFS to load the bootfile.
1064                                                  */
1065                                                 NfsStart();
1066                                                 return;
1067 #endif
1068                                         }
1069                                 }
1070
1071                                 TftpStart();
1072                                 return;
1073                         }
1074                         break;
1075
1076                 default:
1077                         puts("## Error: DHCP in INVALID STATE\n");
1078                         break;
1079         }
1080
1081 }
1082
1083 void DhcpRequest(void){
1084         BootpRequest();
1085 }
1086 #endif  /* CFG_CMD_DHCP */
1087
1088 #endif /* CFG_CMD_NET */