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