xref: /openbmc/u-boot/net/bootp.c (revision e2211743)
1 /*
2  *	Based on LiMon - BOOTP.
3  *
4  *	Copyright 1994, 1995, 2000 Neil Russell.
5  *	(See License)
6  *	Copyright 2000 Roland Borde
7  *	Copyright 2000 Paolo Scaffardi
8  *	Copyright 2000-2002 Wolfgang Denk, wd@denx.de
9  */
10 
11 #if 0
12 #define	DEBUG		1	/* general debug */
13 #define DEBUG_BOOTP_EXT	1	/* Debug received vendor fields	*/
14 #endif
15 
16 #ifdef DEBUG_BOOTP_EXT
17 #define debug_ext(fmt,args...)	printf (fmt ,##args)
18 #else
19 #define debug_ext(fmt,args...)
20 #endif
21 
22 #include <common.h>
23 #include <command.h>
24 #include <net.h>
25 #include "bootp.h"
26 #include "tftp.h"
27 #include "arp.h"
28 #ifdef CONFIG_STATUS_LED
29 #include <status_led.h>
30 #endif
31 
32 #define	BOOTP_VENDOR_MAGIC	0x63825363 	/* RFC1048 Magic Cookie 	*/
33 
34 #if (CONFIG_COMMANDS & CFG_CMD_NET)
35 
36 #define TIMEOUT		5		/* Seconds before trying BOOTP again	*/
37 #ifndef	CONFIG_NET_RETRY_COUNT
38 # define TIMEOUT_COUNT	5		/* # of timeouts before giving up  */
39 #else
40 # define TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT)
41 #endif
42 
43 #define PORT_BOOTPS	67		/* BOOTP server UDP port		*/
44 #define PORT_BOOTPC	68		/* BOOTP client UDP port		*/
45 
46 #ifndef CONFIG_DHCP_MIN_EXT_LEN		/* minimal length of extension list	*/
47 #define	CONFIG_DHCP_MIN_EXT_LEN	64
48 #endif
49 
50 ulong		BootpID;
51 int		BootpTry;
52 #ifdef CONFIG_BOOTP_RANDOM_DELAY
53 ulong		seed1, seed2;
54 #endif
55 
56 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
57 dhcp_state_t dhcp_state = INIT;
58 unsigned int dhcp_leasetime = 0;
59 static void DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len);
60 
61 /* For Debug */
62 char *dhcpmsg2str(int type)
63 {
64 	switch (type) {
65 	case 1:  return "DHCPDISCOVER";	break;
66 	case 2:  return "DHCPOFFER";	break;
67 	case 3:  return "DHCPREQUEST";	break;
68 	case 4:  return "DHCPDECLINE";	break;
69 	case 5:  return "DHCPACK";	break;
70 	case 6:  return "DHCPNACK";	break;
71 	case 7:  return "DHCPRELEASE";	break;
72 	default: return "UNKNOWN/INVALID MSG TYPE"; break;
73 	}
74 }
75 
76 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
77 extern u8 *dhcp_vendorex_prep (u8 *e); /*rtn new e after add own opts. */
78 extern u8 *dhcp_vendorex_proc (u8 *e); /*rtn next e if mine,else NULL  */
79 #endif
80 
81 #endif	/* CFG_CMD_DHCP */
82 
83 static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
84 {
85 	Bootp_t *bp = (Bootp_t *) pkt;
86 	int retval = 0;
87 
88 	if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
89 		retval = -1;
90 	else if (len < sizeof (Bootp_t) - OPT_SIZE)
91 		retval = -2;
92 	else if (bp->bp_op != OP_BOOTREQUEST &&
93 	    bp->bp_op != OP_BOOTREPLY &&
94 	    bp->bp_op != DHCP_OFFER &&
95 	    bp->bp_op != DHCP_ACK &&
96 	    bp->bp_op != DHCP_NAK ) {
97 		retval = -3;
98 	}
99 	else if (bp->bp_htype != HWT_ETHER)
100 		retval = -4;
101 	else if (bp->bp_hlen != HWL_ETHER)
102 		retval = -5;
103 	else if (NetReadLong((ulong*)&bp->bp_id) != BootpID) {
104 		retval = -6;
105 	}
106 
107 	debug ("Filtering pkt = %d\n", retval);
108 
109 	return retval;
110 }
111 
112 /*
113  * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
114  */
115 void BootpCopyNetParams(Bootp_t *bp)
116 {
117 	NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
118 	NetCopyIP(&NetServerIP, &bp->bp_siaddr);
119 	memcpy (NetServerEther, ((Ethernet_t *)NetRxPkt)->et_src, 6);
120 	copy_filename (BootFile, bp->bp_file, sizeof(BootFile));
121 
122 	debug ("Bootfile: %s\n", BootFile);
123 
124 	/* Propagate to environment:
125          * don't delete exising entry when BOOTP / DHCP reply does
126 	 * not contain a new value
127 	 */
128 	if (*BootFile) {
129 		setenv ("bootfile", BootFile);
130 	}
131 }
132 
133 static int truncate_sz (const char *name, int maxlen, int curlen)
134 {
135 	if (curlen >= maxlen) {
136 		printf("*** WARNING: %s is too long (%d - max: %d) - truncated\n",
137 			name, curlen, maxlen);
138 		curlen = maxlen - 1;
139 	}
140 	return (curlen);
141 }
142 
143 #if !(CONFIG_COMMANDS & CFG_CMD_DHCP)
144 
145 static void BootpVendorFieldProcess(u8 *ext)
146 {
147     int size = *(ext+1) ;
148 
149     debug_ext ("[BOOTP] Processing extension %d... (%d bytes)\n", *ext, *(ext+1));
150 
151     NetBootFileSize = 0;
152 
153     switch (*ext) {
154     /* Fixed length fields */
155 	case 1:		/* Subnet mask					*/
156 		if (NetOurSubnetMask == 0)
157 			NetCopyIP(&NetOurSubnetMask, (IPaddr_t*)(ext+2));
158 		break;
159 	case 2:		/* Time offset - Not yet supported		*/
160 		break;
161     /* Variable length fields */
162 	case 3:		/* Gateways list				*/
163 		if (NetOurGatewayIP == 0) {
164 			NetCopyIP(&NetOurGatewayIP, (IPaddr_t*)(ext+2));
165 		}
166 		break;
167 	case 4:		/* Time server - Not yet supported		*/
168 		break;
169 	case 5:		/* IEN-116 name server - Not yet supported	*/
170 		break;
171 	case 6:
172 		if (NetOurDNSIP == 0) {
173 			NetCopyIP(&NetOurDNSIP, (IPaddr_t*)(ext+2));
174 		}
175 		break;
176 	case 7:		/* Log server - Not yet supported		*/
177 		break;
178 	case 8:		/* Cookie/Quote server - Not yet supported	*/
179 		break;
180 	case 9:		/* LPR server - Not yet supported		*/
181 		break;
182 	case 10:	/* Impress server - Not yet supported		*/
183 		break;
184 	case 11:	/* RPL server - Not yet supported		*/
185 		break;
186 	case 12:	/* Host name					*/
187 		if (NetOurHostName[0] == 0) {
188 		    size = truncate_sz("Host Name", sizeof(NetOurHostName), size);
189 		    memcpy(&NetOurHostName, ext+2, size);
190 		    NetOurHostName[size] = 0 ;
191 		}
192 		break;
193 	case 13:	/* Boot file size				*/
194 		if (size == 2)
195 			NetBootFileSize = ntohs(*(ushort*)(ext+2));
196 		else if (size == 4)
197 			NetBootFileSize = ntohl(*(ulong*)(ext+2));
198 		break;
199 	case 14:	/* Merit dump file - Not yet supported		*/
200 		break;
201 	case 15:	/* Domain name - Not yet supported		*/
202 		break;
203 	case 16:	/* Swap server - Not yet supported		*/
204 		break;
205 	case 17:	/* Root path					*/
206 		if (NetOurRootPath[0] == 0) {
207 		    size = truncate_sz("Root Path", sizeof(NetOurRootPath), size);
208 		    memcpy(&NetOurRootPath, ext+2, size);
209 		    NetOurRootPath[size] = 0 ;
210 		}
211 		break;
212 	case 18:	/* Extension path - Not yet supported		*/
213 		/*
214                  * This can be used to send the informations of the
215                  * vendor area in another file that the client can
216                  * access via TFTP.
217 		 */
218 		break;
219     /* IP host layer fields */
220 	case 40:	/* NIS Domain name				*/
221 		if (NetOurNISDomain[0] == 0) {
222 		    size = truncate_sz ("NIS Domain Name",
223 		    			sizeof(NetOurNISDomain),
224 					size);
225 		    memcpy(&NetOurNISDomain, ext+2, size);
226 		    NetOurNISDomain[size] = 0 ;
227 		}
228 		break;
229     /* Application layer fields */
230 	case 43:	/* Vendor specific info - Not yet supported	*/
231 		/*
232                  * Binary informations to exchange specific
233                  * product information.
234 		 */
235 		break;
236     /* Reserved (custom) fields (128..254) */
237     }
238 }
239 
240 static void BootpVendorProcess(u8 *ext, int size)
241 {
242     u8 *end = ext + size ;
243 
244     debug_ext ("[BOOTP] Checking extension (%d bytes)...\n", size);
245 
246     while ((ext < end) && (*ext != 0xff)) {
247 	if (*ext == 0) {
248 	    ext ++ ;
249 	} else {
250 		u8 *opt = ext ;
251 		ext += ext[1] + 2 ;
252 		if (ext <= end)
253 		    BootpVendorFieldProcess (opt) ;
254 	}
255     }
256 
257 #ifdef DEBUG_BOOTP_EXT
258     printf("[BOOTP] Received fields: \n");
259     if (NetOurSubnetMask) {
260 	puts ("NetOurSubnetMask	: ");
261 	print_IPaddr (NetOurSubnetMask);
262 	putc('\n');
263     }
264 
265     if (NetOurGatewayIP) {
266 	puts ("NetOurGatewayIP	: ");
267 	print_IPaddr (NetOurGatewayIP);
268 	putc('\n');
269     }
270 
271     if (NetBootFileSize) {
272 	printf("NetBootFileSize : %d\n", NetBootFileSize);
273     }
274 
275     if (NetOurHostName[0]) {
276 	printf("NetOurHostName  : %s\n", NetOurHostName);
277     }
278 
279     if (NetOurRootPath[0]) {
280 	printf("NetOurRootPath  : %s\n", NetOurRootPath);
281     }
282 
283     if (NetOurNISDomain[0]) {
284         printf("NetOurNISDomain : %s\n", NetOurNISDomain);
285     }
286 
287     if (NetBootFileSize) {
288 	printf("NetBootFileSize: %d\n", NetBootFileSize);
289     }
290 #endif	/* DEBUG_BOOTP_EXT */
291 }
292 
293 /*
294  *	Handle a BOOTP received packet.
295  */
296 static void
297 BootpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
298 {
299 	Bootp_t *bp;
300 	char	*s;
301 
302 	debug ("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%d)\n",
303 		src, dest, len, sizeof (Bootp_t));
304 
305 	bp = (Bootp_t *)pkt;
306 
307 	if (BootpCheckPkt(pkt, dest, src, len))	/* Filter out pkts we don't want */
308 		return;
309 
310 	/*
311 	 *	Got a good BOOTP reply.  Copy the data into our variables.
312 	 */
313 #ifdef CONFIG_STATUS_LED
314 	status_led_set (STATUS_LED_BOOT, STATUS_LED_OFF);
315 #endif
316 
317 	BootpCopyNetParams(bp);		/* Store net parameters from reply */
318 
319 	/* Retrieve extended information (we must parse the vendor area) */
320 	if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
321 		BootpVendorProcess(&bp->bp_vend[4], len);
322 
323 	NetSetTimeout(0, (thand_f *)0);
324 
325 	debug ("Got good BOOTP\n");
326 
327 	if (((s = getenv("autoload")) != NULL) && (*s == 'n')) {
328 		/*
329 		 * Just use BOOTP to configure system;
330 		 * Do not use TFTP to load the bootfile.
331 		 */
332 		NetState = NETLOOP_SUCCESS;
333 		return;
334 	}
335 
336 	/* Send ARP request to get TFTP server ethernet address.
337 	 * This automagically starts TFTP, too.
338 	 */
339 	ArpRequest();
340 }
341 #endif	/* !CFG_CMD_DHCP */
342 
343 /*
344  *	Timeout on BOOTP/DHCP request.
345  */
346 static void
347 BootpTimeout(void)
348 {
349 	if (BootpTry >= TIMEOUT_COUNT) {
350 		puts ("\nRetry count exceeded; starting again\n");
351 		NetStartAgain ();
352 	} else {
353 		NetSetTimeout (TIMEOUT * CFG_HZ, BootpTimeout);
354 		BootpRequest ();
355 	}
356 }
357 
358 /*
359  *	Initialize BOOTP extension fields in the request.
360  */
361 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
362 static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)
363 {
364     u8 *start = e ;
365     u8 *cnt;
366 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
367     u8 *x;
368 #endif
369 
370     *e++ =  99;		/* RFC1048 Magic Cookie */
371     *e++ = 130;
372     *e++ =  83;
373     *e++ =  99;
374 
375     *e++ = 53;		/* DHCP Message Type */
376     *e++ = 1;
377     *e++ = message_type;
378 
379     *e++ = 57;		/* Maximum DHCP Message Size */
380     *e++ = 2;
381     *e++ = (576-312+OPT_SIZE) >> 8;
382     *e++ = (576-312+OPT_SIZE) & 0xff;
383 
384     if ( ServerID ) {
385     	    int tmp = ntohl(ServerID);
386 
387 	    *e++ = 54;	/* ServerID */
388 	    *e++ = 4;
389 	    *e++ = tmp >> 24;
390 	    *e++ = tmp >> 16;
391 	    *e++ = tmp >> 8;
392 	    *e++ = tmp & 0xff;
393     }
394 
395     if ( RequestedIP ) {
396     	    int tmp = ntohl(RequestedIP);
397 
398 	    *e++ = 50;	/* Requested IP */
399 	    *e++ = 4;
400 	    *e++ = tmp >> 24;
401 	    *e++ = tmp >> 16;
402 	    *e++ = tmp >> 8;
403 	    *e++ = tmp & 0xff;
404     }
405 
406 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
407     if ((x = dhcp_vendorex_prep (e)))
408     	return x - start ;
409 #endif
410 
411     *e++ = 55;		/* Parameter Request List */
412     cnt  = e++;		/* Pointer to count of requested items */
413     *cnt = 0;
414 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
415     *e++ = 1;		/* Subnet Mask */
416     *cnt += 1;
417 #endif
418 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
419     *e++ = 3;		/* Router Option */
420     *cnt += 1;
421 #endif
422 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
423     *e++ = 6;		/* DNS Server(s) */
424     *cnt += 1;
425 #endif
426 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
427     *e++ = 12;		/* Hostname */
428     *cnt += 1;
429 #endif
430 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
431     *e++ = 13;		/* Boot File Size */
432     *cnt += 1;
433 #endif
434 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
435     *e++ = 17;		/* Boot path */
436     *cnt += 1;
437 #endif
438 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
439     *e++ = 40;		/* NIS Domain name request */
440     *cnt += 1;
441 #endif
442     *e++ = 255;		/* End of the list */
443 
444     /* Pad to minimal length */
445 #ifdef	CONFIG_DHCP_MIN_EXT_LEN
446     while ((e - start) <= CONFIG_DHCP_MIN_EXT_LEN)
447 	*e++ = 0;
448 #endif
449 
450     return e - start ;
451 }
452 
453 #else	/* CFG_CMD_DHCP */
454 /*
455  *	Warning: no field size check - change CONFIG_BOOTP_MASK at your own risk!
456  */
457 static int BootpExtended (u8 *e)
458 {
459     u8 *start = e ;
460 
461     *e++ =  99;		/* RFC1048 Magic Cookie */
462     *e++ = 130;
463     *e++ =  83;
464     *e++ =  99;
465 
466 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
467     *e++ = 53;		/* DHCP Message Type */
468     *e++ = 1;
469     *e++ = DHCP_DISCOVER;
470 
471     *e++ = 57;		/* Maximum DHCP Message Size */
472     *e++ = 2;
473     *e++ = (576-312+OPT_SIZE) >> 16;
474     *e++ = (576-312+OPT_SIZE) & 0xff;
475 #endif	/* CFG_CMD_DHCP */
476 
477 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
478     *e++ =  1;		/* Subnet mask request */
479     *e++ =  4;
480      e  +=  4;
481 #endif
482 
483 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
484     *e++ =  3;		/* Default gateway request */
485     *e++ =  4;
486      e  +=  4;
487 #endif
488 
489 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
490     *e++ =  6;		/* Domain Name Server */
491     *e++ =  4;
492      e  +=  4;
493 #endif
494 
495 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
496     *e++ = 12;		/* Host name request */
497     *e++ = 32;
498      e  += 32;
499 #endif
500 
501 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
502     *e++ = 13;		/* Boot file size */
503     *e++ =  2;
504      e  +=  2;
505 #endif
506 
507 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
508     *e++ = 17;		/* Boot path */
509     *e++ = 32;
510      e  += 32;
511 #endif
512 
513 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
514     *e++ = 40;		/* NIS Domain name request */
515     *e++ = 32;
516      e  += 32;
517 #endif
518 
519     *e++ = 255;		/* End of the list */
520 
521     return e - start ;
522 }
523 #endif	/* CFG_CMD_DHCP */
524 
525 void
526 BootpRequest (void)
527 {
528 	volatile uchar *pkt, *iphdr;
529 	Bootp_t *bp;
530 	int ext_len, pktlen, iplen;
531 
532 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
533 	dhcp_state = INIT;
534 #endif
535 
536 #ifdef CONFIG_BOOTP_RANDOM_DELAY		/* Random BOOTP delay */
537 	unsigned char bi_enetaddr[6];
538 	int   reg;
539 	char  *e,*s;
540 	uchar tmp[64];
541 	ulong tst1, tst2, sum, m_mask, m_value = 0;
542 
543 	if (BootpTry ==0) {
544 		/* get our mac */
545 		reg = getenv_r ("ethaddr", tmp, sizeof(tmp));
546 		s = (reg > 0) ? tmp : NULL;
547 
548 		for (reg=0; reg<6; ++reg) {
549 			bi_enetaddr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
550 			if (s) {
551 				s = (*e) ? e+1 : e;
552 			}
553 		}
554 #ifdef DEBUG
555 		printf("BootpRequest => Our Mac: ");
556 		for (reg=0; reg<6; reg++) {
557 			printf ("%x%c",
558 				bi_enetaddr[reg],
559 				reg==5 ? '\n' : ':');
560 		}
561 #endif /* DEBUG */
562 
563 		/* Mac-Manipulation 2 get seed1 */
564 		tst1=0;
565 		tst2=0;
566 		for (reg=2; reg<6; reg++) {
567 			tst1 = tst1 << 8;
568 			tst1 = tst1 | bi_enetaddr[reg];
569 		}
570 		for (reg=0; reg<2; reg++) {
571 			tst2 = tst2 | bi_enetaddr[reg];
572 			tst2 = tst2 << 8;
573 		}
574 
575 		seed1 = tst1^tst2;
576 
577 		/* Mirror seed1*/
578 		m_mask=0x1;
579 		for (reg=1;reg<=32;reg++) {
580 			m_value |= (m_mask & seed1);
581 			seed1 = seed1 >> 1;
582 			m_value = m_value << 1;
583 		}
584 		seed1 = m_value;
585 		seed2 = 0xB78D0945;
586 	}
587 
588 	/* Random Number Generator */
589 
590 	for (reg=0;reg<=0;reg++) {
591 		sum = seed1 + seed2;
592 		if (sum < seed1 || sum < seed2)
593 			sum++;
594 	        seed2 = seed1;
595 		seed1 = sum;
596 
597 		if (BootpTry<=2) {	/* Start with max 1024 * 1ms */
598 			sum = sum >> (22-BootpTry);
599 		} else {		/*After 3rd BOOTP request max 8192 * 1ms */
600 			sum = sum >> 19;
601 		}
602 	}
603 
604 	printf ("Random delay: %ld ms...\n", sum);
605 	for (reg=0; reg <sum; reg++) {
606 		udelay(1000); /*Wait 1ms*/
607 	}
608 #endif	/* CONFIG_BOOTP_RANDOM_DELAY */
609 
610 	printf("BOOTP broadcast %d\n", ++BootpTry);
611 	pkt = NetTxPacket;
612 	memset ((void*)pkt, 0, PKTSIZE);
613 
614 	NetSetEther(pkt, NetBcastAddr, PROT_IP);
615 	pkt += ETHER_HDR_SIZE;
616 
617 	/*
618 	 * Next line results in incorrect packet size being transmitted, resulting
619 	 * in errors in some DHCP servers, reporting missing bytes.  Size must be
620 	 * set in packet header after extension length has been determined.
621 	 * C. Hallinan, DS4.COM, Inc.
622 	 */
623 	/* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (Bootp_t)); */
624 	iphdr = pkt;	/* We need this later for NetSetIP() */
625 	pkt += IP_HDR_SIZE;
626 
627 	bp = (Bootp_t *)pkt;
628 	bp->bp_op = OP_BOOTREQUEST;
629 	bp->bp_htype = HWT_ETHER;
630 	bp->bp_hlen = HWL_ETHER;
631 	bp->bp_hops = 0;
632 	bp->bp_secs = htons(get_timer(0) / CFG_HZ);
633 	NetWriteIP(&bp->bp_ciaddr, 0);
634 	NetWriteIP(&bp->bp_yiaddr, 0);
635 	NetWriteIP(&bp->bp_siaddr, 0);
636 	NetWriteIP(&bp->bp_giaddr, 0);
637 	memcpy (bp->bp_chaddr, NetOurEther, 6);
638 	copy_filename (bp->bp_file, BootFile, sizeof(bp->bp_file));
639 
640 	/* Request additional information from the BOOTP/DHCP server */
641 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
642 	ext_len = DhcpExtended(bp->bp_vend, DHCP_DISCOVER, 0, 0);
643 #else
644 	ext_len = BootpExtended(bp->bp_vend);
645 #endif	/* CFG_CMD_DHCP */
646 
647 	/*
648 	 *	Bootp ID is the lower 4 bytes of our ethernet address
649 	 *	plus the current time in HZ.
650 	 */
651 	BootpID = ((ulong)NetOurEther[2] << 24)
652 		| ((ulong)NetOurEther[3] << 16)
653 		| ((ulong)NetOurEther[4] << 8)
654 		| (ulong)NetOurEther[5];
655 	BootpID += get_timer(0);
656 	BootpID  = htonl(BootpID);
657 	NetCopyLong(&bp->bp_id, &BootpID);
658 
659 	/*
660 	 * Calculate proper packet lengths taking into account the
661 	 * variable size of the options field
662 	 */
663 	pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + ext_len;
664 	iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
665 	NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
666 	NetSetTimeout(SELECT_TIMEOUT * CFG_HZ, BootpTimeout);
667 
668 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
669 	dhcp_state = SELECTING;
670 	NetSetHandler(DhcpHandler);
671 #else
672 	NetSetHandler(BootpHandler);
673 #endif	/* CFG_CMD_DHCP */
674 	NetSendPacket(NetTxPacket, pktlen);
675 }
676 
677 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
678 void DhcpOptionsProcess(char *popt)
679 {
680 	char *end = popt + BOOTP_HDR_SIZE;
681 	int oplen, size;
682 
683 	while ( popt < end && *popt != 0xff ) {
684 		oplen = *(popt + 1);
685 		switch(*popt) {
686 			case  1:
687 				NetCopyIP(&NetOurSubnetMask, (popt+2));
688 				break;
689 			case  3:
690 				NetCopyIP(&NetOurGatewayIP, (popt+2));
691 				break;
692 			case  6:
693 				NetCopyIP(&NetOurDNSIP, (popt+2));
694 				break;
695 			case 12:
696 				size = truncate_sz ("Host Name",
697 						    sizeof(NetOurHostName),
698 						    oplen);
699 				memcpy(&NetOurHostName, popt+2, size);
700 				NetOurHostName[size] = 0 ;
701 				break;
702 			case 15:		/* Ignore Domain Name Option */
703 				break;
704 			case 17:
705 				size = truncate_sz ("Root Path",
706 						    sizeof(NetOurRootPath),
707 						    oplen);
708 				memcpy(&NetOurRootPath, popt+2, size);
709 				NetOurRootPath[size] = 0 ;
710 				break;
711 			case 51:
712 				dhcp_leasetime = *(unsigned int *)(popt + 2);
713 				break;
714 			case 53:		/* Ignore Message Type Option */
715 				break;
716 			case 54:
717 				NetCopyIP(&NetServerIP, (popt+2));
718 				break;
719 			case 58:		/* Ignore Renewal Time Option */
720 				break;
721 			case 59:		/* Ignore Rebinding Time Option */
722 				break;
723 			default:
724 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
725 			    if (dhcp_vendorex_proc(popt))
726         			break;
727 #endif
728 				printf("*** Unhandled DHCP Option in OFFER/ACK: %d\n",
729 					*popt);
730 				break;
731 		}
732 		popt += oplen + 2;	/* Process next option */
733 	}
734 }
735 
736 static int DhcpMessageType(unsigned char *popt)
737 {
738 	if (NetReadLong((ulong*)popt) != htonl(BOOTP_VENDOR_MAGIC))
739 		return -1;
740 
741 	popt += 4;
742 	while ( *popt != 0xff ) {
743 		if ( *popt == 53 )	/* DHCP Message Type */
744 			return *(popt + 2);
745 		popt += *(popt + 1) + 2;	/* Scan through all options */
746 	}
747 	return -1;
748 }
749 
750 void DhcpSendRequestPkt(Bootp_t *bp_offer)
751 {
752 	volatile uchar *pkt, *iphdr;
753 	Bootp_t *bp;
754 	int pktlen, iplen, extlen;
755 
756 	debug ("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
757 	pkt = NetTxPacket;
758 	memset ((void*)pkt, 0, PKTSIZE);
759 
760 	NetSetEther(pkt, NetBcastAddr, PROT_IP);
761 	pkt += ETHER_HDR_SIZE;
762 
763 	iphdr = pkt;		/* We'll need this later to set proper pkt size */
764 	pkt += IP_HDR_SIZE;
765 
766 	bp = (Bootp_t *)pkt;
767 	bp->bp_op = OP_BOOTREQUEST;
768 	bp->bp_htype = HWT_ETHER;
769 	bp->bp_hlen = HWL_ETHER;
770 	bp->bp_hops = 0;
771 	bp->bp_secs = htons(get_timer(0) / CFG_HZ);
772 	NetCopyIP(&bp->bp_ciaddr, &bp_offer->bp_ciaddr); /* both in network byte order */
773 	NetCopyIP(&bp->bp_yiaddr, &bp_offer->bp_yiaddr);
774 	NetCopyIP(&bp->bp_siaddr, &bp_offer->bp_siaddr);
775 	NetCopyIP(&bp->bp_giaddr, &bp_offer->bp_giaddr);
776 	memcpy (bp->bp_chaddr, NetOurEther, 6);
777 
778 	/*
779 	 * ID is the id of the OFFER packet
780 	 */
781 
782 	NetCopyLong(&bp->bp_id, &bp_offer->bp_id);
783 
784 	/*
785 	 * Copy options from OFFER packet if present
786 	 */
787 	extlen = DhcpExtended(bp->bp_vend, DHCP_REQUEST, NetServerIP, bp->bp_yiaddr);
788 
789 	pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + extlen;
790 	iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
791 	NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
792 
793 	debug ("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
794 	NetSendPacket(NetTxPacket, pktlen);
795 }
796 
797 /*
798  *	Handle DHCP received packets.
799  */
800 static void
801 DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
802 {
803 	Bootp_t *bp = (Bootp_t *)pkt;
804 
805 	debug ("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
806 		src, dest, len, dhcp_state);
807 
808 	if (BootpCheckPkt(pkt, dest, src, len))	/* Filter out pkts we don't want */
809 		return;
810 
811 	debug ("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n",
812 		src, dest, len, dhcp_state);
813 
814 	switch (dhcp_state) {
815 	case SELECTING:
816 		/*
817 		 * Wait an appropriate time for any potential DHCPOFFER packets
818 		 * to arrive.  Then select one, and generate DHCPREQUEST response.
819 		 * If filename is in format we recognize, assume it is a valid
820 		 * OFFER from a server we want.
821 		 */
822 		debug ("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
823 #ifdef CFG_BOOTFILE_PREFIX
824 		if (strncmp(bp->bp_file,
825 			    CFG_BOOTFILE_PREFIX,
826 			    strlen(CFG_BOOTFILE_PREFIX)) == 0 ) {
827 #endif	/* CFG_BOOTFILE_PREFIX */
828 
829 			debug ("TRANSITIONING TO REQUESTING STATE\n");
830 			dhcp_state = REQUESTING;
831 #if 0
832 			if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
833 				DhcpOptionsProcess(&bp->bp_vend[4]);
834 
835 #endif
836 			BootpCopyNetParams(bp);	/* Store net params from reply */
837 
838 			NetSetTimeout(TIMEOUT * CFG_HZ, BootpTimeout);
839 			DhcpSendRequestPkt(bp);
840 #ifdef CFG_BOOTFILE_PREFIX
841 		}
842 #endif	/* CFG_BOOTFILE_PREFIX */
843 
844 		return;
845 		break;
846 	case REQUESTING:
847 		debug ("DHCP State: REQUESTING\n");
848 
849 		if ( DhcpMessageType(bp->bp_vend) == DHCP_ACK ) {
850 			char *s;
851 
852 			if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
853 				DhcpOptionsProcess(&bp->bp_vend[4]);
854 			BootpCopyNetParams(bp);	/* Store net params from reply */
855 			dhcp_state = BOUND;
856 			printf("DHCP client bound to address ");
857 			print_IPaddr(NetOurIP);
858 			printf("\n");
859 
860 			/* Obey the 'autoload' setting */
861 			if (((s = getenv("autoload")) != NULL) && (*s == 'n')) {
862 				NetState = NETLOOP_SUCCESS;
863 				return;
864 			}
865 			/* Send ARP request to get TFTP server ethernet address.
866 			 * This automagically starts TFTP, too.
867 			 */
868 			ArpRequest();
869 			return;
870 		}
871 		break;
872 	default:
873 		printf("DHCP: INVALID STATE\n");
874 		break;
875 	}
876 
877 }
878 
879 void DhcpRequest(void)
880 {
881 	BootpRequest();
882 }
883 #endif	/* CFG_CMD_DHCP */
884 
885 #endif /* CFG_CMD_NET */
886