blob: 9e324769db12e07b49b4a6dda91c01487d1fa035 [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
wdenk232c1502004-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"
wdenk232c1502004-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 Gustschinc0fe04b2011-11-19 10:29:58 +000020#include <linux/compiler.h>
wdenk3861aa52002-09-27 23:19:37 +000021
wdenk232c1502004-03-12 00:14:09 +000022#define BOOTP_VENDOR_MAGIC 0x63825363 /* RFC1048 Magic Cookie */
wdenk3861aa52002-09-27 23:19:37 +000023
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +020024#define TIMEOUT 5000UL /* Milliseconds before trying BOOTP again */
wdenk232c1502004-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
wdenk232c1502004-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 */
wdenk232c1502004-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 Loeliger643d1ab2007-07-09 17:45:14 -050044#if defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +000045dhcp_state_t dhcp_state = INIT;
wdenk682011f2003-06-03 23:54:09 +000046unsigned long dhcp_leasetime = 0;
stroese759a51b2003-04-10 13:26:44 +000047IPaddr_t NetDHCPServerIP = 0;
Luca Ceresoli03eb1292011-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 */
wdenk3e386912003-04-05 00:53:31 +000052#if 0
53static char *dhcpmsg2str(int type)
wdenk3861aa52002-09-27 23:19:37 +000054{
55 switch (type) {
wdenk232c1502004-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}
wdenk3e386912003-04-05 00:53:31 +000066#endif
wdenk3861aa52002-09-27 23:19:37 +000067
Jon Loeliger1fe80d72007-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 Loeliger610f2e92007-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 Getz0ebf04c2009-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 */
wdenk3e386912003-04-05 00:53:31 +0000107static void BootpCopyNetParams(Bootp_t *bp)
wdenk3861aa52002-09-27 23:19:37 +0000108{
Anatolij Gustschinc0fe04b2011-11-19 10:29:58 +0000109 __maybe_unused IPaddr_t tmp_ip;
wdenk3d3befa2004-03-14 15:06:13 +0000110
wdenk3861aa52002-09-27 23:19:37 +0000111 NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
Wilson Callan5d110f02007-07-28 10:56:13 -0400112#if !defined(CONFIG_BOOTP_SERVERIP)
wdenk3d3befa2004-03-14 15:06:13 +0000113 NetCopyIP(&tmp_ip, &bp->bp_siaddr);
114 if (tmp_ip != 0)
115 NetCopyIP(&NetServerIP, &bp->bp_siaddr);
Mike Frysingerd9bec9f2009-07-18 21:04:08 -0400116 memcpy (NetServerEther, ((Ethernet_t *)NetRxPacket)->et_src, 6);
Wilson Callan5d110f02007-07-28 10:56:13 -0400117#endif
wdenk3d3befa2004-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 Getz0ebf04c2009-07-23 03:01:03 -0400121 debug("Bootfile: %s\n", BootFile);
wdenk3861aa52002-09-27 23:19:37 +0000122
123 /* Propagate to environment:
wdenk8bde7f72003-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 Loeliger643d1ab2007-07-09 17:45:14 -0500142#if !defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000143
wdenk232c1502004-03-12 00:14:09 +0000144static void BootpVendorFieldProcess (u8 * ext)
wdenk3861aa52002-09-27 23:19:37 +0000145{
wdenk232c1502004-03-12 00:14:09 +0000146 int size = *(ext + 1);
wdenk3861aa52002-09-27 23:19:37 +0000147
Robin Getz0ebf04c2009-07-23 03:01:03 -0400148 debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
wdenk232c1502004-03-12 00:14:09 +0000149 *(ext + 1));
wdenk3861aa52002-09-27 23:19:37 +0000150
wdenk232c1502004-03-12 00:14:09 +0000151 NetBootFileSize = 0;
wdenk3861aa52002-09-27 23:19:37 +0000152
wdenk232c1502004-03-12 00:14:09 +0000153 switch (*ext) {
154 /* Fixed length fields */
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700155 case 1: /* Subnet mask */
wdenk3861aa52002-09-27 23:19:37 +0000156 if (NetOurSubnetMask == 0)
wdenk232c1502004-03-12 00:14:09 +0000157 NetCopyIP (&NetOurSubnetMask, (IPaddr_t *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000158 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700159 case 2: /* Time offset - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000160 break;
wdenk232c1502004-03-12 00:14:09 +0000161 /* Variable length fields */
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700162 case 3: /* Gateways list */
wdenk3861aa52002-09-27 23:19:37 +0000163 if (NetOurGatewayIP == 0) {
wdenk232c1502004-03-12 00:14:09 +0000164 NetCopyIP (&NetOurGatewayIP, (IPaddr_t *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000165 }
166 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700167 case 4: /* Time server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000168 break;
Wolfgang Denk1aeed8d2008-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) {
wdenk232c1502004-03-12 00:14:09 +0000173 NetCopyIP (&NetOurDNSIP, (IPaddr_t *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000174 }
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500175#if defined(CONFIG_BOOTP_DNS2)
stroesefe389a82003-08-28 14:17:32 +0000176 if ((NetOurDNS2IP == 0) && (size > 4)) {
wdenk232c1502004-03-12 00:14:09 +0000177 NetCopyIP (&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4));
stroesefe389a82003-08-28 14:17:32 +0000178 }
179#endif
wdenk3861aa52002-09-27 23:19:37 +0000180 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700181 case 7: /* Log server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000182 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700183 case 8: /* Cookie/Quote server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000184 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700185 case 9: /* LPR server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000186 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700187 case 10: /* Impress server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000188 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700189 case 11: /* RPL server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000190 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700191 case 12: /* Host name */
wdenk3861aa52002-09-27 23:19:37 +0000192 if (NetOurHostName[0] == 0) {
wdenk232c1502004-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 Denk1aeed8d2008-04-13 09:59:26 -0700198 case 13: /* Boot file size */
wdenk3861aa52002-09-27 23:19:37 +0000199 if (size == 2)
wdenk232c1502004-03-12 00:14:09 +0000200 NetBootFileSize = ntohs (*(ushort *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000201 else if (size == 4)
wdenk232c1502004-03-12 00:14:09 +0000202 NetBootFileSize = ntohl (*(ulong *) (ext + 2));
wdenk3861aa52002-09-27 23:19:37 +0000203 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700204 case 14: /* Merit dump file - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000205 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700206 case 15: /* Domain name - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000207 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700208 case 16: /* Swap server - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000209 break;
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700210 case 17: /* Root path */
wdenk3861aa52002-09-27 23:19:37 +0000211 if (NetOurRootPath[0] == 0) {
wdenk232c1502004-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 Denk1aeed8d2008-04-13 09:59:26 -0700217 case 18: /* Extension path - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000218 /*
wdenk8bde7f72003-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;
wdenk232c1502004-03-12 00:14:09 +0000224 /* IP host layer fields */
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700225 case 40: /* NIS Domain name */
wdenk3861aa52002-09-27 23:19:37 +0000226 if (NetOurNISDomain[0] == 0) {
wdenk232c1502004-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 Paulussen09e3a672011-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
wdenk232c1502004-03-12 00:14:09 +0000237 /* Application layer fields */
Wolfgang Denk1aeed8d2008-04-13 09:59:26 -0700238 case 43: /* Vendor specific info - Not yet supported */
wdenk3861aa52002-09-27 23:19:37 +0000239 /*
wdenk8bde7f72003-06-27 21:31:46 +0000240 * Binary information to exchange specific
241 * product information.
wdenk3861aa52002-09-27 23:19:37 +0000242 */
243 break;
wdenk232c1502004-03-12 00:14:09 +0000244 /* Reserved (custom) fields (128..254) */
245 }
wdenk3861aa52002-09-27 23:19:37 +0000246}
247
wdenk232c1502004-03-12 00:14:09 +0000248static void BootpVendorProcess (u8 * ext, int size)
wdenk3861aa52002-09-27 23:19:37 +0000249{
wdenk232c1502004-03-12 00:14:09 +0000250 u8 *end = ext + size;
wdenk3861aa52002-09-27 23:19:37 +0000251
Robin Getz0ebf04c2009-07-23 03:01:03 -0400252 debug("[BOOTP] Checking extension (%d bytes)...\n", size);
wdenk3861aa52002-09-27 23:19:37 +0000253
wdenk232c1502004-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 Getz0ebf04c2009-07-23 03:01:03 -0400266 debug("[BOOTP] Received fields: \n");
Mike Frysingerb6446b62009-02-17 00:00:53 -0500267 if (NetOurSubnetMask)
Robin Getz0ebf04c2009-07-23 03:01:03 -0400268 debug("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask);
wdenk3861aa52002-09-27 23:19:37 +0000269
Mike Frysingerb6446b62009-02-17 00:00:53 -0500270 if (NetOurGatewayIP)
Robin Getz0ebf04c2009-07-23 03:01:03 -0400271 debug("NetOurGatewayIP : %pI4", &NetOurGatewayIP);
wdenk3861aa52002-09-27 23:19:37 +0000272
Robin Getz0ebf04c2009-07-23 03:01:03 -0400273 if (NetBootFileSize)
274 debug("NetBootFileSize : %d\n", NetBootFileSize);
wdenk3861aa52002-09-27 23:19:37 +0000275
Robin Getz0ebf04c2009-07-23 03:01:03 -0400276 if (NetOurHostName[0])
277 debug("NetOurHostName : %s\n", NetOurHostName);
wdenk3861aa52002-09-27 23:19:37 +0000278
Robin Getz0ebf04c2009-07-23 03:01:03 -0400279 if (NetOurRootPath[0])
280 debug("NetOurRootPath : %s\n", NetOurRootPath);
wdenk3861aa52002-09-27 23:19:37 +0000281
Robin Getz0ebf04c2009-07-23 03:01:03 -0400282 if (NetOurNISDomain[0])
283 debug("NetOurNISDomain : %s\n", NetOurNISDomain);
wdenk3861aa52002-09-27 23:19:37 +0000284
Robin Getz0ebf04c2009-07-23 03:01:03 -0400285 if (NetBootFileSize)
286 debug("NetBootFileSize: %d\n", NetBootFileSize);
Luuk Paulussen09e3a672011-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 Glass09349862011-06-13 16:13:12 -0700293
wdenk3861aa52002-09-27 23:19:37 +0000294/*
295 * Handle a BOOTP received packet.
296 */
297static void
Luca Ceresoli03eb1292011-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 Getz0ebf04c2009-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
wdenk232c1502004-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 /*
wdenk232c1502004-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 Denk77ddac92005-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);
Simon Glass573f14f2011-12-10 11:08:06 +0000325 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
wdenk3861aa52002-09-27 23:19:37 +0000326
Robin Getz0ebf04c2009-07-23 03:01:03 -0400327 debug("Got good BOOTP\n");
wdenk3861aa52002-09-27 23:19:37 +0000328
Simon Glasse4a3d572011-10-27 06:24:32 +0000329 net_auto_load();
wdenk3861aa52002-09-27 23:19:37 +0000330}
Jon Loeliger610f2e92007-07-10 11:05:02 -0500331#endif
wdenk3861aa52002-09-27 23:19:37 +0000332
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 {
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200343 NetSetTimeout (TIMEOUT, BootpTimeout);
wdenk3861aa52002-09-27 23:19:37 +0000344 BootpRequest ();
345 }
346}
347
348/*
349 * Initialize BOOTP extension fields in the request.
350 */
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500351#if defined(CONFIG_CMD_DHCP)
wdenk232c1502004-03-12 00:14:09 +0000352static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)
wdenk3861aa52002-09-27 23:19:37 +0000353{
wdenk232c1502004-03-12 00:14:09 +0000354 u8 *start = e;
355 u8 *cnt;
Jason Hobbsd2b5d5c2011-08-31 05:37:31 +0000356#if defined(CONFIG_BOOTP_PXE)
357 char *uuid;
358 size_t vci_strlen;
359 u16 clientarch;
360#endif
wdenk232c1502004-03-12 00:14:09 +0000361
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500362#if defined(CONFIG_BOOTP_VENDOREX)
wdenk232c1502004-03-12 00:14:09 +0000363 u8 *x;
wdenk3861aa52002-09-27 23:19:37 +0000364#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500365#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200366 char *hostname;
stroesefe389a82003-08-28 14:17:32 +0000367#endif
wdenk3861aa52002-09-27 23:19:37 +0000368
wdenk232c1502004-03-12 00:14:09 +0000369 *e++ = 99; /* RFC1048 Magic Cookie */
370 *e++ = 130;
371 *e++ = 83;
372 *e++ = 99;
wdenk3861aa52002-09-27 23:19:37 +0000373
wdenk232c1502004-03-12 00:14:09 +0000374 *e++ = 53; /* DHCP Message Type */
375 *e++ = 1;
376 *e++ = message_type;
wdenk3861aa52002-09-27 23:19:37 +0000377
wdenk232c1502004-03-12 00:14:09 +0000378 *e++ = 57; /* Maximum DHCP Message Size */
379 *e++ = 2;
380 *e++ = (576 - 312 + OPT_SIZE) >> 8;
381 *e++ = (576 - 312 + OPT_SIZE) & 0xff;
wdenk3861aa52002-09-27 23:19:37 +0000382
wdenk232c1502004-03-12 00:14:09 +0000383 if (ServerID) {
384 int tmp = ntohl (ServerID);
wdenk3861aa52002-09-27 23:19:37 +0000385
wdenk232c1502004-03-12 00:14:09 +0000386 *e++ = 54; /* ServerID */
387 *e++ = 4;
388 *e++ = tmp >> 24;
389 *e++ = tmp >> 16;
390 *e++ = tmp >> 8;
391 *e++ = tmp & 0xff;
392 }
wdenk3861aa52002-09-27 23:19:37 +0000393
wdenk232c1502004-03-12 00:14:09 +0000394 if (RequestedIP) {
395 int tmp = ntohl (RequestedIP);
wdenk3861aa52002-09-27 23:19:37 +0000396
wdenk232c1502004-03-12 00:14:09 +0000397 *e++ = 50; /* Requested IP */
398 *e++ = 4;
399 *e++ = tmp >> 24;
400 *e++ = tmp >> 16;
401 *e++ = tmp >> 8;
402 *e++ = tmp & 0xff;
403 }
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500404#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
wdenk232c1502004-03-12 00:14:09 +0000405 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 }
stroesefe389a82003-08-28 14:17:32 +0000413#endif
414
Jason Hobbsd2b5d5c2011-08-31 05:37:31 +0000415#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
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500450#if defined(CONFIG_BOOTP_VENDOREX)
wdenk232c1502004-03-12 00:14:09 +0000451 if ((x = dhcp_vendorex_prep (e)))
452 return x - start;
wdenk3861aa52002-09-27 23:19:37 +0000453#endif
454
wdenk232c1502004-03-12 00:14:09 +0000455 *e++ = 55; /* Parameter Request List */
456 cnt = e++; /* Pointer to count of requested items */
457 *cnt = 0;
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500458#if defined(CONFIG_BOOTP_SUBNETMASK)
wdenk232c1502004-03-12 00:14:09 +0000459 *e++ = 1; /* Subnet Mask */
460 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000461#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500462#if defined(CONFIG_BOOTP_TIMEOFFSET)
wdenkea287de2005-04-01 00:25:43 +0000463 *e++ = 2;
464 *cnt += 1;
465#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500466#if defined(CONFIG_BOOTP_GATEWAY)
wdenk232c1502004-03-12 00:14:09 +0000467 *e++ = 3; /* Router Option */
468 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000469#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500470#if defined(CONFIG_BOOTP_DNS)
wdenk232c1502004-03-12 00:14:09 +0000471 *e++ = 6; /* DNS Server(s) */
472 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000473#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500474#if defined(CONFIG_BOOTP_HOSTNAME)
wdenk232c1502004-03-12 00:14:09 +0000475 *e++ = 12; /* Hostname */
476 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000477#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500478#if defined(CONFIG_BOOTP_BOOTFILESIZE)
wdenk232c1502004-03-12 00:14:09 +0000479 *e++ = 13; /* Boot File Size */
480 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000481#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500482#if defined(CONFIG_BOOTP_BOOTPATH)
wdenk232c1502004-03-12 00:14:09 +0000483 *e++ = 17; /* Boot path */
484 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000485#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500486#if defined(CONFIG_BOOTP_NISDOMAIN)
wdenk232c1502004-03-12 00:14:09 +0000487 *e++ = 40; /* NIS Domain name request */
488 *cnt += 1;
wdenk3861aa52002-09-27 23:19:37 +0000489#endif
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500490#if defined(CONFIG_BOOTP_NTPSERVER)
wdenkea287de2005-04-01 00:25:43 +0000491 *e++ = 42;
492 *cnt += 1;
493#endif
Jason Liu258ccd62010-11-14 12:23:09 +0800494 /* no options, so back up to avoid sending an empty request list */
495 if (*cnt == 0)
496 e -= 2;
497
wdenk232c1502004-03-12 00:14:09 +0000498 *e++ = 255; /* End of the list */
wdenk3861aa52002-09-27 23:19:37 +0000499
wdenk232c1502004-03-12 00:14:09 +0000500 /* Pad to minimal length */
wdenk3861aa52002-09-27 23:19:37 +0000501#ifdef CONFIG_DHCP_MIN_EXT_LEN
Simon Glass21076f62011-02-02 15:03:28 -0800502 while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
wdenk232c1502004-03-12 00:14:09 +0000503 *e++ = 0;
wdenk3861aa52002-09-27 23:19:37 +0000504#endif
505
wdenk232c1502004-03-12 00:14:09 +0000506 return e - start;
wdenk3861aa52002-09-27 23:19:37 +0000507}
508
Jon Loeliger610f2e92007-07-10 11:05:02 -0500509#else
wdenk3861aa52002-09-27 23:19:37 +0000510/*
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500511 * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
wdenk3861aa52002-09-27 23:19:37 +0000512 */
wdenk232c1502004-03-12 00:14:09 +0000513static int BootpExtended (u8 * e)
wdenk3861aa52002-09-27 23:19:37 +0000514{
wdenk232c1502004-03-12 00:14:09 +0000515 u8 *start = e;
wdenk3861aa52002-09-27 23:19:37 +0000516
wdenk232c1502004-03-12 00:14:09 +0000517 *e++ = 99; /* RFC1048 Magic Cookie */
518 *e++ = 130;
519 *e++ = 83;
520 *e++ = 99;
wdenk3861aa52002-09-27 23:19:37 +0000521
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500522#if defined(CONFIG_CMD_DHCP)
wdenk232c1502004-03-12 00:14:09 +0000523 *e++ = 53; /* DHCP Message Type */
524 *e++ = 1;
525 *e++ = DHCP_DISCOVER;
wdenk3861aa52002-09-27 23:19:37 +0000526
wdenk232c1502004-03-12 00:14:09 +0000527 *e++ = 57; /* Maximum DHCP Message Size */
528 *e++ = 2;
529 *e++ = (576 - 312 + OPT_SIZE) >> 16;
530 *e++ = (576 - 312 + OPT_SIZE) & 0xff;
Jon Loeliger610f2e92007-07-10 11:05:02 -0500531#endif
wdenk3861aa52002-09-27 23:19:37 +0000532
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500533#if defined(CONFIG_BOOTP_SUBNETMASK)
wdenk232c1502004-03-12 00:14:09 +0000534 *e++ = 1; /* Subnet mask request */
535 *e++ = 4;
536 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000537#endif
538
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500539#if defined(CONFIG_BOOTP_GATEWAY)
wdenk232c1502004-03-12 00:14:09 +0000540 *e++ = 3; /* Default gateway request */
541 *e++ = 4;
542 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000543#endif
544
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500545#if defined(CONFIG_BOOTP_DNS)
wdenk232c1502004-03-12 00:14:09 +0000546 *e++ = 6; /* Domain Name Server */
547 *e++ = 4;
548 e += 4;
wdenk3861aa52002-09-27 23:19:37 +0000549#endif
550
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500551#if defined(CONFIG_BOOTP_HOSTNAME)
wdenk232c1502004-03-12 00:14:09 +0000552 *e++ = 12; /* Host name request */
553 *e++ = 32;
554 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000555#endif
556
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500557#if defined(CONFIG_BOOTP_BOOTFILESIZE)
wdenk232c1502004-03-12 00:14:09 +0000558 *e++ = 13; /* Boot file size */
559 *e++ = 2;
560 e += 2;
wdenk3861aa52002-09-27 23:19:37 +0000561#endif
562
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500563#if defined(CONFIG_BOOTP_BOOTPATH)
wdenk232c1502004-03-12 00:14:09 +0000564 *e++ = 17; /* Boot path */
565 *e++ = 32;
566 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000567#endif
568
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500569#if defined(CONFIG_BOOTP_NISDOMAIN)
wdenk232c1502004-03-12 00:14:09 +0000570 *e++ = 40; /* NIS Domain name request */
571 *e++ = 32;
572 e += 32;
wdenk3861aa52002-09-27 23:19:37 +0000573#endif
Luuk Paulussen09e3a672011-05-16 18:29:19 +0000574#if defined(CONFIG_BOOTP_NTPSERVER)
575 *e++ = 42;
576 *e++ = 4;
577 e += 4;
578#endif
wdenk3861aa52002-09-27 23:19:37 +0000579
wdenk232c1502004-03-12 00:14:09 +0000580 *e++ = 255; /* End of the list */
wdenk3861aa52002-09-27 23:19:37 +0000581
wdenk232c1502004-03-12 00:14:09 +0000582 return e - start;
wdenk3861aa52002-09-27 23:19:37 +0000583}
Jon Loeliger610f2e92007-07-10 11:05:02 -0500584#endif
wdenk3861aa52002-09-27 23:19:37 +0000585
586void
587BootpRequest (void)
588{
589 volatile uchar *pkt, *iphdr;
590 Bootp_t *bp;
591 int ext_len, pktlen, iplen;
592
Simon Glass573f14f2011-12-10 11:08:06 +0000593 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500594#if defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000595 dhcp_state = INIT;
596#endif
597
598#ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */
599 unsigned char bi_enetaddr[6];
600 int reg;
wdenk3861aa52002-09-27 23:19:37 +0000601 ulong tst1, tst2, sum, m_mask, m_value = 0;
602
603 if (BootpTry ==0) {
604 /* get our mac */
Mike Frysinger95823ca2009-02-11 18:23:48 -0500605 eth_getenv_enetaddr("ethaddr", bi_enetaddr);
wdenk3861aa52002-09-27 23:19:37 +0000606
Robin Getz0ebf04c2009-07-23 03:01:03 -0400607 debug("BootpRequest => Our Mac: ");
608 for (reg=0; reg<6; reg++)
609 debug("%x%c", bi_enetaddr[reg], reg==5 ? '\n' : ':');
wdenk3861aa52002-09-27 23:19:37 +0000610
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++;
wdenk8bde7f72003-06-27 21:31:46 +0000642 seed2 = seed1;
wdenk3861aa52002-09-27 23:19:37 +0000643 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
wdenka3d991b2004-04-15 21:48:45 +0000662 pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
wdenk3861aa52002-09-27 23:19:37 +0000663
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;
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200679 bp->bp_secs = htons(get_timer(0) / 1000);
wdenk3861aa52002-09-27 23:19:37 +0000680 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 */
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500688#if defined(CONFIG_CMD_DHCP)
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200689 ext_len = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
wdenk3861aa52002-09-27 23:19:37 +0000690#else
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200691 ext_len = BootpExtended((u8 *)bp->bp_vend);
Jon Loeliger610f2e92007-07-10 11:05:02 -0500692#endif
wdenk3861aa52002-09-27 23:19:37 +0000693
694 /*
695 * Bootp ID is the lower 4 bytes of our ethernet address
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200696 * plus the current time in ms.
wdenk3861aa52002-09-27 23:19:37 +0000697 */
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);
wdenk232c1502004-03-12 00:14:09 +0000703 BootpID = htonl(BootpID);
wdenk3861aa52002-09-27 23:19:37 +0000704 NetCopyLong(&bp->bp_id, &BootpID);
705
706 /*
707 * Calculate proper packet lengths taking into account the
708 * variable size of the options field
709 */
Norbert van Bolhuisc9a2aab2009-06-04 09:39:48 +0200710 pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
wdenk3861aa52002-09-27 23:19:37 +0000711 iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
712 NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200713 NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
wdenk3861aa52002-09-27 23:19:37 +0000714
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500715#if defined(CONFIG_CMD_DHCP)
wdenk3861aa52002-09-27 23:19:37 +0000716 dhcp_state = SELECTING;
717 NetSetHandler(DhcpHandler);
718#else
719 NetSetHandler(BootpHandler);
Jon Loeliger610f2e92007-07-10 11:05:02 -0500720#endif
wdenk3861aa52002-09-27 23:19:37 +0000721 NetSendPacket(NetTxPacket, pktlen);
722}
723
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500724#if defined(CONFIG_CMD_DHCP)
Wolfgang Denk3b2e4fd2006-03-12 18:26:46 +0100725static void DhcpOptionsProcess (uchar * popt, Bootp_t *bp)
wdenk3861aa52002-09-27 23:19:37 +0000726{
wdenk3e386912003-04-05 00:53:31 +0000727 uchar *end = popt + BOOTP_HDR_SIZE;
wdenk3861aa52002-09-27 23:19:37 +0000728 int oplen, size;
Wolfgang Denkd8d87242009-09-11 09:05:32 +0200729#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
730 int *to_ptr;
731#endif
wdenk3861aa52002-09-27 23:19:37 +0000732
wdenk232c1502004-03-12 00:14:09 +0000733 while (popt < end && *popt != 0xff) {
wdenk3861aa52002-09-27 23:19:37 +0000734 oplen = *(popt + 1);
wdenk232c1502004-03-12 00:14:09 +0000735 switch (*popt) {
736 case 1:
737 NetCopyIP (&NetOurSubnetMask, (popt + 2));
738 break;
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500739#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
wdenkea287de2005-04-01 00:25:43 +0000740 case 2: /* Time offset */
Wolfgang Denkd8d87242009-09-11 09:05:32 +0200741 to_ptr = &NetTimeOffset;
742 NetCopyLong ((ulong *)to_ptr, (ulong *)(popt + 2));
wdenkea287de2005-04-01 00:25:43 +0000743 NetTimeOffset = ntohl (NetTimeOffset);
744 break;
745#endif
wdenk232c1502004-03-12 00:14:09 +0000746 case 3:
747 NetCopyIP (&NetOurGatewayIP, (popt + 2));
748 break;
749 case 6:
750 NetCopyIP (&NetOurDNSIP, (popt + 2));
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500751#if defined(CONFIG_BOOTP_DNS2)
wdenk232c1502004-03-12 00:14:09 +0000752 if (*(popt + 1) > 4) {
753 NetCopyIP (&NetOurDNS2IP, (popt + 2 + 4));
754 }
stroesefe389a82003-08-28 14:17:32 +0000755#endif
wdenk232c1502004-03-12 00:14:09 +0000756 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;
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500769#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
wdenkea287de2005-04-01 00:25:43 +0000770 case 42: /* NTP server IP */
771 NetCopyIP (&NetNtpServerIP, (popt + 2));
772 break;
773#endif
wdenk232c1502004-03-12 00:14:09 +0000774 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;
Wolfgang Denk3b2e4fd2006-03-12 18:26:46 +0100786 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;
wdenk232c1502004-03-12 00:14:09 +0000814 default:
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500815#if defined(CONFIG_BOOTP_VENDOREX)
wdenk232c1502004-03-12 00:14:09 +0000816 if (dhcp_vendorex_proc (popt))
wdenk8bde7f72003-06-27 21:31:46 +0000817 break;
wdenk3861aa52002-09-27 23:19:37 +0000818#endif
wdenk232c1502004-03-12 00:14:09 +0000819 printf ("*** Unhandled DHCP Option in OFFER/ACK: %d\n", *popt);
820 break;
wdenk3861aa52002-09-27 23:19:37 +0000821 }
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
wdenk3e386912003-04-05 00:53:31 +0000840static void DhcpSendRequestPkt(Bootp_t *bp_offer)
wdenk3861aa52002-09-27 23:19:37 +0000841{
842 volatile uchar *pkt, *iphdr;
843 Bootp_t *bp;
844 int pktlen, iplen, extlen;
wdenk47cd00f2003-03-06 13:39:27 +0000845 IPaddr_t OfferedIP;
wdenk3861aa52002-09-27 23:19:37 +0000846
Robin Getz0ebf04c2009-07-23 03:01:03 -0400847 debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
wdenk3861aa52002-09-27 23:19:37 +0000848 pkt = NetTxPacket;
849 memset ((void*)pkt, 0, PKTSIZE);
850
wdenka3d991b2004-04-15 21:48:45 +0000851 pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
wdenk3861aa52002-09-27 23:19:37 +0000852
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;
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200861 bp->bp_secs = htons(get_timer(0) / 1000);
Justin Flammiae5c794e2007-10-29 17:40:35 -0400862 /* 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
Wolfgang Denkc6686702006-10-12 00:01:08 +0200865 /*
Wolfgang Denkd82718f2006-10-09 01:26:14 +0200866 * RFC3046 requires Relay Agents to discard packets with
867 * nonzero and offered giaddr
868 */
869 NetWriteIP(&bp->bp_giaddr, 0);
870
wdenk3861aa52002-09-27 23:19:37 +0000871 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 */
Justin Flammiae5c794e2007-10-29 17:40:35 -0400882
883 /* Copy offered IP into the parameters request list */
884 NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr);
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200885 extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP);
wdenk3861aa52002-09-27 23:19:37 +0000886
Norbert van Bolhuisc9a2aab2009-06-04 09:39:48 +0200887 pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
wdenk3861aa52002-09-27 23:19:37 +0000888 iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
889 NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
890
Robin Getz0ebf04c2009-07-23 03:01:03 -0400891 debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
Aras Vaichasd9a2f412008-03-26 09:43:57 +1100892#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
893 udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
894#endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
wdenk3861aa52002-09-27 23:19:37 +0000895 NetSendPacket(NetTxPacket, pktlen);
896}
897
898/*
899 * Handle DHCP received packets.
900 */
901static void
Luca Ceresoli03eb1292011-04-18 06:19:50 +0000902DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
903 unsigned len)
wdenk3861aa52002-09-27 23:19:37 +0000904{
905 Bootp_t *bp = (Bootp_t *)pkt;
906
Robin Getz0ebf04c2009-07-23 03:01:03 -0400907 debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
wdenk3861aa52002-09-27 23:19:37 +0000908 src, dest, len, dhcp_state);
909
wdenk232c1502004-03-12 00:14:09 +0000910 if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
wdenk3861aa52002-09-27 23:19:37 +0000911 return;
912
Robin Getz0ebf04c2009-07-23 03:01:03 -0400913 debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n",
wdenk3861aa52002-09-27 23:19:37 +0000914 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 */
Robin Getz0ebf04c2009-07-23 03:01:03 -0400924 debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200925#ifdef CONFIG_SYS_BOOTFILE_PREFIX
wdenk3861aa52002-09-27 23:19:37 +0000926 if (strncmp(bp->bp_file,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200927 CONFIG_SYS_BOOTFILE_PREFIX,
928 strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0 ) {
929#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
wdenk3861aa52002-09-27 23:19:37 +0000930
Robin Getz0ebf04c2009-07-23 03:01:03 -0400931 debug("TRANSITIONING TO REQUESTING STATE\n");
wdenk3861aa52002-09-27 23:19:37 +0000932 dhcp_state = REQUESTING;
stroese759a51b2003-04-10 13:26:44 +0000933
wdenk3861aa52002-09-27 23:19:37 +0000934 if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
Wolfgang Denk3b2e4fd2006-03-12 18:26:46 +0100935 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
wdenk3861aa52002-09-27 23:19:37 +0000936
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200937 NetSetTimeout(TIMEOUT, BootpTimeout);
wdenk3861aa52002-09-27 23:19:37 +0000938 DhcpSendRequestPkt(bp);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200939#ifdef CONFIG_SYS_BOOTFILE_PREFIX
wdenk3861aa52002-09-27 23:19:37 +0000940 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200941#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
wdenk3861aa52002-09-27 23:19:37 +0000942
943 return;
944 break;
945 case REQUESTING:
Robin Getz0ebf04c2009-07-23 03:01:03 -0400946 debug("DHCP State: REQUESTING\n");
wdenk3861aa52002-09-27 23:19:37 +0000947
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200948 if ( DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK ) {
wdenk3861aa52002-09-27 23:19:37 +0000949 if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
Wolfgang Denk3b2e4fd2006-03-12 18:26:46 +0100950 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
wdenk232c1502004-03-12 00:14:09 +0000951 BootpCopyNetParams(bp); /* Store net params from reply */
wdenk3861aa52002-09-27 23:19:37 +0000952 dhcp_state = BOUND;
Mike Frysingerb6446b62009-02-17 00:00:53 -0500953 printf ("DHCP client bound to address %pI4\n", &NetOurIP);
Simon Glass573f14f2011-12-10 11:08:06 +0000954 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
955 "bootp_stop");
wdenk3861aa52002-09-27 23:19:37 +0000956
Simon Glasse4a3d572011-10-27 06:24:32 +0000957 net_auto_load();
wdenk3861aa52002-09-27 23:19:37 +0000958 return;
959 }
960 break;
Remy Bohmer51dfe132008-08-20 11:30:28 +0200961 case BOUND:
962 /* DHCP client bound to address */
963 break;
wdenk3861aa52002-09-27 23:19:37 +0000964 default:
wdenk4b9206e2004-03-23 22:14:11 +0000965 puts ("DHCP: INVALID STATE\n");
wdenk3861aa52002-09-27 23:19:37 +0000966 break;
967 }
968
969}
970
971void DhcpRequest(void)
972{
973 BootpRequest();
974}
Wolfgang Denk992742a2007-11-03 23:09:27 +0100975#endif /* CONFIG_CMD_DHCP */