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