blob: 34124b8fc2425d6fe70e3b5cd42ec159119670df [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
Anatolij Gustschine4e53d12011-11-19 10:29:58 +000020#include <linux/compiler.h>
wdenk3861aa52002-09-27 23:19:37 +000021
wdenk29e7f5a2004-03-12 00:14:09 +000022#define BOOTP_VENDOR_MAGIC 0x63825363 /* RFC1048 Magic Cookie */
wdenk3861aa52002-09-27 23:19:37 +000023
Bartlomiej Sieka56668462008-10-01 15:26:28 +020024#define TIMEOUT 5000UL /* Milliseconds before trying BOOTP again */
wdenk29e7f5a2004-03-12 00:14:09 +000025#ifndef CONFIG_NET_RETRY_COUNT
wdenk3861aa52002-09-27 23:19:37 +000026# define TIMEOUT_COUNT 5 /* # of timeouts before giving up */
27#else
wdenk29e7f5a2004-03-12 00:14:09 +000028# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
wdenk3861aa52002-09-27 23:19:37 +000029#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 */
wdenk29e7f5a2004-03-12 00:14:09 +000035#define CONFIG_DHCP_MIN_EXT_LEN 64
wdenk3861aa52002-09-27 23:19:37 +000036#endif
37
38ulong BootpID;
39int BootpTry;
40#ifdef CONFIG_BOOTP_RANDOM_DELAY
41ulong seed1, seed2;
42#endif
43
Jon Loeliger54f35c22007-07-09 17:45:14 -050044#if defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +000045dhcp_state_t dhcp_state = INIT;
wdenk4e112c12003-06-03 23:54:09 +000046unsigned long dhcp_leasetime = 0;
stroese5fa6e902003-04-10 13:26:44 +000047IPaddr_t NetDHCPServerIP = 0;
Luca Ceresoli428ab362011-04-18 06:19:50 +000048static void DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
49 unsigned len);
wdenk3861aa52002-09-27 23:19:37 +000050
51/* For Debug */
wdenkb02744a2003-04-05 00:53:31 +000052#if 0
53static char *dhcpmsg2str(int type)
wdenk3861aa52002-09-27 23:19:37 +000054{
55 switch (type) {
wdenk29e7f5a2004-03-12 00:14:09 +000056 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;
wdenk3861aa52002-09-27 23:19:37 +000063 default: return "UNKNOWN/INVALID MSG TYPE"; break;
64 }
65}
wdenkb02744a2003-04-05 00:53:31 +000066#endif
wdenk3861aa52002-09-27 23:19:37 +000067
Jon Loeliger5336a762007-07-09 22:08:34 -050068#if defined(CONFIG_BOOTP_VENDOREX)
wdenk3861aa52002-09-27 23:19:37 +000069extern 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
Jon Loeligera9807e52007-07-10 11:05:02 -050073#endif
wdenk3861aa52002-09-27 23:19:37 +000074
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
Robin Getz9e0a4d62009-07-23 03:01:03 -040099 debug("Filtering pkt = %d\n", retval);
wdenk3861aa52002-09-27 23:19:37 +0000100
101 return retval;
102}
103
104/*
105 * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
106 */
wdenkb02744a2003-04-05 00:53:31 +0000107static void BootpCopyNetParams(Bootp_t *bp)
wdenk3861aa52002-09-27 23:19:37 +0000108{
Anatolij Gustschine4e53d12011-11-19 10:29:58 +0000109 __maybe_unused IPaddr_t tmp_ip;
wdenk4989f872004-03-14 15:06:13 +0000110
wdenk3861aa52002-09-27 23:19:37 +0000111 NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
Wilson Callan22bcd6e2007-07-28 10:56:13 -0400112#if !defined(CONFIG_BOOTP_SERVERIP)
wdenk4989f872004-03-14 15:06:13 +0000113 NetCopyIP(&tmp_ip, &bp->bp_siaddr);
114 if (tmp_ip != 0)
115 NetCopyIP(&NetServerIP, &bp->bp_siaddr);
Mike Frysingerdc166032009-07-18 21:04:08 -0400116 memcpy (NetServerEther, ((Ethernet_t *)NetRxPacket)->et_src, 6);
Wilson Callan22bcd6e2007-07-28 10:56:13 -0400117#endif
wdenk4989f872004-03-14 15:06:13 +0000118 if (strlen(bp->bp_file) > 0)
119 copy_filename (BootFile, bp->bp_file, sizeof(BootFile));
wdenk3861aa52002-09-27 23:19:37 +0000120
Robin Getz9e0a4d62009-07-23 03:01:03 -0400121 debug("Bootfile: %s\n", BootFile);
wdenk3861aa52002-09-27 23:19:37 +0000122
123 /* Propagate to environment:
wdenk57b2d802003-06-27 21:31:46 +0000124 * don't delete exising entry when BOOTP / DHCP reply does
wdenk3861aa52002-09-27 23:19:37 +0000125 * 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
Jon Loeliger54f35c22007-07-09 17:45:14 -0500142#if !defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000143
wdenk29e7f5a2004-03-12 00:14:09 +0000144static void BootpVendorFieldProcess (u8 * ext)
wdenk3861aa52002-09-27 23:19:37 +0000145{
wdenk29e7f5a2004-03-12 00:14:09 +0000146 int size = *(ext + 1);
wdenk3861aa52002-09-27 23:19:37 +0000147
Robin Getz9e0a4d62009-07-23 03:01:03 -0400148 debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
wdenk29e7f5a2004-03-12 00:14:09 +0000149 *(ext + 1));
wdenk3861aa52002-09-27 23:19:37 +0000150
wdenk29e7f5a2004-03-12 00:14:09 +0000151 NetBootFileSize = 0;
wdenk3861aa52002-09-27 23:19:37 +0000152
wdenk29e7f5a2004-03-12 00:14:09 +0000153 switch (*ext) {
154 /* Fixed length fields */
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700155 case 1: /* Subnet mask */
wdenk3861aa52002-09-27 23:19:37 +0000156 if (NetOurSubnetMask == 0)
wdenk29e7f5a2004-03-12 00:14:09 +0000157 NetCopyIP (&NetOurSubnetMask, (IPaddr_t *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000158 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700159 case 2: /* Time offset - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000160 break;
wdenk29e7f5a2004-03-12 00:14:09 +0000161 /* Variable length fields */
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700162 case 3: /* Gateways list */
wdenk3861aa52002-09-27 23:19:37 +0000163 if (NetOurGatewayIP == 0) {
wdenk29e7f5a2004-03-12 00:14:09 +0000164 NetCopyIP (&NetOurGatewayIP, (IPaddr_t *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000165 }
166 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700167 case 4: /* Time server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000168 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700169 case 5: /* IEN-116 name server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000170 break;
171 case 6:
172 if (NetOurDNSIP == 0) {
wdenk29e7f5a2004-03-12 00:14:09 +0000173 NetCopyIP (&NetOurDNSIP, (IPaddr_t *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000174 }
Jon Loeliger5336a762007-07-09 22:08:34 -0500175#if defined(CONFIG_BOOTP_DNS2)
stroesee0aadfb2003-08-28 14:17:32 +0000176 if ((NetOurDNS2IP == 0) && (size > 4)) {
wdenk29e7f5a2004-03-12 00:14:09 +0000177 NetCopyIP (&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4));
stroesee0aadfb2003-08-28 14:17:32 +0000178 }
179#endif
wdenk3861aa52002-09-27 23:19:37 +0000180 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700181 case 7: /* Log server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000182 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700183 case 8: /* Cookie/Quote server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000184 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700185 case 9: /* LPR server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000186 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700187 case 10: /* Impress server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000188 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700189 case 11: /* RPL server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000190 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700191 case 12: /* Host name */
wdenk3861aa52002-09-27 23:19:37 +0000192 if (NetOurHostName[0] == 0) {
wdenk29e7f5a2004-03-12 00:14:09 +0000193 size = truncate_sz ("Host Name", sizeof (NetOurHostName), size);
194 memcpy (&NetOurHostName, ext + 2, size);
195 NetOurHostName[size] = 0;
wdenk3861aa52002-09-27 23:19:37 +0000196 }
197 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700198 case 13: /* Boot file size */
wdenk3861aa52002-09-27 23:19:37 +0000199 if (size == 2)
wdenk29e7f5a2004-03-12 00:14:09 +0000200 NetBootFileSize = ntohs (*(ushort *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000201 else if (size == 4)
wdenk29e7f5a2004-03-12 00:14:09 +0000202 NetBootFileSize = ntohl (*(ulong *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000203 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700204 case 14: /* Merit dump file - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000205 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700206 case 15: /* Domain name - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000207 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700208 case 16: /* Swap server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000209 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700210 case 17: /* Root path */
wdenk3861aa52002-09-27 23:19:37 +0000211 if (NetOurRootPath[0] == 0) {
wdenk29e7f5a2004-03-12 00:14:09 +0000212 size = truncate_sz ("Root Path", sizeof (NetOurRootPath), size);
213 memcpy (&NetOurRootPath, ext + 2, size);
214 NetOurRootPath[size] = 0;
wdenk3861aa52002-09-27 23:19:37 +0000215 }
216 break;
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700217 case 18: /* Extension path - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000218 /*
wdenk57b2d802003-06-27 21:31:46 +0000219 * This can be used to send the information of the
220 * vendor area in another file that the client can
221 * access via TFTP.
wdenk3861aa52002-09-27 23:19:37 +0000222 */
223 break;
wdenk29e7f5a2004-03-12 00:14:09 +0000224 /* IP host layer fields */
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700225 case 40: /* NIS Domain name */
wdenk3861aa52002-09-27 23:19:37 +0000226 if (NetOurNISDomain[0] == 0) {
wdenk29e7f5a2004-03-12 00:14:09 +0000227 size = truncate_sz ("NIS Domain Name", sizeof (NetOurNISDomain), size);
228 memcpy (&NetOurNISDomain, ext + 2, size);
229 NetOurNISDomain[size] = 0;
wdenk3861aa52002-09-27 23:19:37 +0000230 }
231 break;
Luuk Paulussen6380e012011-05-16 18:29:19 +0000232#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
wdenk29e7f5a2004-03-12 00:14:09 +0000237 /* Application layer fields */
Wolfgang Denk35f734f2008-04-13 09:59:26 -0700238 case 43: /* Vendor specific info - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000239 /*
wdenk57b2d802003-06-27 21:31:46 +0000240 * Binary information to exchange specific
241 * product information.
wdenk3861aa52002-09-27 23:19:37 +0000242 */
243 break;
wdenk29e7f5a2004-03-12 00:14:09 +0000244 /* Reserved (custom) fields (128..254) */
245 }
wdenk3861aa52002-09-27 23:19:37 +0000246}
247
wdenk29e7f5a2004-03-12 00:14:09 +0000248static void BootpVendorProcess (u8 * ext, int size)
wdenk3861aa52002-09-27 23:19:37 +0000249{
wdenk29e7f5a2004-03-12 00:14:09 +0000250 u8 *end = ext + size;
wdenk3861aa52002-09-27 23:19:37 +0000251
Robin Getz9e0a4d62009-07-23 03:01:03 -0400252 debug("[BOOTP] Checking extension (%d bytes)...\n", size);
wdenk3861aa52002-09-27 23:19:37 +0000253
wdenk29e7f5a2004-03-12 00:14:09 +0000254 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 }
wdenk3861aa52002-09-27 23:19:37 +0000264 }
wdenk3861aa52002-09-27 23:19:37 +0000265
Robin Getz9e0a4d62009-07-23 03:01:03 -0400266 debug("[BOOTP] Received fields: \n");
Mike Frysingerd5695f42009-02-17 00:00:53 -0500267 if (NetOurSubnetMask)
Robin Getz9e0a4d62009-07-23 03:01:03 -0400268 debug("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask);
wdenk3861aa52002-09-27 23:19:37 +0000269
Mike Frysingerd5695f42009-02-17 00:00:53 -0500270 if (NetOurGatewayIP)
Robin Getz9e0a4d62009-07-23 03:01:03 -0400271 debug("NetOurGatewayIP : %pI4", &NetOurGatewayIP);
wdenk3861aa52002-09-27 23:19:37 +0000272
Robin Getz9e0a4d62009-07-23 03:01:03 -0400273 if (NetBootFileSize)
274 debug("NetBootFileSize : %d\n", NetBootFileSize);
wdenk3861aa52002-09-27 23:19:37 +0000275
Robin Getz9e0a4d62009-07-23 03:01:03 -0400276 if (NetOurHostName[0])
277 debug("NetOurHostName : %s\n", NetOurHostName);
wdenk3861aa52002-09-27 23:19:37 +0000278
Robin Getz9e0a4d62009-07-23 03:01:03 -0400279 if (NetOurRootPath[0])
280 debug("NetOurRootPath : %s\n", NetOurRootPath);
wdenk3861aa52002-09-27 23:19:37 +0000281
Robin Getz9e0a4d62009-07-23 03:01:03 -0400282 if (NetOurNISDomain[0])
283 debug("NetOurNISDomain : %s\n", NetOurNISDomain);
wdenk3861aa52002-09-27 23:19:37 +0000284
Robin Getz9e0a4d62009-07-23 03:01:03 -0400285 if (NetBootFileSize)
286 debug("NetBootFileSize: %d\n", NetBootFileSize);
Luuk Paulussen6380e012011-05-16 18:29:19 +0000287
288#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
289 if (NetNtpServerIP)
290 debug("NetNtpServerIP : %pI4\n", &NetNtpServerIP);
291#endif
wdenk3861aa52002-09-27 23:19:37 +0000292}
Simon Glassab068eb2011-06-13 16:13:12 -0700293
wdenk3861aa52002-09-27 23:19:37 +0000294/*
295 * Handle a BOOTP received packet.
296 */
297static void
Luca Ceresoli428ab362011-04-18 06:19:50 +0000298BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
299 unsigned len)
wdenk3861aa52002-09-27 23:19:37 +0000300{
301 Bootp_t *bp;
wdenk3861aa52002-09-27 23:19:37 +0000302
Robin Getz9e0a4d62009-07-23 03:01:03 -0400303 debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
wdenk3861aa52002-09-27 23:19:37 +0000304 src, dest, len, sizeof (Bootp_t));
305
306 bp = (Bootp_t *)pkt;
307
wdenk29e7f5a2004-03-12 00:14:09 +0000308 if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
wdenk3861aa52002-09-27 23:19:37 +0000309 return;
310
311 /*
wdenk29e7f5a2004-03-12 00:14:09 +0000312 * Got a good BOOTP reply. Copy the data into our variables.
wdenk3861aa52002-09-27 23:19:37 +0000313 */
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))
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200322 BootpVendorProcess((uchar *)&bp->bp_vend[4], len);
wdenk3861aa52002-09-27 23:19:37 +0000323
324 NetSetTimeout(0, (thand_f *)0);
325
Robin Getz9e0a4d62009-07-23 03:01:03 -0400326 debug("Got good BOOTP\n");
wdenk3861aa52002-09-27 23:19:37 +0000327
Simon Glass5234ad12011-10-27 06:24:32 +0000328 net_auto_load();
wdenk3861aa52002-09-27 23:19:37 +0000329}
Jon Loeligera9807e52007-07-10 11:05:02 -0500330#endif
wdenk3861aa52002-09-27 23:19:37 +0000331
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 {
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200342 NetSetTimeout (TIMEOUT, BootpTimeout);
wdenk3861aa52002-09-27 23:19:37 +0000343 BootpRequest ();
344 }
345}
346
347/*
348 * Initialize BOOTP extension fields in the request.
349 */
Jon Loeliger54f35c22007-07-09 17:45:14 -0500350#if defined(CONFIG_CMD_DHCP)
wdenk29e7f5a2004-03-12 00:14:09 +0000351static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)
wdenk3861aa52002-09-27 23:19:37 +0000352{
wdenk29e7f5a2004-03-12 00:14:09 +0000353 u8 *start = e;
354 u8 *cnt;
Jason Hobbsea3202812011-08-31 05:37:31 +0000355#if defined(CONFIG_BOOTP_PXE)
356 char *uuid;
357 size_t vci_strlen;
358 u16 clientarch;
359#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000360
Jon Loeliger5336a762007-07-09 22:08:34 -0500361#if defined(CONFIG_BOOTP_VENDOREX)
wdenk29e7f5a2004-03-12 00:14:09 +0000362 u8 *x;
wdenk3861aa52002-09-27 23:19:37 +0000363#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500364#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200365 char *hostname;
stroesee0aadfb2003-08-28 14:17:32 +0000366#endif
wdenk3861aa52002-09-27 23:19:37 +0000367
wdenk29e7f5a2004-03-12 00:14:09 +0000368 *e++ = 99; /* RFC1048 Magic Cookie */
369 *e++ = 130;
370 *e++ = 83;
371 *e++ = 99;
wdenk3861aa52002-09-27 23:19:37 +0000372
wdenk29e7f5a2004-03-12 00:14:09 +0000373 *e++ = 53; /* DHCP Message Type */
374 *e++ = 1;
375 *e++ = message_type;
wdenk3861aa52002-09-27 23:19:37 +0000376
wdenk29e7f5a2004-03-12 00:14:09 +0000377 *e++ = 57; /* Maximum DHCP Message Size */
378 *e++ = 2;
379 *e++ = (576 - 312 + OPT_SIZE) >> 8;
380 *e++ = (576 - 312 + OPT_SIZE) & 0xff;
wdenk3861aa52002-09-27 23:19:37 +0000381
wdenk29e7f5a2004-03-12 00:14:09 +0000382 if (ServerID) {
383 int tmp = ntohl (ServerID);
wdenk3861aa52002-09-27 23:19:37 +0000384
wdenk29e7f5a2004-03-12 00:14:09 +0000385 *e++ = 54; /* ServerID */
386 *e++ = 4;
387 *e++ = tmp >> 24;
388 *e++ = tmp >> 16;
389 *e++ = tmp >> 8;
390 *e++ = tmp & 0xff;
391 }
wdenk3861aa52002-09-27 23:19:37 +0000392
wdenk29e7f5a2004-03-12 00:14:09 +0000393 if (RequestedIP) {
394 int tmp = ntohl (RequestedIP);
wdenk3861aa52002-09-27 23:19:37 +0000395
wdenk29e7f5a2004-03-12 00:14:09 +0000396 *e++ = 50; /* Requested IP */
397 *e++ = 4;
398 *e++ = tmp >> 24;
399 *e++ = tmp >> 16;
400 *e++ = tmp >> 8;
401 *e++ = tmp & 0xff;
402 }
Jon Loeliger5336a762007-07-09 22:08:34 -0500403#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
wdenk29e7f5a2004-03-12 00:14:09 +0000404 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 }
Jason Hobbsea3202812011-08-31 05:37:31 +0000412#endif
413
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;
stroesee0aadfb2003-08-28 14:17:32 +0000447#endif
448
Jon Loeliger5336a762007-07-09 22:08:34 -0500449#if defined(CONFIG_BOOTP_VENDOREX)
wdenk29e7f5a2004-03-12 00:14:09 +0000450 if ((x = dhcp_vendorex_prep (e)))
451 return x - start;
wdenk3861aa52002-09-27 23:19:37 +0000452#endif
453
wdenk29e7f5a2004-03-12 00:14:09 +0000454 *e++ = 55; /* Parameter Request List */
455 cnt = e++; /* Pointer to count of requested items */
456 *cnt = 0;
Jon Loeliger5336a762007-07-09 22:08:34 -0500457#if defined(CONFIG_BOOTP_SUBNETMASK)
wdenk29e7f5a2004-03-12 00:14:09 +0000458 *e++ = 1; /* Subnet Mask */
459 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000460#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500461#if defined(CONFIG_BOOTP_TIMEOFFSET)
wdenkb4ad9622005-04-01 00:25:43 +0000462 *e++ = 2;
463 *cnt += 1;
464#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500465#if defined(CONFIG_BOOTP_GATEWAY)
wdenk29e7f5a2004-03-12 00:14:09 +0000466 *e++ = 3; /* Router Option */
467 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000468#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500469#if defined(CONFIG_BOOTP_DNS)
wdenk29e7f5a2004-03-12 00:14:09 +0000470 *e++ = 6; /* DNS Server(s) */
471 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000472#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500473#if defined(CONFIG_BOOTP_HOSTNAME)
wdenk29e7f5a2004-03-12 00:14:09 +0000474 *e++ = 12; /* Hostname */
475 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000476#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500477#if defined(CONFIG_BOOTP_BOOTFILESIZE)
wdenk29e7f5a2004-03-12 00:14:09 +0000478 *e++ = 13; /* Boot File Size */
479 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000480#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500481#if defined(CONFIG_BOOTP_BOOTPATH)
wdenk29e7f5a2004-03-12 00:14:09 +0000482 *e++ = 17; /* Boot path */
483 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000484#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500485#if defined(CONFIG_BOOTP_NISDOMAIN)
wdenk29e7f5a2004-03-12 00:14:09 +0000486 *e++ = 40; /* NIS Domain name request */
487 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000488#endif
Jon Loeliger5336a762007-07-09 22:08:34 -0500489#if defined(CONFIG_BOOTP_NTPSERVER)
wdenkb4ad9622005-04-01 00:25:43 +0000490 *e++ = 42;
491 *cnt += 1;
492#endif
Jason Liu1c7dca52010-11-14 12:23:09 +0800493 /* no options, so back up to avoid sending an empty request list */
494 if (*cnt == 0)
495 e -= 2;
496
wdenk29e7f5a2004-03-12 00:14:09 +0000497 *e++ = 255; /* End of the list */
wdenk3861aa52002-09-27 23:19:37 +0000498
wdenk29e7f5a2004-03-12 00:14:09 +0000499 /* Pad to minimal length */
wdenk3861aa52002-09-27 23:19:37 +0000500#ifdef CONFIG_DHCP_MIN_EXT_LEN
Simon Glassa0978eb2011-02-02 15:03:28 -0800501 while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
wdenk29e7f5a2004-03-12 00:14:09 +0000502 *e++ = 0;
wdenk3861aa52002-09-27 23:19:37 +0000503#endif
504
wdenk29e7f5a2004-03-12 00:14:09 +0000505 return e - start;
wdenk3861aa52002-09-27 23:19:37 +0000506}
507
Jon Loeligera9807e52007-07-10 11:05:02 -0500508#else
wdenk3861aa52002-09-27 23:19:37 +0000509/*
Jon Loeliger5336a762007-07-09 22:08:34 -0500510 * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
wdenk3861aa52002-09-27 23:19:37 +0000511 */
wdenk29e7f5a2004-03-12 00:14:09 +0000512static int BootpExtended (u8 * e)
wdenk3861aa52002-09-27 23:19:37 +0000513{
wdenk29e7f5a2004-03-12 00:14:09 +0000514 u8 *start = e;
wdenk3861aa52002-09-27 23:19:37 +0000515
wdenk29e7f5a2004-03-12 00:14:09 +0000516 *e++ = 99; /* RFC1048 Magic Cookie */
517 *e++ = 130;
518 *e++ = 83;
519 *e++ = 99;
wdenk3861aa52002-09-27 23:19:37 +0000520
Jon Loeliger54f35c22007-07-09 17:45:14 -0500521#if defined(CONFIG_CMD_DHCP)
wdenk29e7f5a2004-03-12 00:14:09 +0000522 *e++ = 53; /* DHCP Message Type */
523 *e++ = 1;
524 *e++ = DHCP_DISCOVER;
wdenk3861aa52002-09-27 23:19:37 +0000525
wdenk29e7f5a2004-03-12 00:14:09 +0000526 *e++ = 57; /* Maximum DHCP Message Size */
527 *e++ = 2;
528 *e++ = (576 - 312 + OPT_SIZE) >> 16;
529 *e++ = (576 - 312 + OPT_SIZE) & 0xff;
Jon Loeligera9807e52007-07-10 11:05:02 -0500530#endif
wdenk3861aa52002-09-27 23:19:37 +0000531
Jon Loeliger5336a762007-07-09 22:08:34 -0500532#if defined(CONFIG_BOOTP_SUBNETMASK)
wdenk29e7f5a2004-03-12 00:14:09 +0000533 *e++ = 1; /* Subnet mask request */
534 *e++ = 4;
535 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000536#endif
537
Jon Loeliger5336a762007-07-09 22:08:34 -0500538#if defined(CONFIG_BOOTP_GATEWAY)
wdenk29e7f5a2004-03-12 00:14:09 +0000539 *e++ = 3; /* Default gateway request */
540 *e++ = 4;
541 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000542#endif
543
Jon Loeliger5336a762007-07-09 22:08:34 -0500544#if defined(CONFIG_BOOTP_DNS)
wdenk29e7f5a2004-03-12 00:14:09 +0000545 *e++ = 6; /* Domain Name Server */
546 *e++ = 4;
547 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000548#endif
549
Jon Loeliger5336a762007-07-09 22:08:34 -0500550#if defined(CONFIG_BOOTP_HOSTNAME)
wdenk29e7f5a2004-03-12 00:14:09 +0000551 *e++ = 12; /* Host name request */
552 *e++ = 32;
553 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000554#endif
555
Jon Loeliger5336a762007-07-09 22:08:34 -0500556#if defined(CONFIG_BOOTP_BOOTFILESIZE)
wdenk29e7f5a2004-03-12 00:14:09 +0000557 *e++ = 13; /* Boot file size */
558 *e++ = 2;
559 e += 2;
wdenk3861aa52002-09-27 23:19:37 +0000560#endif
561
Jon Loeliger5336a762007-07-09 22:08:34 -0500562#if defined(CONFIG_BOOTP_BOOTPATH)
wdenk29e7f5a2004-03-12 00:14:09 +0000563 *e++ = 17; /* Boot path */
564 *e++ = 32;
565 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000566#endif
567
Jon Loeliger5336a762007-07-09 22:08:34 -0500568#if defined(CONFIG_BOOTP_NISDOMAIN)
wdenk29e7f5a2004-03-12 00:14:09 +0000569 *e++ = 40; /* NIS Domain name request */
570 *e++ = 32;
571 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000572#endif
Luuk Paulussen6380e012011-05-16 18:29:19 +0000573#if defined(CONFIG_BOOTP_NTPSERVER)
574 *e++ = 42;
575 *e++ = 4;
576 e += 4;
577#endif
wdenk3861aa52002-09-27 23:19:37 +0000578
wdenk29e7f5a2004-03-12 00:14:09 +0000579 *e++ = 255; /* End of the list */
wdenk3861aa52002-09-27 23:19:37 +0000580
wdenk29e7f5a2004-03-12 00:14:09 +0000581 return e - start;
wdenk3861aa52002-09-27 23:19:37 +0000582}
Jon Loeligera9807e52007-07-10 11:05:02 -0500583#endif
wdenk3861aa52002-09-27 23:19:37 +0000584
585void
586BootpRequest (void)
587{
588 volatile uchar *pkt, *iphdr;
589 Bootp_t *bp;
590 int ext_len, pktlen, iplen;
591
Jon Loeliger54f35c22007-07-09 17:45:14 -0500592#if defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000593 dhcp_state = INIT;
594#endif
595
596#ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */
597 unsigned char bi_enetaddr[6];
598 int reg;
wdenk3861aa52002-09-27 23:19:37 +0000599 ulong tst1, tst2, sum, m_mask, m_value = 0;
600
601 if (BootpTry ==0) {
602 /* get our mac */
Mike Frysinger79ca1b92009-02-11 18:23:48 -0500603 eth_getenv_enetaddr("ethaddr", bi_enetaddr);
wdenk3861aa52002-09-27 23:19:37 +0000604
Robin Getz9e0a4d62009-07-23 03:01:03 -0400605 debug("BootpRequest => Our Mac: ");
606 for (reg=0; reg<6; reg++)
607 debug("%x%c", bi_enetaddr[reg], reg==5 ? '\n' : ':');
wdenk3861aa52002-09-27 23:19:37 +0000608
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++;
wdenk57b2d802003-06-27 21:31:46 +0000640 seed2 = seed1;
wdenk3861aa52002-09-27 23:19:37 +0000641 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
wdenk145d2c12004-04-15 21:48:45 +0000660 pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
wdenk3861aa52002-09-27 23:19:37 +0000661
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;
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200677 bp->bp_secs = htons(get_timer(0) / 1000);
wdenk3861aa52002-09-27 23:19:37 +0000678 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 */
Jon Loeliger54f35c22007-07-09 17:45:14 -0500686#if defined(CONFIG_CMD_DHCP)
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200687 ext_len = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
wdenk3861aa52002-09-27 23:19:37 +0000688#else
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200689 ext_len = BootpExtended((u8 *)bp->bp_vend);
Jon Loeligera9807e52007-07-10 11:05:02 -0500690#endif
wdenk3861aa52002-09-27 23:19:37 +0000691
692 /*
693 * Bootp ID is the lower 4 bytes of our ethernet address
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200694 * plus the current time in ms.
wdenk3861aa52002-09-27 23:19:37 +0000695 */
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);
wdenk29e7f5a2004-03-12 00:14:09 +0000701 BootpID = htonl(BootpID);
wdenk3861aa52002-09-27 23:19:37 +0000702 NetCopyLong(&bp->bp_id, &BootpID);
703
704 /*
705 * Calculate proper packet lengths taking into account the
706 * variable size of the options field
707 */
Norbert van Bolhuis20a020c2009-06-04 09:39:48 +0200708 pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
wdenk3861aa52002-09-27 23:19:37 +0000709 iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
710 NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200711 NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
wdenk3861aa52002-09-27 23:19:37 +0000712
Jon Loeliger54f35c22007-07-09 17:45:14 -0500713#if defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000714 dhcp_state = SELECTING;
715 NetSetHandler(DhcpHandler);
716#else
717 NetSetHandler(BootpHandler);
Jon Loeligera9807e52007-07-10 11:05:02 -0500718#endif
wdenk3861aa52002-09-27 23:19:37 +0000719 NetSendPacket(NetTxPacket, pktlen);
720}
721
Jon Loeliger54f35c22007-07-09 17:45:14 -0500722#if defined(CONFIG_CMD_DHCP)
Wolfgang Denk012429c2006-03-12 18:26:46 +0100723static void DhcpOptionsProcess (uchar * popt, Bootp_t *bp)
wdenk3861aa52002-09-27 23:19:37 +0000724{
wdenkb02744a2003-04-05 00:53:31 +0000725 uchar *end = popt + BOOTP_HDR_SIZE;
wdenk3861aa52002-09-27 23:19:37 +0000726 int oplen, size;
Wolfgang Denk2b184222009-09-11 09:05:32 +0200727#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
728 int *to_ptr;
729#endif
wdenk3861aa52002-09-27 23:19:37 +0000730
wdenk29e7f5a2004-03-12 00:14:09 +0000731 while (popt < end && *popt != 0xff) {
wdenk3861aa52002-09-27 23:19:37 +0000732 oplen = *(popt + 1);
wdenk29e7f5a2004-03-12 00:14:09 +0000733 switch (*popt) {
734 case 1:
735 NetCopyIP (&NetOurSubnetMask, (popt + 2));
736 break;
Jon Loeliger5336a762007-07-09 22:08:34 -0500737#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
wdenkb4ad9622005-04-01 00:25:43 +0000738 case 2: /* Time offset */
Wolfgang Denk2b184222009-09-11 09:05:32 +0200739 to_ptr = &NetTimeOffset;
740 NetCopyLong ((ulong *)to_ptr, (ulong *)(popt + 2));
wdenkb4ad9622005-04-01 00:25:43 +0000741 NetTimeOffset = ntohl (NetTimeOffset);
742 break;
743#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000744 case 3:
745 NetCopyIP (&NetOurGatewayIP, (popt + 2));
746 break;
747 case 6:
748 NetCopyIP (&NetOurDNSIP, (popt + 2));
Jon Loeliger5336a762007-07-09 22:08:34 -0500749#if defined(CONFIG_BOOTP_DNS2)
wdenk29e7f5a2004-03-12 00:14:09 +0000750 if (*(popt + 1) > 4) {
751 NetCopyIP (&NetOurDNS2IP, (popt + 2 + 4));
752 }
stroesee0aadfb2003-08-28 14:17:32 +0000753#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000754 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;
Jon Loeliger5336a762007-07-09 22:08:34 -0500767#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
wdenkb4ad9622005-04-01 00:25:43 +0000768 case 42: /* NTP server IP */
769 NetCopyIP (&NetNtpServerIP, (popt + 2));
770 break;
771#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000772 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;
Wolfgang Denk012429c2006-03-12 18:26:46 +0100784 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;
wdenk29e7f5a2004-03-12 00:14:09 +0000812 default:
Jon Loeliger5336a762007-07-09 22:08:34 -0500813#if defined(CONFIG_BOOTP_VENDOREX)
wdenk29e7f5a2004-03-12 00:14:09 +0000814 if (dhcp_vendorex_proc (popt))
wdenk57b2d802003-06-27 21:31:46 +0000815 break;
wdenk3861aa52002-09-27 23:19:37 +0000816#endif
wdenk29e7f5a2004-03-12 00:14:09 +0000817 printf ("*** Unhandled DHCP Option in OFFER/ACK: %d\n", *popt);
818 break;
wdenk3861aa52002-09-27 23:19:37 +0000819 }
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
wdenkb02744a2003-04-05 00:53:31 +0000838static void DhcpSendRequestPkt(Bootp_t *bp_offer)
wdenk3861aa52002-09-27 23:19:37 +0000839{
840 volatile uchar *pkt, *iphdr;
841 Bootp_t *bp;
842 int pktlen, iplen, extlen;
wdenkcc1e2562003-03-06 13:39:27 +0000843 IPaddr_t OfferedIP;
wdenk3861aa52002-09-27 23:19:37 +0000844
Robin Getz9e0a4d62009-07-23 03:01:03 -0400845 debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
wdenk3861aa52002-09-27 23:19:37 +0000846 pkt = NetTxPacket;
847 memset ((void*)pkt, 0, PKTSIZE);
848
wdenk145d2c12004-04-15 21:48:45 +0000849 pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
wdenk3861aa52002-09-27 23:19:37 +0000850
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;
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200859 bp->bp_secs = htons(get_timer(0) / 1000);
Justin Flammia01f256b2007-10-29 17:40:35 -0400860 /* 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
Wolfgang Denk8a933fb2006-10-12 00:01:08 +0200863 /*
Wolfgang Denk68e83a82006-10-09 01:26:14 +0200864 * RFC3046 requires Relay Agents to discard packets with
865 * nonzero and offered giaddr
866 */
867 NetWriteIP(&bp->bp_giaddr, 0);
868
wdenk3861aa52002-09-27 23:19:37 +0000869 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 */
Justin Flammia01f256b2007-10-29 17:40:35 -0400880
881 /* Copy offered IP into the parameters request list */
882 NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr);
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200883 extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP);
wdenk3861aa52002-09-27 23:19:37 +0000884
Norbert van Bolhuis20a020c2009-06-04 09:39:48 +0200885 pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
wdenk3861aa52002-09-27 23:19:37 +0000886 iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
887 NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
888
Robin Getz9e0a4d62009-07-23 03:01:03 -0400889 debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
Aras Vaichas72aa3f32008-03-26 09:43:57 +1100890#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
891 udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
892#endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
wdenk3861aa52002-09-27 23:19:37 +0000893 NetSendPacket(NetTxPacket, pktlen);
894}
895
896/*
897 * Handle DHCP received packets.
898 */
899static void
Luca Ceresoli428ab362011-04-18 06:19:50 +0000900DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
901 unsigned len)
wdenk3861aa52002-09-27 23:19:37 +0000902{
903 Bootp_t *bp = (Bootp_t *)pkt;
904
Robin Getz9e0a4d62009-07-23 03:01:03 -0400905 debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
wdenk3861aa52002-09-27 23:19:37 +0000906 src, dest, len, dhcp_state);
907
wdenk29e7f5a2004-03-12 00:14:09 +0000908 if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
wdenk3861aa52002-09-27 23:19:37 +0000909 return;
910
Robin Getz9e0a4d62009-07-23 03:01:03 -0400911 debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n",
wdenk3861aa52002-09-27 23:19:37 +0000912 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 */
Robin Getz9e0a4d62009-07-23 03:01:03 -0400922 debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200923#ifdef CONFIG_SYS_BOOTFILE_PREFIX
wdenk3861aa52002-09-27 23:19:37 +0000924 if (strncmp(bp->bp_file,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200925 CONFIG_SYS_BOOTFILE_PREFIX,
926 strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0 ) {
927#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
wdenk3861aa52002-09-27 23:19:37 +0000928
Robin Getz9e0a4d62009-07-23 03:01:03 -0400929 debug("TRANSITIONING TO REQUESTING STATE\n");
wdenk3861aa52002-09-27 23:19:37 +0000930 dhcp_state = REQUESTING;
stroese5fa6e902003-04-10 13:26:44 +0000931
wdenk3861aa52002-09-27 23:19:37 +0000932 if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
Wolfgang Denk012429c2006-03-12 18:26:46 +0100933 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
wdenk3861aa52002-09-27 23:19:37 +0000934
Bartlomiej Sieka56668462008-10-01 15:26:28 +0200935 NetSetTimeout(TIMEOUT, BootpTimeout);
wdenk3861aa52002-09-27 23:19:37 +0000936 DhcpSendRequestPkt(bp);
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200937#ifdef CONFIG_SYS_BOOTFILE_PREFIX
wdenk3861aa52002-09-27 23:19:37 +0000938 }
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200939#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
wdenk3861aa52002-09-27 23:19:37 +0000940
941 return;
942 break;
943 case REQUESTING:
Robin Getz9e0a4d62009-07-23 03:01:03 -0400944 debug("DHCP State: REQUESTING\n");
wdenk3861aa52002-09-27 23:19:37 +0000945
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200946 if ( DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK ) {
wdenk3861aa52002-09-27 23:19:37 +0000947 if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
Wolfgang Denk012429c2006-03-12 18:26:46 +0100948 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
wdenk29e7f5a2004-03-12 00:14:09 +0000949 BootpCopyNetParams(bp); /* Store net params from reply */
wdenk3861aa52002-09-27 23:19:37 +0000950 dhcp_state = BOUND;
Mike Frysingerd5695f42009-02-17 00:00:53 -0500951 printf ("DHCP client bound to address %pI4\n", &NetOurIP);
wdenk3861aa52002-09-27 23:19:37 +0000952
Simon Glass5234ad12011-10-27 06:24:32 +0000953 net_auto_load();
wdenk3861aa52002-09-27 23:19:37 +0000954 return;
955 }
956 break;
Remy Bohmer03a44492008-08-20 11:30:28 +0200957 case BOUND:
958 /* DHCP client bound to address */
959 break;
wdenk3861aa52002-09-27 23:19:37 +0000960 default:
wdenk42c05472004-03-23 22:14:11 +0000961 puts ("DHCP: INVALID STATE\n");
wdenk3861aa52002-09-27 23:19:37 +0000962 break;
963 }
964
965}
966
967void DhcpRequest(void)
968{
969 BootpRequest();
970}
Wolfgang Denkf7a7f082007-11-03 23:09:27 +0100971#endif /* CONFIG_CMD_DHCP */