]> git.ipfire.org Git - people/ms/u-boot.git/blame - net/bootp.c
net: cosmetic: net.h checkpatch compliance
[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);
573f14fe 325 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
3861aa5c 326
0ebf04c6 327 debug("Got good BOOTP\n");
3861aa5c 328
e4a3d57d 329 net_auto_load();
3861aa5c 330}
610f2e9c 331#endif
3861aa5c
WD
332
333/*
334 * Timeout on BOOTP/DHCP request.
335 */
336static void
337BootpTimeout(void)
338{
339 if (BootpTry >= TIMEOUT_COUNT) {
340 puts ("\nRetry count exceeded; starting again\n");
341 NetStartAgain ();
342 } else {
49f3bdbb 343 NetSetTimeout (TIMEOUT, BootpTimeout);
3861aa5c
WD
344 BootpRequest ();
345 }
346}
347
348/*
349 * Initialize BOOTP extension fields in the request.
350 */
643d1ab2 351#if defined(CONFIG_CMD_DHCP)
232c150a 352static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)
3861aa5c 353{
232c150a
WD
354 u8 *start = e;
355 u8 *cnt;
d2b5d5c4
JH
356#if defined(CONFIG_BOOTP_PXE)
357 char *uuid;
358 size_t vci_strlen;
359 u16 clientarch;
360#endif
232c150a 361
1fe80d79 362#if defined(CONFIG_BOOTP_VENDOREX)
232c150a 363 u8 *x;
3861aa5c 364#endif
1fe80d79 365#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
77ddac94 366 char *hostname;
fe389a82 367#endif
3861aa5c 368
232c150a
WD
369 *e++ = 99; /* RFC1048 Magic Cookie */
370 *e++ = 130;
371 *e++ = 83;
372 *e++ = 99;
3861aa5c 373
232c150a
WD
374 *e++ = 53; /* DHCP Message Type */
375 *e++ = 1;
376 *e++ = message_type;
3861aa5c 377
232c150a
WD
378 *e++ = 57; /* Maximum DHCP Message Size */
379 *e++ = 2;
380 *e++ = (576 - 312 + OPT_SIZE) >> 8;
381 *e++ = (576 - 312 + OPT_SIZE) & 0xff;
3861aa5c 382
232c150a
WD
383 if (ServerID) {
384 int tmp = ntohl (ServerID);
3861aa5c 385
232c150a
WD
386 *e++ = 54; /* ServerID */
387 *e++ = 4;
388 *e++ = tmp >> 24;
389 *e++ = tmp >> 16;
390 *e++ = tmp >> 8;
391 *e++ = tmp & 0xff;
392 }
3861aa5c 393
232c150a
WD
394 if (RequestedIP) {
395 int tmp = ntohl (RequestedIP);
3861aa5c 396
232c150a
WD
397 *e++ = 50; /* Requested IP */
398 *e++ = 4;
399 *e++ = tmp >> 24;
400 *e++ = tmp >> 16;
401 *e++ = tmp >> 8;
402 *e++ = tmp & 0xff;
403 }
1fe80d79 404#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
232c150a
WD
405 if ((hostname = getenv ("hostname"))) {
406 int hostnamelen = strlen (hostname);
407
408 *e++ = 12; /* Hostname */
409 *e++ = hostnamelen;
410 memcpy (e, hostname, hostnamelen);
411 e += hostnamelen;
412 }
fe389a82
SR
413#endif
414
d2b5d5c4
JH
415#if defined(CONFIG_BOOTP_PXE)
416 clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
417 *e++ = 93; /* Client System Architecture */
418 *e++ = 2;
419 *e++ = (clientarch >> 8) & 0xff;
420 *e++ = clientarch & 0xff;
421
422 *e++ = 94; /* Client Network Interface Identifier */
423 *e++ = 3;
424 *e++ = 1; /* type field for UNDI */
425 *e++ = 0; /* major revision */
426 *e++ = 0; /* minor revision */
427
428 uuid = getenv("pxeuuid");
429
430 if (uuid) {
431 if (uuid_str_valid(uuid)) {
432 *e++ = 97; /* Client Machine Identifier */
433 *e++ = 17;
434 *e++ = 0; /* type 0 - UUID */
435
436 uuid_str_to_bin(uuid, e);
437 e += 16;
438 } else {
439 printf("Invalid pxeuuid: %s\n", uuid);
440 }
441 }
442
443 *e++ = 60; /* Vendor Class Identifier */
444 vci_strlen = strlen(CONFIG_BOOTP_VCI_STRING);
445 *e++ = vci_strlen;
446 memcpy(e, CONFIG_BOOTP_VCI_STRING, vci_strlen);
447 e += vci_strlen;
448#endif
449
1fe80d79 450#if defined(CONFIG_BOOTP_VENDOREX)
232c150a
WD
451 if ((x = dhcp_vendorex_prep (e)))
452 return x - start;
3861aa5c
WD
453#endif
454
232c150a
WD
455 *e++ = 55; /* Parameter Request List */
456 cnt = e++; /* Pointer to count of requested items */
457 *cnt = 0;
1fe80d79 458#if defined(CONFIG_BOOTP_SUBNETMASK)
232c150a
WD
459 *e++ = 1; /* Subnet Mask */
460 *cnt += 1;
3861aa5c 461#endif
1fe80d79 462#if defined(CONFIG_BOOTP_TIMEOFFSET)
ea287deb
WD
463 *e++ = 2;
464 *cnt += 1;
465#endif
1fe80d79 466#if defined(CONFIG_BOOTP_GATEWAY)
232c150a
WD
467 *e++ = 3; /* Router Option */
468 *cnt += 1;
3861aa5c 469#endif
1fe80d79 470#if defined(CONFIG_BOOTP_DNS)
232c150a
WD
471 *e++ = 6; /* DNS Server(s) */
472 *cnt += 1;
3861aa5c 473#endif
1fe80d79 474#if defined(CONFIG_BOOTP_HOSTNAME)
232c150a
WD
475 *e++ = 12; /* Hostname */
476 *cnt += 1;
3861aa5c 477#endif
1fe80d79 478#if defined(CONFIG_BOOTP_BOOTFILESIZE)
232c150a
WD
479 *e++ = 13; /* Boot File Size */
480 *cnt += 1;
3861aa5c 481#endif
1fe80d79 482#if defined(CONFIG_BOOTP_BOOTPATH)
232c150a
WD
483 *e++ = 17; /* Boot path */
484 *cnt += 1;
3861aa5c 485#endif
1fe80d79 486#if defined(CONFIG_BOOTP_NISDOMAIN)
232c150a
WD
487 *e++ = 40; /* NIS Domain name request */
488 *cnt += 1;
ea287deb 489#endif
1fe80d79 490#if defined(CONFIG_BOOTP_NTPSERVER)
ea287deb
WD
491 *e++ = 42;
492 *cnt += 1;
3861aa5c 493#endif
258ccd68
JL
494 /* no options, so back up to avoid sending an empty request list */
495 if (*cnt == 0)
496 e -= 2;
497
232c150a 498 *e++ = 255; /* End of the list */
3861aa5c 499
232c150a 500 /* Pad to minimal length */
3861aa5c 501#ifdef CONFIG_DHCP_MIN_EXT_LEN
21076f61 502 while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
232c150a 503 *e++ = 0;
3861aa5c
WD
504#endif
505
232c150a 506 return e - start;
3861aa5c
WD
507}
508
610f2e9c 509#else
3861aa5c 510/*
1fe80d79 511 * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
3861aa5c 512 */
232c150a 513static int BootpExtended (u8 * e)
3861aa5c 514{
232c150a 515 u8 *start = e;
3861aa5c 516
232c150a
WD
517 *e++ = 99; /* RFC1048 Magic Cookie */
518 *e++ = 130;
519 *e++ = 83;
520 *e++ = 99;
3861aa5c 521
643d1ab2 522#if defined(CONFIG_CMD_DHCP)
232c150a
WD
523 *e++ = 53; /* DHCP Message Type */
524 *e++ = 1;
525 *e++ = DHCP_DISCOVER;
526
527 *e++ = 57; /* Maximum DHCP Message Size */
528 *e++ = 2;
529 *e++ = (576 - 312 + OPT_SIZE) >> 16;
530 *e++ = (576 - 312 + OPT_SIZE) & 0xff;
610f2e9c 531#endif
3861aa5c 532
1fe80d79 533#if defined(CONFIG_BOOTP_SUBNETMASK)
232c150a
WD
534 *e++ = 1; /* Subnet mask request */
535 *e++ = 4;
536 e += 4;
3861aa5c
WD
537#endif
538
1fe80d79 539#if defined(CONFIG_BOOTP_GATEWAY)
232c150a
WD
540 *e++ = 3; /* Default gateway request */
541 *e++ = 4;
542 e += 4;
3861aa5c
WD
543#endif
544
1fe80d79 545#if defined(CONFIG_BOOTP_DNS)
232c150a
WD
546 *e++ = 6; /* Domain Name Server */
547 *e++ = 4;
548 e += 4;
3861aa5c
WD
549#endif
550
1fe80d79 551#if defined(CONFIG_BOOTP_HOSTNAME)
232c150a
WD
552 *e++ = 12; /* Host name request */
553 *e++ = 32;
554 e += 32;
3861aa5c
WD
555#endif
556
1fe80d79 557#if defined(CONFIG_BOOTP_BOOTFILESIZE)
232c150a
WD
558 *e++ = 13; /* Boot file size */
559 *e++ = 2;
560 e += 2;
3861aa5c
WD
561#endif
562
1fe80d79 563#if defined(CONFIG_BOOTP_BOOTPATH)
232c150a
WD
564 *e++ = 17; /* Boot path */
565 *e++ = 32;
566 e += 32;
3861aa5c
WD
567#endif
568
1fe80d79 569#if defined(CONFIG_BOOTP_NISDOMAIN)
232c150a
WD
570 *e++ = 40; /* NIS Domain name request */
571 *e++ = 32;
572 e += 32;
3861aa5c 573#endif
09e3a67d
LP
574#if defined(CONFIG_BOOTP_NTPSERVER)
575 *e++ = 42;
576 *e++ = 4;
577 e += 4;
578#endif
3861aa5c 579
232c150a 580 *e++ = 255; /* End of the list */
3861aa5c 581
232c150a 582 return e - start;
3861aa5c 583}
610f2e9c 584#endif
3861aa5c
WD
585
586void
587BootpRequest (void)
588{
db288a96 589 uchar *pkt, *iphdr;
3861aa5c
WD
590 Bootp_t *bp;
591 int ext_len, pktlen, iplen;
592
573f14fe 593 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
643d1ab2 594#if defined(CONFIG_CMD_DHCP)
3861aa5c
WD
595 dhcp_state = INIT;
596#endif
597
598#ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */
599 unsigned char bi_enetaddr[6];
600 int reg;
3861aa5c
WD
601 ulong tst1, tst2, sum, m_mask, m_value = 0;
602
603 if (BootpTry ==0) {
604 /* get our mac */
95823ca0
MF
605 eth_getenv_enetaddr("ethaddr", bi_enetaddr);
606
0ebf04c6
RG
607 debug("BootpRequest => Our Mac: ");
608 for (reg=0; reg<6; reg++)
609 debug("%x%c", bi_enetaddr[reg], reg==5 ? '\n' : ':');
3861aa5c
WD
610
611 /* Mac-Manipulation 2 get seed1 */
612 tst1=0;
613 tst2=0;
614 for (reg=2; reg<6; reg++) {
615 tst1 = tst1 << 8;
616 tst1 = tst1 | bi_enetaddr[reg];
617 }
618 for (reg=0; reg<2; reg++) {
619 tst2 = tst2 | bi_enetaddr[reg];
620 tst2 = tst2 << 8;
621 }
622
623 seed1 = tst1^tst2;
624
625 /* Mirror seed1*/
626 m_mask=0x1;
627 for (reg=1;reg<=32;reg++) {
628 m_value |= (m_mask & seed1);
629 seed1 = seed1 >> 1;
630 m_value = m_value << 1;
631 }
632 seed1 = m_value;
633 seed2 = 0xB78D0945;
634 }
635
636 /* Random Number Generator */
637
638 for (reg=0;reg<=0;reg++) {
639 sum = seed1 + seed2;
640 if (sum < seed1 || sum < seed2)
641 sum++;
8bde7f77 642 seed2 = seed1;
3861aa5c
WD
643 seed1 = sum;
644
645 if (BootpTry<=2) { /* Start with max 1024 * 1ms */
646 sum = sum >> (22-BootpTry);
647 } else { /*After 3rd BOOTP request max 8192 * 1ms */
648 sum = sum >> 19;
649 }
650 }
651
652 printf ("Random delay: %ld ms...\n", sum);
653 for (reg=0; reg <sum; reg++) {
654 udelay(1000); /*Wait 1ms*/
655 }
656#endif /* CONFIG_BOOTP_RANDOM_DELAY */
657
658 printf("BOOTP broadcast %d\n", ++BootpTry);
659 pkt = NetTxPacket;
660 memset ((void*)pkt, 0, PKTSIZE);
661
a3d991bd 662 pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
3861aa5c
WD
663
664 /*
665 * Next line results in incorrect packet size being transmitted, resulting
666 * in errors in some DHCP servers, reporting missing bytes. Size must be
667 * set in packet header after extension length has been determined.
668 * C. Hallinan, DS4.COM, Inc.
669 */
670 /* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (Bootp_t)); */
671 iphdr = pkt; /* We need this later for NetSetIP() */
672 pkt += IP_HDR_SIZE;
673
674 bp = (Bootp_t *)pkt;
675 bp->bp_op = OP_BOOTREQUEST;
676 bp->bp_htype = HWT_ETHER;
677 bp->bp_hlen = HWL_ETHER;
678 bp->bp_hops = 0;
49f3bdbb 679 bp->bp_secs = htons(get_timer(0) / 1000);
3861aa5c
WD
680 NetWriteIP(&bp->bp_ciaddr, 0);
681 NetWriteIP(&bp->bp_yiaddr, 0);
682 NetWriteIP(&bp->bp_siaddr, 0);
683 NetWriteIP(&bp->bp_giaddr, 0);
684 memcpy (bp->bp_chaddr, NetOurEther, 6);
685 copy_filename (bp->bp_file, BootFile, sizeof(bp->bp_file));
686
687 /* Request additional information from the BOOTP/DHCP server */
643d1ab2 688#if defined(CONFIG_CMD_DHCP)
77ddac94 689 ext_len = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
3861aa5c 690#else
77ddac94 691 ext_len = BootpExtended((u8 *)bp->bp_vend);
610f2e9c 692#endif
3861aa5c
WD
693
694 /*
695 * Bootp ID is the lower 4 bytes of our ethernet address
49f3bdbb 696 * plus the current time in ms.
3861aa5c
WD
697 */
698 BootpID = ((ulong)NetOurEther[2] << 24)
699 | ((ulong)NetOurEther[3] << 16)
700 | ((ulong)NetOurEther[4] << 8)
701 | (ulong)NetOurEther[5];
702 BootpID += get_timer(0);
232c150a 703 BootpID = htonl(BootpID);
3861aa5c
WD
704 NetCopyLong(&bp->bp_id, &BootpID);
705
706 /*
707 * Calculate proper packet lengths taking into account the
708 * variable size of the options field
709 */
c9a2aab1 710 pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
3861aa5c
WD
711 iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
712 NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
49f3bdbb 713 NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
3861aa5c 714
643d1ab2 715#if defined(CONFIG_CMD_DHCP)
3861aa5c
WD
716 dhcp_state = SELECTING;
717 NetSetHandler(DhcpHandler);
718#else
719 NetSetHandler(BootpHandler);
610f2e9c 720#endif
3861aa5c
WD
721 NetSendPacket(NetTxPacket, pktlen);
722}
723
643d1ab2 724#if defined(CONFIG_CMD_DHCP)
3b2e4fd9 725static void DhcpOptionsProcess (uchar * popt, Bootp_t *bp)
3861aa5c 726{
3e38691e 727 uchar *end = popt + BOOTP_HDR_SIZE;
3861aa5c 728 int oplen, size;
d8d8724b
WD
729#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
730 int *to_ptr;
731#endif
3861aa5c 732
232c150a 733 while (popt < end && *popt != 0xff) {
3861aa5c 734 oplen = *(popt + 1);
232c150a
WD
735 switch (*popt) {
736 case 1:
737 NetCopyIP (&NetOurSubnetMask, (popt + 2));
738 break;
1fe80d79 739#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
ea287deb 740 case 2: /* Time offset */
d8d8724b
WD
741 to_ptr = &NetTimeOffset;
742 NetCopyLong ((ulong *)to_ptr, (ulong *)(popt + 2));
ea287deb
WD
743 NetTimeOffset = ntohl (NetTimeOffset);
744 break;
745#endif
232c150a
WD
746 case 3:
747 NetCopyIP (&NetOurGatewayIP, (popt + 2));
748 break;
749 case 6:
750 NetCopyIP (&NetOurDNSIP, (popt + 2));
1fe80d79 751#if defined(CONFIG_BOOTP_DNS2)
232c150a
WD
752 if (*(popt + 1) > 4) {
753 NetCopyIP (&NetOurDNS2IP, (popt + 2 + 4));
754 }
fe389a82 755#endif
232c150a
WD
756 break;
757 case 12:
758 size = truncate_sz ("Host Name", sizeof (NetOurHostName), oplen);
759 memcpy (&NetOurHostName, popt + 2, size);
760 NetOurHostName[size] = 0;
761 break;
762 case 15: /* Ignore Domain Name Option */
763 break;
764 case 17:
765 size = truncate_sz ("Root Path", sizeof (NetOurRootPath), oplen);
766 memcpy (&NetOurRootPath, popt + 2, size);
767 NetOurRootPath[size] = 0;
768 break;
1fe80d79 769#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
ea287deb
WD
770 case 42: /* NTP server IP */
771 NetCopyIP (&NetNtpServerIP, (popt + 2));
772 break;
773#endif
232c150a
WD
774 case 51:
775 NetCopyLong (&dhcp_leasetime, (ulong *) (popt + 2));
776 break;
777 case 53: /* Ignore Message Type Option */
778 break;
779 case 54:
780 NetCopyIP (&NetDHCPServerIP, (popt + 2));
781 break;
782 case 58: /* Ignore Renewal Time Option */
783 break;
784 case 59: /* Ignore Rebinding Time Option */
785 break;
3b2e4fd9
WD
786 case 66: /* Ignore TFTP server name */
787 break;
788 case 67: /* vendor opt bootfile */
789 /*
790 * I can't use dhcp_vendorex_proc here because I need
791 * to write into the bootp packet - even then I had to
792 * pass the bootp packet pointer into here as the
793 * second arg
794 */
795 size = truncate_sz ("Opt Boot File",
796 sizeof(bp->bp_file),
797 oplen);
798 if (bp->bp_file[0] == '\0' && size > 0) {
799 /*
800 * only use vendor boot file if we didn't
801 * receive a boot file in the main non-vendor
802 * part of the packet - god only knows why
803 * some vendors chose not to use this perfectly
804 * good spot to store the boot file (join on
805 * Tru64 Unix) it seems mind bogglingly crazy
806 * to me
807 */
808 printf("*** WARNING: using vendor "
809 "optional boot file\n");
810 memcpy(bp->bp_file, popt + 2, size);
811 bp->bp_file[size] = '\0';
812 }
813 break;
232c150a 814 default:
1fe80d79 815#if defined(CONFIG_BOOTP_VENDOREX)
232c150a 816 if (dhcp_vendorex_proc (popt))
8bde7f77 817 break;
3861aa5c 818#endif
232c150a
WD
819 printf ("*** Unhandled DHCP Option in OFFER/ACK: %d\n", *popt);
820 break;
3861aa5c
WD
821 }
822 popt += oplen + 2; /* Process next option */
823 }
824}
825
826static int DhcpMessageType(unsigned char *popt)
827{
828 if (NetReadLong((ulong*)popt) != htonl(BOOTP_VENDOR_MAGIC))
829 return -1;
830
831 popt += 4;
832 while ( *popt != 0xff ) {
833 if ( *popt == 53 ) /* DHCP Message Type */
834 return *(popt + 2);
835 popt += *(popt + 1) + 2; /* Scan through all options */
836 }
837 return -1;
838}
839
3e38691e 840static void DhcpSendRequestPkt(Bootp_t *bp_offer)
3861aa5c 841{
db288a96 842 uchar *pkt, *iphdr;
3861aa5c
WD
843 Bootp_t *bp;
844 int pktlen, iplen, extlen;
47cd00fa 845 IPaddr_t OfferedIP;
3861aa5c 846
0ebf04c6 847 debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
3861aa5c
WD
848 pkt = NetTxPacket;
849 memset ((void*)pkt, 0, PKTSIZE);
850
a3d991bd 851 pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
3861aa5c
WD
852
853 iphdr = pkt; /* We'll need this later to set proper pkt size */
854 pkt += IP_HDR_SIZE;
855
856 bp = (Bootp_t *)pkt;
857 bp->bp_op = OP_BOOTREQUEST;
858 bp->bp_htype = HWT_ETHER;
859 bp->bp_hlen = HWL_ETHER;
860 bp->bp_hops = 0;
49f3bdbb 861 bp->bp_secs = htons(get_timer(0) / 1000);
e5c794e4
JF
862 /* Do not set the client IP, your IP, or server IP yet, since it hasn't been ACK'ed by
863 * the server yet */
864
c6686703 865 /*
d82718fe
WD
866 * RFC3046 requires Relay Agents to discard packets with
867 * nonzero and offered giaddr
868 */
869 NetWriteIP(&bp->bp_giaddr, 0);
870
3861aa5c
WD
871 memcpy (bp->bp_chaddr, NetOurEther, 6);
872
873 /*
874 * ID is the id of the OFFER packet
875 */
876
877 NetCopyLong(&bp->bp_id, &bp_offer->bp_id);
878
879 /*
880 * Copy options from OFFER packet if present
881 */
e5c794e4
JF
882
883 /* Copy offered IP into the parameters request list */
884 NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr);
77ddac94 885 extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP);
3861aa5c 886
c9a2aab1 887 pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
3861aa5c
WD
888 iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
889 NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
890
0ebf04c6 891 debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
d9a2f416
AV
892#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
893 udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
894#endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
3861aa5c
WD
895 NetSendPacket(NetTxPacket, pktlen);
896}
897
898/*
899 * Handle DHCP received packets.
900 */
901static void
03eb129f
LC
902DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
903 unsigned len)
3861aa5c
WD
904{
905 Bootp_t *bp = (Bootp_t *)pkt;
906
0ebf04c6 907 debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
3861aa5c
WD
908 src, dest, len, dhcp_state);
909
232c150a 910 if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
3861aa5c
WD
911 return;
912
0ebf04c6 913 debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n",
3861aa5c
WD
914 src, dest, len, dhcp_state);
915
916 switch (dhcp_state) {
917 case SELECTING:
918 /*
919 * Wait an appropriate time for any potential DHCPOFFER packets
920 * to arrive. Then select one, and generate DHCPREQUEST response.
921 * If filename is in format we recognize, assume it is a valid
922 * OFFER from a server we want.
923 */
0ebf04c6 924 debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
6d0f6bcf 925#ifdef CONFIG_SYS_BOOTFILE_PREFIX
3861aa5c 926 if (strncmp(bp->bp_file,
6d0f6bcf
JCPV
927 CONFIG_SYS_BOOTFILE_PREFIX,
928 strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0 ) {
929#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
3861aa5c 930
0ebf04c6 931 debug("TRANSITIONING TO REQUESTING STATE\n");
3861aa5c 932 dhcp_state = REQUESTING;
759a51b4 933
3861aa5c 934 if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
3b2e4fd9 935 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
3861aa5c 936
49f3bdbb 937 NetSetTimeout(TIMEOUT, BootpTimeout);
3861aa5c 938 DhcpSendRequestPkt(bp);
6d0f6bcf 939#ifdef CONFIG_SYS_BOOTFILE_PREFIX
3861aa5c 940 }
6d0f6bcf 941#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
3861aa5c
WD
942
943 return;
944 break;
945 case REQUESTING:
0ebf04c6 946 debug("DHCP State: REQUESTING\n");
3861aa5c 947
77ddac94 948 if ( DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK ) {
3861aa5c 949 if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
3b2e4fd9 950 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
232c150a 951 BootpCopyNetParams(bp); /* Store net params from reply */
3861aa5c 952 dhcp_state = BOUND;
b6446b67 953 printf ("DHCP client bound to address %pI4\n", &NetOurIP);
573f14fe
SG
954 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
955 "bootp_stop");
3861aa5c 956
e4a3d57d 957 net_auto_load();
3861aa5c
WD
958 return;
959 }
960 break;
51dfe138
RB
961 case BOUND:
962 /* DHCP client bound to address */
963 break;
3861aa5c 964 default:
4b9206ed 965 puts ("DHCP: INVALID STATE\n");
3861aa5c
WD
966 break;
967 }
968
969}
970
971void DhcpRequest(void)
972{
973 BootpRequest();
974}
992742a5 975#endif /* CONFIG_CMD_DHCP */