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