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