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