blob: a4f6db570c6c956db2e4e18d94b6923f5458ff4e [file] [log] [blame]
wdenk3861aa52002-09-27 23:19:37 +00001/*
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
wdenk29e7f5a2004-03-12 00:14:09 +00008 * Copyright 2000-2004 Wolfgang Denk, wd@denx.de
wdenk3861aa52002-09-27 23:19:37 +00009 */
10
wdenk3861aa52002-09-27 23:19:37 +000011#include <common.h>
12#include <command.h>
13#include <net.h>
14#include "bootp.h"
15#include "tftp.h"
wdenk29e7f5a2004-03-12 00:14:09 +000016#include "nfs.h"
wdenk3861aa52002-09-27 23:19:37 +000017#ifdef CONFIG_STATUS_LED
18#include <status_led.h>
19#endif
Kim Phillips576175b2012-07-05 13:19:32 +000020#ifdef CONFIG_BOOTP_RANDOM_DELAY
21#include "net_rand.h"
22#endif
wdenk3861aa52002-09-27 23:19:37 +000023
Joe Hershberger8f4b1352012-05-15 08:59:06 +000024#define BOOTP_VENDOR_MAGIC 0x63825363 /* RFC1048 Magic Cookie */
wdenk3861aa52002-09-27 23:19:37 +000025
Stephen Warren69e1e352014-07-25 17:30:48 -060026/*
27 * The timeout for the initial BOOTP/DHCP request used to be described by a
28 * counter of fixed-length timeout periods. TIMEOUT_COUNT represents
29 * that counter
30 *
31 * Now that the timeout periods are variable (exponential backoff and retry)
32 * we convert the timeout count to the absolute time it would have take to
33 * execute that many retries, and keep sending retry packets until that time
34 * is reached.
35 */
wdenk29e7f5a2004-03-12 00:14:09 +000036#ifndef CONFIG_NET_RETRY_COUNT
Joe Hershberger8f4b1352012-05-15 08:59:06 +000037# define TIMEOUT_COUNT 5 /* # of timeouts before giving up */
wdenk3861aa52002-09-27 23:19:37 +000038#else
wdenk29e7f5a2004-03-12 00:14:09 +000039# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
wdenk3861aa52002-09-27 23:19:37 +000040#endif
Stephen Warren69e1e352014-07-25 17:30:48 -060041#define TIMEOUT_MS ((3 + (TIMEOUT_COUNT * 5)) * 1000)
wdenk3861aa52002-09-27 23:19:37 +000042
Joe Hershberger8f4b1352012-05-15 08:59:06 +000043#define PORT_BOOTPS 67 /* BOOTP server UDP port */
44#define PORT_BOOTPC 68 /* BOOTP client UDP port */
wdenk3861aa52002-09-27 23:19:37 +000045
Joe Hershberger8f4b1352012-05-15 08:59:06 +000046#ifndef CONFIG_DHCP_MIN_EXT_LEN /* minimal length of extension list */
wdenk29e7f5a2004-03-12 00:14:09 +000047#define CONFIG_DHCP_MIN_EXT_LEN 64
wdenk3861aa52002-09-27 23:19:37 +000048#endif
49
50ulong BootpID;
51int BootpTry;
Stephen Warren69e1e352014-07-25 17:30:48 -060052ulong bootp_start;
53ulong bootp_timeout;
wdenk3861aa52002-09-27 23:19:37 +000054
Jon Loeliger54f35c22007-07-09 17:45:14 -050055#if defined(CONFIG_CMD_DHCP)
Kim Phillips40c2c032012-10-29 13:34:33 +000056static dhcp_state_t dhcp_state = INIT;
57static unsigned long dhcp_leasetime;
58static IPaddr_t NetDHCPServerIP;
Luca Ceresoli428ab362011-04-18 06:19:50 +000059static void DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
60 unsigned len);
wdenk3861aa52002-09-27 23:19:37 +000061
62/* For Debug */
wdenkb02744a2003-04-05 00:53:31 +000063#if 0
64static char *dhcpmsg2str(int type)
wdenk3861aa52002-09-27 23:19:37 +000065{
66 switch (type) {
wdenk29e7f5a2004-03-12 00:14:09 +000067 case 1: return "DHCPDISCOVER"; break;
68 case 2: return "DHCPOFFER"; break;
69 case 3: return "DHCPREQUEST"; break;
70 case 4: return "DHCPDECLINE"; break;
71 case 5: return "DHCPACK"; break;
72 case 6: return "DHCPNACK"; break;
73 case 7: return "DHCPRELEASE"; break;
wdenk3861aa52002-09-27 23:19:37 +000074 default: return "UNKNOWN/INVALID MSG TYPE"; break;
75 }
76}
wdenkb02744a2003-04-05 00:53:31 +000077#endif
Jon Loeligera9807e52007-07-10 11:05:02 -050078#endif
wdenk3861aa52002-09-27 23:19:37 +000079
80static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
81{
Joe Hershberger8f4b1352012-05-15 08:59:06 +000082 struct Bootp_t *bp = (struct Bootp_t *) pkt;
wdenk3861aa52002-09-27 23:19:37 +000083 int retval = 0;
84
85 if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
86 retval = -1;
Joe Hershbergerceba4472012-05-23 07:58:14 +000087 else if (len < sizeof(struct Bootp_t) - OPT_FIELD_SIZE)
wdenk3861aa52002-09-27 23:19:37 +000088 retval = -2;
89 else if (bp->bp_op != OP_BOOTREQUEST &&
Joe Hershberger8f4b1352012-05-15 08:59:06 +000090 bp->bp_op != OP_BOOTREPLY &&
91 bp->bp_op != DHCP_OFFER &&
92 bp->bp_op != DHCP_ACK &&
93 bp->bp_op != DHCP_NAK)
wdenk3861aa52002-09-27 23:19:37 +000094 retval = -3;
wdenk3861aa52002-09-27 23:19:37 +000095 else if (bp->bp_htype != HWT_ETHER)
96 retval = -4;
97 else if (bp->bp_hlen != HWL_ETHER)
98 retval = -5;
Joe Hershberger8f4b1352012-05-15 08:59:06 +000099 else if (NetReadLong((ulong *)&bp->bp_id) != BootpID)
wdenk3861aa52002-09-27 23:19:37 +0000100 retval = -6;
wdenk3861aa52002-09-27 23:19:37 +0000101
Robin Getz9e0a4d62009-07-23 03:01:03 -0400102 debug("Filtering pkt = %d\n", retval);
wdenk3861aa52002-09-27 23:19:37 +0000103
104 return retval;
105}
106
107/*
108 * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
109 */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000110static void BootpCopyNetParams(struct Bootp_t *bp)
wdenk3861aa52002-09-27 23:19:37 +0000111{
Wilson Callan22bcd6e2007-07-28 10:56:13 -0400112#if !defined(CONFIG_BOOTP_SERVERIP)
Joe Hershberger9d37a582012-05-23 07:59:18 +0000113 IPaddr_t tmp_ip;
114
wdenk4989f872004-03-14 15:06:13 +0000115 NetCopyIP(&tmp_ip, &bp->bp_siaddr);
116 if (tmp_ip != 0)
117 NetCopyIP(&NetServerIP, &bp->bp_siaddr);
Joe Hershberger1178f412012-05-23 07:58:06 +0000118 memcpy(NetServerEther, ((struct ethernet_hdr *)NetRxPacket)->et_src, 6);
Wilson Callan22bcd6e2007-07-28 10:56:13 -0400119#endif
Joe Hershberger9d37a582012-05-23 07:59:18 +0000120 NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
wdenk4989f872004-03-14 15:06:13 +0000121 if (strlen(bp->bp_file) > 0)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000122 copy_filename(BootFile, bp->bp_file, sizeof(BootFile));
wdenk3861aa52002-09-27 23:19:37 +0000123
Robin Getz9e0a4d62009-07-23 03:01:03 -0400124 debug("Bootfile: %s\n", BootFile);
wdenk3861aa52002-09-27 23:19:37 +0000125
126 /* Propagate to environment:
wdenk57b2d802003-06-27 21:31:46 +0000127 * don't delete exising entry when BOOTP / DHCP reply does
wdenk3861aa52002-09-27 23:19:37 +0000128 * not contain a new value
129 */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000130 if (*BootFile)
131 setenv("bootfile", BootFile);
wdenk3861aa52002-09-27 23:19:37 +0000132}
133
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000134static int truncate_sz(const char *name, int maxlen, int curlen)
wdenk3861aa52002-09-27 23:19:37 +0000135{
136 if (curlen >= maxlen) {
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000137 printf("*** WARNING: %s is too long (%d - max: %d)"
138 " - truncated\n", name, curlen, maxlen);
wdenk3861aa52002-09-27 23:19:37 +0000139 curlen = maxlen - 1;
140 }
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000141 return curlen;
wdenk3861aa52002-09-27 23:19:37 +0000142}
143
Jon Loeliger54f35c22007-07-09 17:45:14 -0500144#if !defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000145
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000146static void BootpVendorFieldProcess(u8 *ext)
wdenk3861aa52002-09-27 23:19:37 +0000147{
wdenk29e7f5a2004-03-12 00:14:09 +0000148 int size = *(ext + 1);
wdenk3861aa52002-09-27 23:19:37 +0000149
Robin Getz9e0a4d62009-07-23 03:01:03 -0400150 debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000151 *(ext + 1));
wdenk3861aa52002-09-27 23:19:37 +0000152
wdenk29e7f5a2004-03-12 00:14:09 +0000153 NetBootFileSize = 0;
wdenk3861aa52002-09-27 23:19:37 +0000154
wdenk29e7f5a2004-03-12 00:14:09 +0000155 switch (*ext) {
156 /* Fixed length fields */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000157 case 1: /* Subnet mask */
wdenk3861aa52002-09-27 23:19:37 +0000158 if (NetOurSubnetMask == 0)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000159 NetCopyIP(&NetOurSubnetMask, (IPaddr_t *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000160 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000161 case 2: /* Time offset - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000162 break;
wdenk29e7f5a2004-03-12 00:14:09 +0000163 /* Variable length fields */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000164 case 3: /* Gateways list */
165 if (NetOurGatewayIP == 0)
166 NetCopyIP(&NetOurGatewayIP, (IPaddr_t *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000167 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000168 case 4: /* Time server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000169 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000170 case 5: /* IEN-116 name server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000171 break;
172 case 6:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000173 if (NetOurDNSIP == 0)
174 NetCopyIP(&NetOurDNSIP, (IPaddr_t *) (ext + 2));
Jon Loeliger5336a762007-07-09 22:08:34 -0500175#if defined(CONFIG_BOOTP_DNS2)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000176 if ((NetOurDNS2IP == 0) && (size > 4))
177 NetCopyIP(&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4));
stroesee0aadfb2003-08-28 14:17:32 +0000178#endif
wdenk3861aa52002-09-27 23:19:37 +0000179 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000180 case 7: /* Log server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000181 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000182 case 8: /* Cookie/Quote server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000183 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000184 case 9: /* LPR server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000185 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000186 case 10: /* Impress server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000187 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000188 case 11: /* RPL server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000189 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000190 case 12: /* Host name */
wdenk3861aa52002-09-27 23:19:37 +0000191 if (NetOurHostName[0] == 0) {
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000192 size = truncate_sz("Host Name",
193 sizeof(NetOurHostName), size);
194 memcpy(&NetOurHostName, ext + 2, size);
wdenk29e7f5a2004-03-12 00:14:09 +0000195 NetOurHostName[size] = 0;
wdenk3861aa52002-09-27 23:19:37 +0000196 }
197 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000198 case 13: /* Boot file size */
wdenk3861aa52002-09-27 23:19:37 +0000199 if (size == 2)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000200 NetBootFileSize = ntohs(*(ushort *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000201 else if (size == 4)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000202 NetBootFileSize = ntohl(*(ulong *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000203 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000204 case 14: /* Merit dump file - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000205 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000206 case 15: /* Domain name - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000207 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000208 case 16: /* Swap server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000209 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000210 case 17: /* Root path */
wdenk3861aa52002-09-27 23:19:37 +0000211 if (NetOurRootPath[0] == 0) {
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000212 size = truncate_sz("Root Path",
213 sizeof(NetOurRootPath), size);
214 memcpy(&NetOurRootPath, ext + 2, size);
wdenk29e7f5a2004-03-12 00:14:09 +0000215 NetOurRootPath[size] = 0;
wdenk3861aa52002-09-27 23:19:37 +0000216 }
217 break;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000218 case 18: /* Extension path - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000219 /*
wdenk57b2d802003-06-27 21:31:46 +0000220 * This can be used to send the information of the
221 * vendor area in another file that the client can
222 * access via TFTP.
wdenk3861aa52002-09-27 23:19:37 +0000223 */
224 break;
wdenk29e7f5a2004-03-12 00:14:09 +0000225 /* IP host layer fields */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000226 case 40: /* NIS Domain name */
wdenk3861aa52002-09-27 23:19:37 +0000227 if (NetOurNISDomain[0] == 0) {
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000228 size = truncate_sz("NIS Domain Name",
229 sizeof(NetOurNISDomain), size);
230 memcpy(&NetOurNISDomain, ext + 2, size);
wdenk29e7f5a2004-03-12 00:14:09 +0000231 NetOurNISDomain[size] = 0;
wdenk3861aa52002-09-27 23:19:37 +0000232 }
233 break;
Luuk Paulussen6380e012011-05-16 18:29:19 +0000234#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
235 case 42: /* NTP server IP */
236 NetCopyIP(&NetNtpServerIP, (IPaddr_t *) (ext + 2));
237 break;
238#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000239 /* Application layer fields */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000240 case 43: /* Vendor specific info - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000241 /*
wdenk57b2d802003-06-27 21:31:46 +0000242 * Binary information to exchange specific
243 * product information.
wdenk3861aa52002-09-27 23:19:37 +0000244 */
245 break;
wdenk29e7f5a2004-03-12 00:14:09 +0000246 /* Reserved (custom) fields (128..254) */
247 }
wdenk3861aa52002-09-27 23:19:37 +0000248}
249
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000250static void BootpVendorProcess(u8 *ext, int size)
wdenk3861aa52002-09-27 23:19:37 +0000251{
wdenk29e7f5a2004-03-12 00:14:09 +0000252 u8 *end = ext + size;
wdenk3861aa52002-09-27 23:19:37 +0000253
Robin Getz9e0a4d62009-07-23 03:01:03 -0400254 debug("[BOOTP] Checking extension (%d bytes)...\n", size);
wdenk3861aa52002-09-27 23:19:37 +0000255
wdenk29e7f5a2004-03-12 00:14:09 +0000256 while ((ext < end) && (*ext != 0xff)) {
257 if (*ext == 0) {
258 ext++;
259 } else {
260 u8 *opt = ext;
261
262 ext += ext[1] + 2;
263 if (ext <= end)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000264 BootpVendorFieldProcess(opt);
wdenk29e7f5a2004-03-12 00:14:09 +0000265 }
wdenk3861aa52002-09-27 23:19:37 +0000266 }
wdenk3861aa52002-09-27 23:19:37 +0000267
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000268 debug("[BOOTP] Received fields:\n");
Mike Frysingerd5695f42009-02-17 00:00:53 -0500269 if (NetOurSubnetMask)
Robin Getz9e0a4d62009-07-23 03:01:03 -0400270 debug("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask);
wdenk3861aa52002-09-27 23:19:37 +0000271
Mike Frysingerd5695f42009-02-17 00:00:53 -0500272 if (NetOurGatewayIP)
Robin Getz9e0a4d62009-07-23 03:01:03 -0400273 debug("NetOurGatewayIP : %pI4", &NetOurGatewayIP);
wdenk3861aa52002-09-27 23:19:37 +0000274
Robin Getz9e0a4d62009-07-23 03:01:03 -0400275 if (NetBootFileSize)
276 debug("NetBootFileSize : %d\n", NetBootFileSize);
wdenk3861aa52002-09-27 23:19:37 +0000277
Robin Getz9e0a4d62009-07-23 03:01:03 -0400278 if (NetOurHostName[0])
279 debug("NetOurHostName : %s\n", NetOurHostName);
wdenk3861aa52002-09-27 23:19:37 +0000280
Robin Getz9e0a4d62009-07-23 03:01:03 -0400281 if (NetOurRootPath[0])
282 debug("NetOurRootPath : %s\n", NetOurRootPath);
wdenk3861aa52002-09-27 23:19:37 +0000283
Robin Getz9e0a4d62009-07-23 03:01:03 -0400284 if (NetOurNISDomain[0])
285 debug("NetOurNISDomain : %s\n", NetOurNISDomain);
wdenk3861aa52002-09-27 23:19:37 +0000286
Robin Getz9e0a4d62009-07-23 03:01:03 -0400287 if (NetBootFileSize)
288 debug("NetBootFileSize: %d\n", NetBootFileSize);
Luuk Paulussen6380e012011-05-16 18:29:19 +0000289
290#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
291 if (NetNtpServerIP)
292 debug("NetNtpServerIP : %pI4\n", &NetNtpServerIP);
293#endif
wdenk3861aa52002-09-27 23:19:37 +0000294}
Simon Glassab068eb2011-06-13 16:13:12 -0700295
wdenk3861aa52002-09-27 23:19:37 +0000296/*
297 * Handle a BOOTP received packet.
298 */
299static void
Luca Ceresoli428ab362011-04-18 06:19:50 +0000300BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
301 unsigned len)
wdenk3861aa52002-09-27 23:19:37 +0000302{
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000303 struct Bootp_t *bp;
wdenk3861aa52002-09-27 23:19:37 +0000304
Robin Getz9e0a4d62009-07-23 03:01:03 -0400305 debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000306 src, dest, len, sizeof(struct Bootp_t));
wdenk3861aa52002-09-27 23:19:37 +0000307
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000308 bp = (struct Bootp_t *)pkt;
wdenk3861aa52002-09-27 23:19:37 +0000309
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000310 /* Filter out pkts we don't want */
311 if (BootpCheckPkt(pkt, dest, src, len))
wdenk3861aa52002-09-27 23:19:37 +0000312 return;
313
314 /*
wdenk29e7f5a2004-03-12 00:14:09 +0000315 * Got a good BOOTP reply. Copy the data into our variables.
wdenk3861aa52002-09-27 23:19:37 +0000316 */
317#ifdef CONFIG_STATUS_LED
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000318 status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF);
wdenk3861aa52002-09-27 23:19:37 +0000319#endif
320
321 BootpCopyNetParams(bp); /* Store net parameters from reply */
322
323 /* Retrieve extended information (we must parse the vendor area) */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000324 if (NetReadLong((ulong *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200325 BootpVendorProcess((uchar *)&bp->bp_vend[4], len);
wdenk3861aa52002-09-27 23:19:37 +0000326
327 NetSetTimeout(0, (thand_f *)0);
Simon Glass768cbf02011-12-10 11:08:06 +0000328 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
wdenk3861aa52002-09-27 23:19:37 +0000329
Robin Getz9e0a4d62009-07-23 03:01:03 -0400330 debug("Got good BOOTP\n");
wdenk3861aa52002-09-27 23:19:37 +0000331
Simon Glass5234ad12011-10-27 06:24:32 +0000332 net_auto_load();
wdenk3861aa52002-09-27 23:19:37 +0000333}
Jon Loeligera9807e52007-07-10 11:05:02 -0500334#endif
wdenk3861aa52002-09-27 23:19:37 +0000335
336/*
337 * Timeout on BOOTP/DHCP request.
338 */
339static void
340BootpTimeout(void)
341{
Stephen Warren69e1e352014-07-25 17:30:48 -0600342 ulong time_taken = get_timer(bootp_start);
343
344 if (time_taken >= TIMEOUT_MS) {
Joe Hershberger8ca7fa02012-05-23 07:59:19 +0000345#ifdef CONFIG_BOOTP_MAY_FAIL
Stephen Warren69e1e352014-07-25 17:30:48 -0600346 puts("\nRetry time exceeded\n");
benoit.thebaudeau@advans7232ee52012-07-19 01:23:21 +0000347 net_set_state(NETLOOP_FAIL);
Joe Hershberger8ca7fa02012-05-23 07:59:19 +0000348#else
Stephen Warren69e1e352014-07-25 17:30:48 -0600349 puts("\nRetry time exceeded; starting again\n");
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000350 NetStartAgain();
Joe Hershberger8ca7fa02012-05-23 07:59:19 +0000351#endif
wdenk3861aa52002-09-27 23:19:37 +0000352 } else {
Stephen Warren69e1e352014-07-25 17:30:48 -0600353 bootp_timeout *= 2;
354 if (bootp_timeout > 1000)
355 bootp_timeout = 1000;
356 NetSetTimeout(bootp_timeout, BootpTimeout);
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000357 BootpRequest();
wdenk3861aa52002-09-27 23:19:37 +0000358 }
359}
360
Ilya Yanok30876582012-09-17 10:26:25 +0000361#define put_vci(e, str) \
362 do { \
363 size_t vci_strlen = strlen(str); \
364 *e++ = 60; /* Vendor Class Identifier */ \
365 *e++ = vci_strlen; \
366 memcpy(e, str, vci_strlen); \
367 e += vci_strlen; \
368 } while (0)
369
wdenk3861aa52002-09-27 23:19:37 +0000370/*
371 * Initialize BOOTP extension fields in the request.
372 */
Jon Loeliger54f35c22007-07-09 17:45:14 -0500373#if defined(CONFIG_CMD_DHCP)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000374static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID,
375 IPaddr_t RequestedIP)
wdenk3861aa52002-09-27 23:19:37 +0000376{
wdenk29e7f5a2004-03-12 00:14:09 +0000377 u8 *start = e;
378 u8 *cnt;
Jason Hobbsea3202812011-08-31 05:37:31 +0000379#if defined(CONFIG_BOOTP_PXE)
380 char *uuid;
Jason Hobbsea3202812011-08-31 05:37:31 +0000381 u16 clientarch;
382#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000383
Jon Loeliger5336a762007-07-09 22:08:34 -0500384#if defined(CONFIG_BOOTP_VENDOREX)
wdenk29e7f5a2004-03-12 00:14:09 +0000385 u8 *x;
wdenk3861aa52002-09-27 23:19:37 +0000386#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500387#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200388 char *hostname;
stroesee0aadfb2003-08-28 14:17:32 +0000389#endif
wdenk3861aa52002-09-27 23:19:37 +0000390
wdenk29e7f5a2004-03-12 00:14:09 +0000391 *e++ = 99; /* RFC1048 Magic Cookie */
392 *e++ = 130;
393 *e++ = 83;
394 *e++ = 99;
wdenk3861aa52002-09-27 23:19:37 +0000395
wdenk29e7f5a2004-03-12 00:14:09 +0000396 *e++ = 53; /* DHCP Message Type */
397 *e++ = 1;
398 *e++ = message_type;
wdenk3861aa52002-09-27 23:19:37 +0000399
wdenk29e7f5a2004-03-12 00:14:09 +0000400 *e++ = 57; /* Maximum DHCP Message Size */
401 *e++ = 2;
Joe Hershbergerceba4472012-05-23 07:58:14 +0000402 *e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8;
403 *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
wdenk3861aa52002-09-27 23:19:37 +0000404
wdenk29e7f5a2004-03-12 00:14:09 +0000405 if (ServerID) {
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000406 int tmp = ntohl(ServerID);
wdenk3861aa52002-09-27 23:19:37 +0000407
wdenk29e7f5a2004-03-12 00:14:09 +0000408 *e++ = 54; /* ServerID */
409 *e++ = 4;
410 *e++ = tmp >> 24;
411 *e++ = tmp >> 16;
412 *e++ = tmp >> 8;
413 *e++ = tmp & 0xff;
414 }
wdenk3861aa52002-09-27 23:19:37 +0000415
wdenk29e7f5a2004-03-12 00:14:09 +0000416 if (RequestedIP) {
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000417 int tmp = ntohl(RequestedIP);
wdenk3861aa52002-09-27 23:19:37 +0000418
wdenk29e7f5a2004-03-12 00:14:09 +0000419 *e++ = 50; /* Requested IP */
420 *e++ = 4;
421 *e++ = tmp >> 24;
422 *e++ = tmp >> 16;
423 *e++ = tmp >> 8;
424 *e++ = tmp & 0xff;
425 }
Jon Loeliger5336a762007-07-09 22:08:34 -0500426#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000427 hostname = getenv("hostname");
428 if (hostname) {
429 int hostnamelen = strlen(hostname);
wdenk29e7f5a2004-03-12 00:14:09 +0000430
431 *e++ = 12; /* Hostname */
432 *e++ = hostnamelen;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000433 memcpy(e, hostname, hostnamelen);
wdenk29e7f5a2004-03-12 00:14:09 +0000434 e += hostnamelen;
435 }
Jason Hobbsea3202812011-08-31 05:37:31 +0000436#endif
437
438#if defined(CONFIG_BOOTP_PXE)
439 clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
440 *e++ = 93; /* Client System Architecture */
441 *e++ = 2;
442 *e++ = (clientarch >> 8) & 0xff;
443 *e++ = clientarch & 0xff;
444
445 *e++ = 94; /* Client Network Interface Identifier */
446 *e++ = 3;
447 *e++ = 1; /* type field for UNDI */
448 *e++ = 0; /* major revision */
449 *e++ = 0; /* minor revision */
450
451 uuid = getenv("pxeuuid");
452
453 if (uuid) {
454 if (uuid_str_valid(uuid)) {
455 *e++ = 97; /* Client Machine Identifier */
456 *e++ = 17;
457 *e++ = 0; /* type 0 - UUID */
458
Przemyslaw Marczak0c813362014-04-02 10:20:03 +0200459 uuid_str_to_bin(uuid, e, UUID_STR_FORMAT_STD);
Jason Hobbsea3202812011-08-31 05:37:31 +0000460 e += 16;
461 } else {
462 printf("Invalid pxeuuid: %s\n", uuid);
463 }
464 }
Ilya Yanok30876582012-09-17 10:26:25 +0000465#endif
Jason Hobbsea3202812011-08-31 05:37:31 +0000466
Ilya Yanok30876582012-09-17 10:26:25 +0000467#ifdef CONFIG_BOOTP_VCI_STRING
468 put_vci(e, CONFIG_BOOTP_VCI_STRING);
stroesee0aadfb2003-08-28 14:17:32 +0000469#endif
470
Jon Loeliger5336a762007-07-09 22:08:34 -0500471#if defined(CONFIG_BOOTP_VENDOREX)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000472 x = dhcp_vendorex_prep(e);
473 if (x)
wdenk29e7f5a2004-03-12 00:14:09 +0000474 return x - start;
wdenk3861aa52002-09-27 23:19:37 +0000475#endif
476
wdenk29e7f5a2004-03-12 00:14:09 +0000477 *e++ = 55; /* Parameter Request List */
478 cnt = e++; /* Pointer to count of requested items */
479 *cnt = 0;
Jon Loeliger5336a762007-07-09 22:08:34 -0500480#if defined(CONFIG_BOOTP_SUBNETMASK)
wdenk29e7f5a2004-03-12 00:14:09 +0000481 *e++ = 1; /* Subnet Mask */
482 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000483#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500484#if defined(CONFIG_BOOTP_TIMEOFFSET)
wdenkb4ad9622005-04-01 00:25:43 +0000485 *e++ = 2;
486 *cnt += 1;
487#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500488#if defined(CONFIG_BOOTP_GATEWAY)
wdenk29e7f5a2004-03-12 00:14:09 +0000489 *e++ = 3; /* Router Option */
490 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000491#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500492#if defined(CONFIG_BOOTP_DNS)
wdenk29e7f5a2004-03-12 00:14:09 +0000493 *e++ = 6; /* DNS Server(s) */
494 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000495#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500496#if defined(CONFIG_BOOTP_HOSTNAME)
wdenk29e7f5a2004-03-12 00:14:09 +0000497 *e++ = 12; /* Hostname */
498 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000499#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500500#if defined(CONFIG_BOOTP_BOOTFILESIZE)
wdenk29e7f5a2004-03-12 00:14:09 +0000501 *e++ = 13; /* Boot File Size */
502 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000503#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500504#if defined(CONFIG_BOOTP_BOOTPATH)
wdenk29e7f5a2004-03-12 00:14:09 +0000505 *e++ = 17; /* Boot path */
506 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000507#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500508#if defined(CONFIG_BOOTP_NISDOMAIN)
wdenk29e7f5a2004-03-12 00:14:09 +0000509 *e++ = 40; /* NIS Domain name request */
510 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000511#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500512#if defined(CONFIG_BOOTP_NTPSERVER)
wdenkb4ad9622005-04-01 00:25:43 +0000513 *e++ = 42;
514 *cnt += 1;
515#endif
Jason Liu1c7dca52010-11-14 12:23:09 +0800516 /* no options, so back up to avoid sending an empty request list */
517 if (*cnt == 0)
518 e -= 2;
519
wdenk29e7f5a2004-03-12 00:14:09 +0000520 *e++ = 255; /* End of the list */
wdenk3861aa52002-09-27 23:19:37 +0000521
wdenk29e7f5a2004-03-12 00:14:09 +0000522 /* Pad to minimal length */
wdenk3861aa52002-09-27 23:19:37 +0000523#ifdef CONFIG_DHCP_MIN_EXT_LEN
Simon Glassa0978eb2011-02-02 15:03:28 -0800524 while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
wdenk29e7f5a2004-03-12 00:14:09 +0000525 *e++ = 0;
wdenk3861aa52002-09-27 23:19:37 +0000526#endif
527
wdenk29e7f5a2004-03-12 00:14:09 +0000528 return e - start;
wdenk3861aa52002-09-27 23:19:37 +0000529}
530
Jon Loeligera9807e52007-07-10 11:05:02 -0500531#else
wdenk3861aa52002-09-27 23:19:37 +0000532/*
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000533 * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
wdenk3861aa52002-09-27 23:19:37 +0000534 */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000535static int BootpExtended(u8 *e)
wdenk3861aa52002-09-27 23:19:37 +0000536{
wdenk29e7f5a2004-03-12 00:14:09 +0000537 u8 *start = e;
wdenk3861aa52002-09-27 23:19:37 +0000538
wdenk29e7f5a2004-03-12 00:14:09 +0000539 *e++ = 99; /* RFC1048 Magic Cookie */
540 *e++ = 130;
541 *e++ = 83;
542 *e++ = 99;
wdenk3861aa52002-09-27 23:19:37 +0000543
Jon Loeliger54f35c22007-07-09 17:45:14 -0500544#if defined(CONFIG_CMD_DHCP)
wdenk29e7f5a2004-03-12 00:14:09 +0000545 *e++ = 53; /* DHCP Message Type */
546 *e++ = 1;
547 *e++ = DHCP_DISCOVER;
wdenk3861aa52002-09-27 23:19:37 +0000548
wdenk29e7f5a2004-03-12 00:14:09 +0000549 *e++ = 57; /* Maximum DHCP Message Size */
550 *e++ = 2;
Joe Hershbergerceba4472012-05-23 07:58:14 +0000551 *e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16;
552 *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
Jon Loeligera9807e52007-07-10 11:05:02 -0500553#endif
wdenk3861aa52002-09-27 23:19:37 +0000554
Ilya Yanokf7a2c552012-09-18 00:22:50 +0000555#if defined(CONFIG_BOOTP_VCI_STRING) || \
556 (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING))
557#ifdef CONFIG_SPL_BUILD
558 put_vci(e, CONFIG_SPL_NET_VCI_STRING);
559#else
Ilya Yanok30876582012-09-17 10:26:25 +0000560 put_vci(e, CONFIG_BOOTP_VCI_STRING);
561#endif
Ilya Yanokf7a2c552012-09-18 00:22:50 +0000562#endif
Ilya Yanok30876582012-09-17 10:26:25 +0000563
Jon Loeliger5336a762007-07-09 22:08:34 -0500564#if defined(CONFIG_BOOTP_SUBNETMASK)
wdenk29e7f5a2004-03-12 00:14:09 +0000565 *e++ = 1; /* Subnet mask request */
566 *e++ = 4;
567 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000568#endif
569
Jon Loeliger5336a762007-07-09 22:08:34 -0500570#if defined(CONFIG_BOOTP_GATEWAY)
wdenk29e7f5a2004-03-12 00:14:09 +0000571 *e++ = 3; /* Default gateway request */
572 *e++ = 4;
573 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000574#endif
575
Jon Loeliger5336a762007-07-09 22:08:34 -0500576#if defined(CONFIG_BOOTP_DNS)
wdenk29e7f5a2004-03-12 00:14:09 +0000577 *e++ = 6; /* Domain Name Server */
578 *e++ = 4;
579 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000580#endif
581
Jon Loeliger5336a762007-07-09 22:08:34 -0500582#if defined(CONFIG_BOOTP_HOSTNAME)
wdenk29e7f5a2004-03-12 00:14:09 +0000583 *e++ = 12; /* Host name request */
584 *e++ = 32;
585 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000586#endif
587
Jon Loeliger5336a762007-07-09 22:08:34 -0500588#if defined(CONFIG_BOOTP_BOOTFILESIZE)
wdenk29e7f5a2004-03-12 00:14:09 +0000589 *e++ = 13; /* Boot file size */
590 *e++ = 2;
591 e += 2;
wdenk3861aa52002-09-27 23:19:37 +0000592#endif
593
Jon Loeliger5336a762007-07-09 22:08:34 -0500594#if defined(CONFIG_BOOTP_BOOTPATH)
wdenk29e7f5a2004-03-12 00:14:09 +0000595 *e++ = 17; /* Boot path */
596 *e++ = 32;
597 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000598#endif
599
Jon Loeliger5336a762007-07-09 22:08:34 -0500600#if defined(CONFIG_BOOTP_NISDOMAIN)
wdenk29e7f5a2004-03-12 00:14:09 +0000601 *e++ = 40; /* NIS Domain name request */
602 *e++ = 32;
603 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000604#endif
Luuk Paulussen6380e012011-05-16 18:29:19 +0000605#if defined(CONFIG_BOOTP_NTPSERVER)
606 *e++ = 42;
607 *e++ = 4;
608 e += 4;
609#endif
wdenk3861aa52002-09-27 23:19:37 +0000610
wdenk29e7f5a2004-03-12 00:14:09 +0000611 *e++ = 255; /* End of the list */
wdenk3861aa52002-09-27 23:19:37 +0000612
wdenk29e7f5a2004-03-12 00:14:09 +0000613 return e - start;
wdenk3861aa52002-09-27 23:19:37 +0000614}
Jon Loeligera9807e52007-07-10 11:05:02 -0500615#endif
wdenk3861aa52002-09-27 23:19:37 +0000616
Stephen Warren69e1e352014-07-25 17:30:48 -0600617void BootpReset(void)
618{
619 BootpTry = 0;
620 bootp_start = get_timer(0);
621 bootp_timeout = 10;
622}
623
wdenk3861aa52002-09-27 23:19:37 +0000624void
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000625BootpRequest(void)
wdenk3861aa52002-09-27 23:19:37 +0000626{
Joe Hershberger4b7747e2012-05-15 08:59:04 +0000627 uchar *pkt, *iphdr;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000628 struct Bootp_t *bp;
Joe Hershbergerdb3e6e42012-05-23 07:59:10 +0000629 int extlen, pktlen, iplen;
630 int eth_hdr_size;
Joe Hershberger797f2c52012-05-23 07:57:58 +0000631#ifdef CONFIG_BOOTP_RANDOM_DELAY
Pavel Machek764c29d2014-07-11 11:39:37 +0200632 ulong rand_ms;
Joe Hershberger797f2c52012-05-23 07:57:58 +0000633#endif
wdenk3861aa52002-09-27 23:19:37 +0000634
Simon Glass768cbf02011-12-10 11:08:06 +0000635 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
Jon Loeliger54f35c22007-07-09 17:45:14 -0500636#if defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000637 dhcp_state = INIT;
638#endif
639
640#ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */
Joe Hershberger797f2c52012-05-23 07:57:58 +0000641 if (BootpTry == 0)
642 srand_mac();
wdenk3861aa52002-09-27 23:19:37 +0000643
Joe Hershberger797f2c52012-05-23 07:57:58 +0000644 if (BootpTry <= 2) /* Start with max 1024 * 1ms */
645 rand_ms = rand() >> (22 - BootpTry);
646 else /* After 3rd BOOTP request max 8192 * 1ms */
647 rand_ms = rand() >> 19;
wdenk3861aa52002-09-27 23:19:37 +0000648
Joe Hershberger797f2c52012-05-23 07:57:58 +0000649 printf("Random delay: %ld ms...\n", rand_ms);
Pavel Machek764c29d2014-07-11 11:39:37 +0200650 mdelay(rand_ms);
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000651
wdenk3861aa52002-09-27 23:19:37 +0000652#endif /* CONFIG_BOOTP_RANDOM_DELAY */
653
654 printf("BOOTP broadcast %d\n", ++BootpTry);
655 pkt = NetTxPacket;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000656 memset((void *)pkt, 0, PKTSIZE);
wdenk3861aa52002-09-27 23:19:37 +0000657
Joe Hershbergerdb3e6e42012-05-23 07:59:10 +0000658 eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP);
659 pkt += eth_hdr_size;
wdenk3861aa52002-09-27 23:19:37 +0000660
661 /*
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000662 * Next line results in incorrect packet size being transmitted,
663 * resulting in errors in some DHCP servers, reporting missing bytes.
664 * Size must be set in packet header after extension length has been
665 * determined.
wdenk3861aa52002-09-27 23:19:37 +0000666 * C. Hallinan, DS4.COM, Inc.
667 */
Joe Hershberger2ed5b492012-05-23 07:59:07 +0000668 /* net_set_udp_header(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC,
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000669 sizeof (struct Bootp_t)); */
Joe Hershberger2ed5b492012-05-23 07:59:07 +0000670 iphdr = pkt; /* We need this later for net_set_udp_header() */
Joe Hershberger6fe8b452012-05-23 07:58:04 +0000671 pkt += IP_UDP_HDR_SIZE;
wdenk3861aa52002-09-27 23:19:37 +0000672
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000673 bp = (struct Bootp_t *)pkt;
wdenk3861aa52002-09-27 23:19:37 +0000674 bp->bp_op = OP_BOOTREQUEST;
675 bp->bp_htype = HWT_ETHER;
676 bp->bp_hlen = HWL_ETHER;
677 bp->bp_hops = 0;
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200678 bp->bp_secs = htons(get_timer(0) / 1000);
wdenk3861aa52002-09-27 23:19:37 +0000679 NetWriteIP(&bp->bp_ciaddr, 0);
680 NetWriteIP(&bp->bp_yiaddr, 0);
681 NetWriteIP(&bp->bp_siaddr, 0);
682 NetWriteIP(&bp->bp_giaddr, 0);
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000683 memcpy(bp->bp_chaddr, NetOurEther, 6);
684 copy_filename(bp->bp_file, BootFile, sizeof(bp->bp_file));
wdenk3861aa52002-09-27 23:19:37 +0000685
686 /* Request additional information from the BOOTP/DHCP server */
Jon Loeliger54f35c22007-07-09 17:45:14 -0500687#if defined(CONFIG_CMD_DHCP)
Joe Hershbergerdb3e6e42012-05-23 07:59:10 +0000688 extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
wdenk3861aa52002-09-27 23:19:37 +0000689#else
Joe Hershbergerdb3e6e42012-05-23 07:59:10 +0000690 extlen = BootpExtended((u8 *)bp->bp_vend);
Jon Loeligera9807e52007-07-10 11:05:02 -0500691#endif
wdenk3861aa52002-09-27 23:19:37 +0000692
693 /*
694 * Bootp ID is the lower 4 bytes of our ethernet address
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200695 * plus the current time in ms.
wdenk3861aa52002-09-27 23:19:37 +0000696 */
697 BootpID = ((ulong)NetOurEther[2] << 24)
698 | ((ulong)NetOurEther[3] << 16)
699 | ((ulong)NetOurEther[4] << 8)
700 | (ulong)NetOurEther[5];
701 BootpID += get_timer(0);
wdenk29e7f5a2004-03-12 00:14:09 +0000702 BootpID = htonl(BootpID);
wdenk3861aa52002-09-27 23:19:37 +0000703 NetCopyLong(&bp->bp_id, &BootpID);
704
705 /*
706 * Calculate proper packet lengths taking into account the
707 * variable size of the options field
708 */
Joe Hershbergerdb3e6e42012-05-23 07:59:10 +0000709 iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
710 pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
Joe Hershberger2ed5b492012-05-23 07:59:07 +0000711 net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
Stephen Warren69e1e352014-07-25 17:30:48 -0600712 NetSetTimeout(bootp_timeout, BootpTimeout);
wdenk3861aa52002-09-27 23:19:37 +0000713
Jon Loeliger54f35c22007-07-09 17:45:14 -0500714#if defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000715 dhcp_state = SELECTING;
Joe Hershbergerf50357b2012-05-23 07:59:15 +0000716 net_set_udp_handler(DhcpHandler);
wdenk3861aa52002-09-27 23:19:37 +0000717#else
Joe Hershbergerf50357b2012-05-23 07:59:15 +0000718 net_set_udp_handler(BootpHandler);
Jon Loeligera9807e52007-07-10 11:05:02 -0500719#endif
wdenk3861aa52002-09-27 23:19:37 +0000720 NetSendPacket(NetTxPacket, pktlen);
721}
722
Jon Loeliger54f35c22007-07-09 17:45:14 -0500723#if defined(CONFIG_CMD_DHCP)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000724static void DhcpOptionsProcess(uchar *popt, struct Bootp_t *bp)
wdenk3861aa52002-09-27 23:19:37 +0000725{
wdenkb02744a2003-04-05 00:53:31 +0000726 uchar *end = popt + BOOTP_HDR_SIZE;
wdenk3861aa52002-09-27 23:19:37 +0000727 int oplen, size;
Wolfgang Denk2b184222009-09-11 09:05:32 +0200728#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
729 int *to_ptr;
730#endif
wdenk3861aa52002-09-27 23:19:37 +0000731
wdenk29e7f5a2004-03-12 00:14:09 +0000732 while (popt < end && *popt != 0xff) {
wdenk3861aa52002-09-27 23:19:37 +0000733 oplen = *(popt + 1);
wdenk29e7f5a2004-03-12 00:14:09 +0000734 switch (*popt) {
735 case 1:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000736 NetCopyIP(&NetOurSubnetMask, (popt + 2));
wdenk29e7f5a2004-03-12 00:14:09 +0000737 break;
Jon Loeliger5336a762007-07-09 22:08:34 -0500738#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
wdenkb4ad9622005-04-01 00:25:43 +0000739 case 2: /* Time offset */
Wolfgang Denk2b184222009-09-11 09:05:32 +0200740 to_ptr = &NetTimeOffset;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000741 NetCopyLong((ulong *)to_ptr, (ulong *)(popt + 2));
742 NetTimeOffset = ntohl(NetTimeOffset);
wdenkb4ad9622005-04-01 00:25:43 +0000743 break;
744#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000745 case 3:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000746 NetCopyIP(&NetOurGatewayIP, (popt + 2));
wdenk29e7f5a2004-03-12 00:14:09 +0000747 break;
748 case 6:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000749 NetCopyIP(&NetOurDNSIP, (popt + 2));
Jon Loeliger5336a762007-07-09 22:08:34 -0500750#if defined(CONFIG_BOOTP_DNS2)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000751 if (*(popt + 1) > 4)
752 NetCopyIP(&NetOurDNS2IP, (popt + 2 + 4));
stroesee0aadfb2003-08-28 14:17:32 +0000753#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000754 break;
755 case 12:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000756 size = truncate_sz("Host Name",
757 sizeof(NetOurHostName), oplen);
758 memcpy(&NetOurHostName, popt + 2, size);
wdenk29e7f5a2004-03-12 00:14:09 +0000759 NetOurHostName[size] = 0;
760 break;
761 case 15: /* Ignore Domain Name Option */
762 break;
763 case 17:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000764 size = truncate_sz("Root Path",
765 sizeof(NetOurRootPath), oplen);
766 memcpy(&NetOurRootPath, popt + 2, size);
wdenk29e7f5a2004-03-12 00:14:09 +0000767 NetOurRootPath[size] = 0;
768 break;
Brian Rzycki5a672a22012-09-11 09:22:53 +0000769 case 28: /* Ignore Broadcast Address Option */
770 break;
Jon Loeliger5336a762007-07-09 22:08:34 -0500771#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
wdenkb4ad9622005-04-01 00:25:43 +0000772 case 42: /* NTP server IP */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000773 NetCopyIP(&NetNtpServerIP, (popt + 2));
wdenkb4ad9622005-04-01 00:25:43 +0000774 break;
775#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000776 case 51:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000777 NetCopyLong(&dhcp_leasetime, (ulong *) (popt + 2));
wdenk29e7f5a2004-03-12 00:14:09 +0000778 break;
779 case 53: /* Ignore Message Type Option */
780 break;
781 case 54:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000782 NetCopyIP(&NetDHCPServerIP, (popt + 2));
wdenk29e7f5a2004-03-12 00:14:09 +0000783 break;
784 case 58: /* Ignore Renewal Time Option */
785 break;
786 case 59: /* Ignore Rebinding Time Option */
787 break;
Wolfgang Denk012429c2006-03-12 18:26:46 +0100788 case 66: /* Ignore TFTP server name */
789 break;
790 case 67: /* vendor opt bootfile */
791 /*
792 * I can't use dhcp_vendorex_proc here because I need
793 * to write into the bootp packet - even then I had to
794 * pass the bootp packet pointer into here as the
795 * second arg
796 */
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000797 size = truncate_sz("Opt Boot File",
Wolfgang Denk012429c2006-03-12 18:26:46 +0100798 sizeof(bp->bp_file),
799 oplen);
800 if (bp->bp_file[0] == '\0' && size > 0) {
801 /*
802 * only use vendor boot file if we didn't
803 * receive a boot file in the main non-vendor
804 * part of the packet - god only knows why
805 * some vendors chose not to use this perfectly
806 * good spot to store the boot file (join on
807 * Tru64 Unix) it seems mind bogglingly crazy
808 * to me
809 */
810 printf("*** WARNING: using vendor "
811 "optional boot file\n");
812 memcpy(bp->bp_file, popt + 2, size);
813 bp->bp_file[size] = '\0';
814 }
815 break;
wdenk29e7f5a2004-03-12 00:14:09 +0000816 default:
Jon Loeliger5336a762007-07-09 22:08:34 -0500817#if defined(CONFIG_BOOTP_VENDOREX)
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000818 if (dhcp_vendorex_proc(popt))
wdenk57b2d802003-06-27 21:31:46 +0000819 break;
wdenk3861aa52002-09-27 23:19:37 +0000820#endif
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000821 printf("*** Unhandled DHCP Option in OFFER/ACK:"
822 " %d\n", *popt);
wdenk29e7f5a2004-03-12 00:14:09 +0000823 break;
wdenk3861aa52002-09-27 23:19:37 +0000824 }
825 popt += oplen + 2; /* Process next option */
826 }
827}
828
829static int DhcpMessageType(unsigned char *popt)
830{
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000831 if (NetReadLong((ulong *)popt) != htonl(BOOTP_VENDOR_MAGIC))
wdenk3861aa52002-09-27 23:19:37 +0000832 return -1;
833
834 popt += 4;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000835 while (*popt != 0xff) {
836 if (*popt == 53) /* DHCP Message Type */
wdenk3861aa52002-09-27 23:19:37 +0000837 return *(popt + 2);
838 popt += *(popt + 1) + 2; /* Scan through all options */
839 }
840 return -1;
841}
842
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000843static void DhcpSendRequestPkt(struct Bootp_t *bp_offer)
wdenk3861aa52002-09-27 23:19:37 +0000844{
Joe Hershberger4b7747e2012-05-15 08:59:04 +0000845 uchar *pkt, *iphdr;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000846 struct Bootp_t *bp;
wdenk3861aa52002-09-27 23:19:37 +0000847 int pktlen, iplen, extlen;
Joe Hershbergerdb3e6e42012-05-23 07:59:10 +0000848 int eth_hdr_size;
wdenkcc1e2562003-03-06 13:39:27 +0000849 IPaddr_t OfferedIP;
wdenk3861aa52002-09-27 23:19:37 +0000850
Robin Getz9e0a4d62009-07-23 03:01:03 -0400851 debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
wdenk3861aa52002-09-27 23:19:37 +0000852 pkt = NetTxPacket;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000853 memset((void *)pkt, 0, PKTSIZE);
wdenk3861aa52002-09-27 23:19:37 +0000854
Joe Hershbergerdb3e6e42012-05-23 07:59:10 +0000855 eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP);
856 pkt += eth_hdr_size;
wdenk3861aa52002-09-27 23:19:37 +0000857
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000858 iphdr = pkt; /* We'll need this later to set proper pkt size */
Joe Hershberger6fe8b452012-05-23 07:58:04 +0000859 pkt += IP_UDP_HDR_SIZE;
wdenk3861aa52002-09-27 23:19:37 +0000860
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000861 bp = (struct Bootp_t *)pkt;
wdenk3861aa52002-09-27 23:19:37 +0000862 bp->bp_op = OP_BOOTREQUEST;
863 bp->bp_htype = HWT_ETHER;
864 bp->bp_hlen = HWL_ETHER;
865 bp->bp_hops = 0;
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200866 bp->bp_secs = htons(get_timer(0) / 1000);
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000867 /* Do not set the client IP, your IP, or server IP yet, since it
868 * hasn't been ACK'ed by the server yet */
Justin Flammia01f256b2007-10-29 17:40:35 -0400869
Wolfgang Denk8a933fb2006-10-12 00:01:08 +0200870 /*
Wolfgang Denk68e83a82006-10-09 01:26:14 +0200871 * RFC3046 requires Relay Agents to discard packets with
872 * nonzero and offered giaddr
873 */
874 NetWriteIP(&bp->bp_giaddr, 0);
875
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000876 memcpy(bp->bp_chaddr, NetOurEther, 6);
wdenk3861aa52002-09-27 23:19:37 +0000877
878 /*
879 * ID is the id of the OFFER packet
880 */
881
882 NetCopyLong(&bp->bp_id, &bp_offer->bp_id);
883
884 /*
885 * Copy options from OFFER packet if present
886 */
Justin Flammia01f256b2007-10-29 17:40:35 -0400887
888 /* Copy offered IP into the parameters request list */
889 NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr);
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000890 extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST,
891 NetDHCPServerIP, OfferedIP);
wdenk3861aa52002-09-27 23:19:37 +0000892
Joe Hershbergerdb3e6e42012-05-23 07:59:10 +0000893 iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
894 pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
Joe Hershberger2ed5b492012-05-23 07:59:07 +0000895 net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
wdenk3861aa52002-09-27 23:19:37 +0000896
Aras Vaichas72aa3f32008-03-26 09:43:57 +1100897#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
898 udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
899#endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
Joe Hershbergerb1e94762012-05-23 07:59:11 +0000900 debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
wdenk3861aa52002-09-27 23:19:37 +0000901 NetSendPacket(NetTxPacket, pktlen);
902}
903
904/*
905 * Handle DHCP received packets.
906 */
907static void
Luca Ceresoli428ab362011-04-18 06:19:50 +0000908DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
909 unsigned len)
wdenk3861aa52002-09-27 23:19:37 +0000910{
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000911 struct Bootp_t *bp = (struct Bootp_t *)pkt;
wdenk3861aa52002-09-27 23:19:37 +0000912
Robin Getz9e0a4d62009-07-23 03:01:03 -0400913 debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
wdenk3861aa52002-09-27 23:19:37 +0000914 src, dest, len, dhcp_state);
915
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000916 /* Filter out pkts we don't want */
917 if (BootpCheckPkt(pkt, dest, src, len))
wdenk3861aa52002-09-27 23:19:37 +0000918 return;
919
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000920 debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state:"
921 " %d\n", src, dest, len, dhcp_state);
wdenk3861aa52002-09-27 23:19:37 +0000922
923 switch (dhcp_state) {
924 case SELECTING:
925 /*
926 * Wait an appropriate time for any potential DHCPOFFER packets
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000927 * to arrive. Then select one, and generate DHCPREQUEST
928 * response. If filename is in format we recognize, assume it
929 * is a valid OFFER from a server we want.
wdenk3861aa52002-09-27 23:19:37 +0000930 */
Robin Getz9e0a4d62009-07-23 03:01:03 -0400931 debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200932#ifdef CONFIG_SYS_BOOTFILE_PREFIX
wdenk3861aa52002-09-27 23:19:37 +0000933 if (strncmp(bp->bp_file,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200934 CONFIG_SYS_BOOTFILE_PREFIX,
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000935 strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200936#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
wdenk3861aa52002-09-27 23:19:37 +0000937
Robin Getz9e0a4d62009-07-23 03:01:03 -0400938 debug("TRANSITIONING TO REQUESTING STATE\n");
wdenk3861aa52002-09-27 23:19:37 +0000939 dhcp_state = REQUESTING;
stroese5fa6e902003-04-10 13:26:44 +0000940
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000941 if (NetReadLong((ulong *)&bp->bp_vend[0]) ==
942 htonl(BOOTP_VENDOR_MAGIC))
Wolfgang Denk012429c2006-03-12 18:26:46 +0100943 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
wdenk3861aa52002-09-27 23:19:37 +0000944
Stephen Warren69e1e352014-07-25 17:30:48 -0600945 NetSetTimeout(5000, BootpTimeout);
wdenk3861aa52002-09-27 23:19:37 +0000946 DhcpSendRequestPkt(bp);
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200947#ifdef CONFIG_SYS_BOOTFILE_PREFIX
wdenk3861aa52002-09-27 23:19:37 +0000948 }
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200949#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
wdenk3861aa52002-09-27 23:19:37 +0000950
951 return;
952 break;
953 case REQUESTING:
Robin Getz9e0a4d62009-07-23 03:01:03 -0400954 debug("DHCP State: REQUESTING\n");
wdenk3861aa52002-09-27 23:19:37 +0000955
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000956 if (DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK) {
957 if (NetReadLong((ulong *)&bp->bp_vend[0]) ==
958 htonl(BOOTP_VENDOR_MAGIC))
Wolfgang Denk012429c2006-03-12 18:26:46 +0100959 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000960 /* Store net params from reply */
961 BootpCopyNetParams(bp);
wdenk3861aa52002-09-27 23:19:37 +0000962 dhcp_state = BOUND;
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000963 printf("DHCP client bound to address %pI4\n",
964 &NetOurIP);
Simon Glass768cbf02011-12-10 11:08:06 +0000965 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000966 "bootp_stop");
wdenk3861aa52002-09-27 23:19:37 +0000967
Simon Glass5234ad12011-10-27 06:24:32 +0000968 net_auto_load();
wdenk3861aa52002-09-27 23:19:37 +0000969 return;
970 }
971 break;
Remy Bohmer03a44492008-08-20 11:30:28 +0200972 case BOUND:
973 /* DHCP client bound to address */
974 break;
wdenk3861aa52002-09-27 23:19:37 +0000975 default:
Joe Hershberger8f4b1352012-05-15 08:59:06 +0000976 puts("DHCP: INVALID STATE\n");
wdenk3861aa52002-09-27 23:19:37 +0000977 break;
978 }
979
980}
981
982void DhcpRequest(void)
983{
984 BootpRequest();
985}
Wolfgang Denkf7a7f082007-11-03 23:09:27 +0100986#endif /* CONFIG_CMD_DHCP */