xref: /freebsd/sys/nfs/bootp_subr.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /* $FreeBSD$	*/
2 
3 /*
4  * Copyright (c) 1995 Gordon Ross, Adam Glass
5  * Copyright (c) 1992 Regents of the University of California.
6  * All rights reserved.
7  *
8  * This software was developed by the Computer Systems Engineering group
9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10  * contributed to Berkeley.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Lawrence Berkeley Laboratory and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  * based on:
41  *      nfs/krpc_subr.c
42  *	$NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
43  */
44 
45 #include "opt_bootp.h"
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/sockio.h>
51 #include <sys/malloc.h>
52 #include <sys/mount.h>
53 #include <sys/mbuf.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <sys/uio.h>
57 
58 #include <net/if.h>
59 #include <net/route.h>
60 
61 #include <netinet/in.h>
62 #include <net/if_types.h>
63 #include <net/if_dl.h>
64 
65 #include <nfs/rpcv2.h>
66 #include <nfs/nfsproto.h>
67 #include <nfs/nfs.h>
68 #include <nfs/nfsdiskless.h>
69 #include <nfs/krpc.h>
70 #include <nfs/xdr_subs.h>
71 
72 
73 #define BOOTP_MIN_LEN		300	/* Minimum size of bootp udp packet */
74 
75 #ifndef BOOTP_SETTLE_DELAY
76 #define BOOTP_SETTLE_DELAY 3
77 #endif
78 
79 /*
80  * What is the longest we will wait before re-sending a request?
81  * Note this is also the frequency of "RPC timeout" messages.
82  * The re-send loop count sup linearly to this maximum, so the
83  * first complaint will happen after (1+2+3+4+5)=15 seconds.
84  */
85 #define	MAX_RESEND_DELAY 5	/* seconds */
86 
87 /* Definitions from RFC951 */
88 struct bootp_packet {
89 	u_int8_t op;
90 	u_int8_t htype;
91 	u_int8_t hlen;
92 	u_int8_t hops;
93 	u_int32_t xid;
94 	u_int16_t secs;
95 	u_int16_t flags;
96 	struct in_addr ciaddr;
97 	struct in_addr yiaddr;
98 	struct in_addr siaddr;
99 	struct in_addr giaddr;
100 	unsigned char chaddr[16];
101 	char sname[64];
102 	char file[128];
103 	unsigned char vend[256];
104 };
105 
106 struct bootpc_ifcontext {
107 	struct bootpc_ifcontext *next;
108 	struct bootp_packet call;
109 	struct bootp_packet reply;
110 	int replylen;
111 	int overload;
112 	struct socket *so;
113 	struct ifreq ireq;
114 	struct ifnet *ifp;
115 	struct sockaddr_dl *sdl;
116 	struct sockaddr_in myaddr;
117 	struct sockaddr_in netmask;
118 	struct sockaddr_in gw;
119 	struct sockaddr_in broadcast;	/* Different for each interface */
120 	int gotgw;
121 	int gotnetmask;
122 	int gotrootpath;
123 	int outstanding;
124 	int sentmsg;
125 	u_int32_t xid;
126 	enum {
127 		IF_BOOTP_UNRESOLVED,
128 		IF_BOOTP_RESOLVED,
129 		IF_DHCP_OFFERED,
130 		IF_DHCP_RESOLVED,
131 		IF_BOOTP_FAILED
132 	} state;
133 };
134 
135 #define TAG_MAXLEN 1024
136 struct bootpc_tagcontext {
137 	char buf[TAG_MAXLEN + 1];
138 	int overload;
139 	int badopt;
140 	int badtag;
141 	int foundopt;
142 	int taglen;
143 };
144 
145 struct bootpc_globalcontext {
146 	struct bootpc_ifcontext *interfaces;
147 	struct bootpc_ifcontext *lastinterface;
148 	u_int32_t xid;
149 	int gotrootpath;
150 	int gotswappath;
151 	int gotgw;
152 	int ifnum;
153 	int secs;
154 	int starttime;
155 	struct bootp_packet reply;
156 	int replylen;
157 	struct bootpc_ifcontext *setswapfs;
158 	struct bootpc_ifcontext *setrootfs;
159 	struct bootpc_ifcontext *sethostname;
160 	char lookup_path[24];
161 	struct bootpc_tagcontext tmptag;
162 	struct bootpc_tagcontext tag;
163 };
164 
165 #define IPPORT_BOOTPC 68
166 #define IPPORT_BOOTPS 67
167 
168 #define BOOTP_REQUEST 1
169 #define BOOTP_REPLY 2
170 
171 /* Common tags */
172 #define TAG_PAD		  0  /* Pad option, implicit length 1 */
173 #define TAG_SUBNETMASK	  1  /* RFC 950 subnet mask */
174 #define TAG_ROUTERS	  3  /* Routers (in order of preference) */
175 #define TAG_HOSTNAME	 12  /* Client host name */
176 #define TAG_ROOT	 17  /* Root path */
177 
178 /* DHCP specific tags */
179 #define TAG_OVERLOAD	 52  /* Option Overload */
180 #define TAG_MAXMSGSIZE   57  /* Maximum DHCP Message Size */
181 
182 #define TAG_END		255  /* End Option (i.e. no more options) */
183 
184 /* Overload values */
185 #define OVERLOAD_FILE     1
186 #define OVERLOAD_SNAME    2
187 
188 /* Site specific tags: */
189 #define TAG_SWAP	128
190 #define TAG_SWAPSIZE	129
191 #define TAG_ROOTOPTS	130
192 #define TAG_SWAPOPTS	131
193 
194 extern int nfs_diskless_valid;
195 extern struct nfsv3_diskless nfsv3_diskless;
196 
197 /* mountd RPC */
198 static int md_mount(struct sockaddr_in *mdsin, char *path,
199 		    u_char *fhp, int *fhsizep,
200 		    struct nfs_args *args,struct proc *procp);
201 static int md_lookup_swap(struct sockaddr_in *mdsin,char *path,
202 			  u_char *fhp, int *fhsizep,
203 			  struct nfs_args *args,
204 			  struct proc *procp);
205 static int setfs(struct sockaddr_in *addr, char *path, char *p);
206 static int getdec(char **ptr);
207 static char *substr(char *a,char *b);
208 static void mountopts(struct nfs_args *args, char *p);
209 static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
210 static int xdr_int_decode(struct mbuf **ptr, int *iptr);
211 static void print_in_addr(struct in_addr addr);
212 static void print_sin_addr(struct sockaddr_in *addr);
213 static void clear_sinaddr(struct sockaddr_in *sin);
214 static
215 struct bootpc_ifcontext *allocifctx(struct bootpc_globalcontext *gctx);
216 static void bootpc_compose_query(struct bootpc_ifcontext *ifctx,
217 				 struct bootpc_globalcontext *gctx,
218 				 struct proc *procp);
219 static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx,
220 				 struct bootp_packet *bp, int len, int tag);
221 static void bootpc_tag_helper(struct bootpc_tagcontext *tctx,
222 			      unsigned char *start, int len, int tag);
223 
224 #ifdef BOOTP_DEBUG
225 void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma);
226 void bootpboot_p_ma(struct sockaddr *ma);
227 void bootpboot_p_rtentry(struct rtentry *rt);
228 void bootpboot_p_tree(struct radix_node *rn);
229 void bootpboot_p_rtlist(void);
230 void bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa);
231 void bootpboot_p_iflist(void);
232 #endif
233 
234 static int  bootpc_call(struct bootpc_globalcontext *gctx,
235 			struct proc *procp);
236 
237 static int bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
238 				   struct bootpc_globalcontext *gctx,
239 				   struct proc *procp);
240 
241 static int bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
242 				   struct bootpc_globalcontext *gctx,
243 				   struct proc *procp);
244 
245 static void bootpc_decode_reply(struct nfsv3_diskless *nd,
246 				struct bootpc_ifcontext *ifctx,
247 				struct bootpc_globalcontext *gctx);
248 
249 static int bootpc_received(struct bootpc_globalcontext *gctx,
250 			   struct bootpc_ifcontext *ifctx);
251 
252 void bootpc_init(void);
253 
254 /*
255  * In order to have multiple active interfaces with address 0.0.0.0
256  * and be able to send data to a selected interface, we perform
257  * some tricks:
258  *
259  *  - The 'broadcast' address is different for each interface.
260  *
261  *  - We temporarily add routing pointing 255.255.255.255 to the
262  *    selected interface broadcast address, thus the packet sent
263  *    goes to that interface.
264  */
265 
266 #ifdef BOOTP_DEBUG
267 void
268 bootpboot_p_sa(struct sockaddr *sa,
269 	       struct sockaddr *ma)
270 {
271 	if (sa == NULL) {
272 		printf("(sockaddr *) <null>");
273 		return;
274 	}
275 	switch (sa->sa_family) {
276 	case AF_INET:
277 	{
278 		struct sockaddr_in *sin;
279 
280 		sin = (struct sockaddr_in *) sa;
281 		printf("inet ");
282 		print_sin_addr(sin);
283 		if (ma != NULL) {
284 			sin = (struct sockaddr_in *) ma;
285 			printf(" mask ");
286 			print_sin_addr(sin);
287 		}
288 	}
289 	break;
290 	case AF_LINK:
291 	{
292 		struct sockaddr_dl *sli;
293 		int i;
294 
295 		sli = (struct sockaddr_dl *) sa;
296 		printf("link %.*s ", sli->sdl_nlen, sli->sdl_data);
297 		for (i = 0; i < sli->sdl_alen; i++) {
298 			if (i > 0)
299 				printf(":");
300 			printf("%x", ((unsigned char *) LLADDR(sli))[i]);
301 		}
302 	}
303 	break;
304 	default:
305 		printf("af%d", sa->sa_family);
306 	}
307 }
308 
309 
310 void
311 bootpboot_p_ma(struct sockaddr *ma)
312 {
313 	if (ma == NULL) {
314 		printf("<null>");
315 		return;
316 	}
317 	printf("%x", *(int *)ma);
318 }
319 
320 
321 void
322 bootpboot_p_rtentry(struct rtentry *rt)
323 {
324 	bootpboot_p_sa(rt_key(rt), rt_mask(rt));
325 	printf(" ");
326 	bootpboot_p_ma(rt->rt_genmask);
327 	printf(" ");
328 	bootpboot_p_sa(rt->rt_gateway, NULL);
329 	printf(" ");
330 	printf("flags %x", (unsigned short) rt->rt_flags);
331 	printf(" %d", (int) rt->rt_rmx.rmx_expire);
332 	printf(" %s%d\n", rt->rt_ifp->if_name, rt->rt_ifp->if_unit);
333 }
334 
335 
336 void
337 bootpboot_p_tree(struct radix_node *rn)
338 {
339 	while (rn != NULL) {
340 		if (rn->rn_bit < 0) {
341 			if ((rn->rn_flags & RNF_ROOT) != 0) {
342 			} else {
343 				bootpboot_p_rtentry((struct rtentry *) rn);
344 			}
345 			rn = rn->rn_dupedkey;
346 		} else {
347 			bootpboot_p_tree(rn->rn_left);
348 			bootpboot_p_tree(rn->rn_right);
349 			return;
350 		}
351 	}
352 }
353 
354 
355 void
356 bootpboot_p_rtlist(void)
357 {
358 	printf("Routing table:\n");
359 	bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop);
360 }
361 
362 
363 void
364 bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa)
365 {
366 	printf("%s%d flags %x, addr ",
367 	       ifp->if_name,
368 	       ifp->if_unit,
369 	       (unsigned short) ifp->if_flags);
370 	print_sin_addr((struct sockaddr_in *) ifa->ifa_addr);
371 	printf(", broadcast ");
372 	print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr);
373 	printf(", netmask ");
374 	print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask);
375 	printf("\n");
376 }
377 
378 
379 void
380 bootpboot_p_iflist(void)
381 {
382 	struct ifnet *ifp;
383 	struct ifaddr *ifa;
384 
385 	printf("Interface list:\n");
386 	for (ifp = TAILQ_FIRST(&ifnet);
387 	     ifp != NULL;
388 	     ifp = TAILQ_NEXT(ifp, if_link)) {
389 		for (ifa = TAILQ_FIRST(&ifp->if_addrhead);
390 		     ifa != NULL;
391 		     ifa = TAILQ_NEXT(ifa, ifa_link))
392 			if (ifa->ifa_addr->sa_family == AF_INET)
393 				bootpboot_p_if(ifp, ifa);
394 	}
395 }
396 #endif /* defined(BOOTP_DEBUG) */
397 
398 
399 static void
400 clear_sinaddr(struct sockaddr_in *sin)
401 {
402 	bzero(sin, sizeof(*sin));
403 	sin->sin_len = sizeof(*sin);
404 	sin->sin_family = AF_INET;
405 	sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */
406 	sin->sin_port = 0;
407 }
408 
409 
410 static struct bootpc_ifcontext *
411 allocifctx(struct bootpc_globalcontext *gctx)
412 {
413 	struct bootpc_ifcontext *ifctx;
414 	ifctx = (struct bootpc_ifcontext *) malloc(sizeof(*ifctx),
415 						   M_TEMP, M_WAITOK);
416 	if (ifctx == NULL)
417 		panic("Failed to allocate bootp interface context structure");
418 
419 	bzero(ifctx, sizeof(*ifctx));
420 	ifctx->xid = gctx->xid;
421 	gctx->xid += 0x100;
422 	return ifctx;
423 }
424 
425 
426 static int
427 bootpc_received(struct bootpc_globalcontext *gctx,
428 		struct bootpc_ifcontext *ifctx)
429 {
430 	/*
431 	 * Need timeout for fallback to less
432 	 * desirable alternative.
433 	 */
434 
435 
436 	/* This call used for the side effect (badopt flag) */
437 	(void) bootpc_tag(&gctx->tmptag, &gctx->reply,
438 			  gctx->replylen,
439 			  TAG_END);
440 
441 	/* If packet is invalid, ignore it */
442 	if (gctx->tmptag.badopt != 0)
443 		return 0;
444 
445 	/* Ignore packet unless it gives us a root tag we didn't have */
446 
447 	if (ifctx->state == IF_BOOTP_RESOLVED &&
448 	    (bootpc_tag(&gctx->tmptag, &ifctx->reply,
449 			ifctx->replylen,
450 			TAG_ROOT) != NULL ||
451 	     bootpc_tag(&gctx->tmptag, &gctx->reply,
452 			gctx->replylen,
453 			TAG_ROOT) == NULL))
454 		return 0;
455 
456 	bcopy(&gctx->reply,
457 	      &ifctx->reply,
458 	      gctx->replylen);
459 	ifctx->replylen = gctx->replylen;
460 
461 	/* XXX: Only reset if 'perfect' response */
462 	ifctx->state = IF_BOOTP_RESOLVED;
463 	ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
464 					 ifctx->replylen,
465 					 TAG_ROOT) != NULL);
466 	ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
467 				   ifctx->replylen,
468 				   TAG_ROUTERS) != NULL);
469 	ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
470 					ifctx->replylen,
471 					TAG_SUBNETMASK) != NULL);
472 	return 1;
473 }
474 
475 static int
476 bootpc_call(struct bootpc_globalcontext *gctx,
477 	    struct proc *procp)
478 {
479 	struct socket *so;
480 	struct sockaddr_in *sin, dst;
481 	struct uio auio;
482 	struct sockopt sopt;
483 	struct iovec aio;
484 	int error, on, rcvflg, timo, len;
485 	time_t atimo;
486 	time_t rtimo;
487 	struct timeval tv;
488 	struct bootpc_ifcontext *ifctx;
489 	int outstanding;
490 	int gotrootpath;
491 
492 	/*
493 	 * Create socket and set its recieve timeout.
494 	 */
495 	error = socreate(AF_INET, &so, SOCK_DGRAM, 0, procp);
496 	if (error != 0)
497 		goto out;
498 
499 	tv.tv_sec = 1;
500 	tv.tv_usec = 0;
501 	bzero(&sopt, sizeof(sopt));
502 	sopt.sopt_level = SOL_SOCKET;
503 	sopt.sopt_name = SO_RCVTIMEO;
504 	sopt.sopt_val = &tv;
505 	sopt.sopt_valsize = sizeof tv;
506 
507 	error = sosetopt(so, &sopt);
508 	if (error != 0)
509 		goto out;
510 
511 	/*
512 	 * Enable broadcast.
513 	 */
514 	on = 1;
515 	sopt.sopt_name = SO_BROADCAST;
516 	sopt.sopt_val = &on;
517 	sopt.sopt_valsize = sizeof on;
518 
519 	error = sosetopt(so, &sopt);
520 	if (error != 0)
521 		goto out;
522 
523 	/*
524 	 * Disable routing.
525 	 */
526 
527 	on = 1;
528 	sopt.sopt_name = SO_DONTROUTE;
529 	sopt.sopt_val = &on;
530 	sopt.sopt_valsize = sizeof on;
531 
532 	error = sosetopt(so, &sopt);
533 	if (error != 0)
534 		goto out;
535 
536 	/*
537 	 * Bind the local endpoint to a bootp client port.
538 	 */
539 	sin = &dst;
540 	clear_sinaddr(sin);
541 	sin->sin_port = htons(IPPORT_BOOTPC);
542 	error = sobind(so, (struct sockaddr *)sin, procp);
543 	if (error != 0) {
544 		printf("bind failed\n");
545 		goto out;
546 	}
547 
548 	/*
549 	 * Setup socket address for the server.
550 	 */
551 	sin = &dst;
552 	clear_sinaddr(sin);
553 	sin->sin_addr.s_addr = INADDR_BROADCAST;
554 	sin->sin_port = htons(IPPORT_BOOTPS);
555 
556 	/*
557 	 * Send it, repeatedly, until a reply is received,
558 	 * but delay each re-send by an increasing amount.
559 	 * If the delay hits the maximum, start complaining.
560 	 */
561 	timo = 0;
562 	rtimo = 0;
563 	for (;;) {
564 
565 		outstanding = 0;
566 		gotrootpath = 0;
567 
568 		for (ifctx = gctx->interfaces;
569 		     ifctx != NULL;
570 		     ifctx = ifctx->next) {
571 			if (ifctx->state == IF_BOOTP_RESOLVED &&
572 			    bootpc_tag(&gctx->tmptag, &ifctx->reply,
573 				       ifctx->replylen,
574 				       TAG_ROOT) != NULL)
575 				gotrootpath = 1;
576 		}
577 
578 		for (ifctx = gctx->interfaces;
579 		     ifctx != NULL;
580 		     ifctx = ifctx->next) {
581 			ifctx->outstanding = 0;
582 			if (ifctx->state == IF_BOOTP_RESOLVED &&
583 			    gotrootpath != 0) {
584 				continue;
585 			}
586 			if (ifctx->state == IF_BOOTP_FAILED)
587 				continue;
588 
589 			outstanding++;
590 			ifctx->outstanding = 1;
591 
592 			/* Send BOOTP request (or re-send). */
593 
594 			if (ifctx->sentmsg == 0) {
595 				printf("Sending BOOTP Query packet from "
596 				       "interface %s (%*D)\n",
597 				       ifctx->ireq.ifr_name,
598 				       ifctx->sdl->sdl_alen,
599 				       (unsigned char *) LLADDR(ifctx->sdl),
600 				       ":");
601 				ifctx->sentmsg = 1;
602 			}
603 
604 			aio.iov_base = (caddr_t) &ifctx->call;
605 			aio.iov_len = sizeof(ifctx->call);
606 
607 			auio.uio_iov = &aio;
608 			auio.uio_iovcnt = 1;
609 			auio.uio_segflg = UIO_SYSSPACE;
610 			auio.uio_rw = UIO_WRITE;
611 			auio.uio_offset = 0;
612 			auio.uio_resid = sizeof(ifctx->call);
613 			auio.uio_procp = procp;
614 
615 			/* Set netmask to 0.0.0.0 */
616 
617 			sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
618 			clear_sinaddr(sin);
619 			error = ifioctl(ifctx->so, SIOCSIFNETMASK,
620 					(caddr_t) &ifctx->ireq, procp);
621 			if (error != 0)
622 				panic("bootpc_call:"
623 				      "set if netmask, error=%d",
624 				      error);
625 
626 			error = sosend(so, (struct sockaddr *) &dst,
627 				       &auio, NULL, NULL, 0, procp);
628 			if (error != 0) {
629 				printf("bootpc_call: sosend: %d state %08x\n",
630 				       error, (int) so->so_state);
631 			}
632 
633 			/* XXX: Is this needed ? */
634 			tsleep(&error, PZERO + 8, "bootpw", 10);
635 
636 			/* Set netmask to 255.0.0.0 */
637 
638 			sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
639 			clear_sinaddr(sin);
640 			sin->sin_addr.s_addr = htonl(0xff000000u);
641 			error = ifioctl(ifctx->so, SIOCSIFNETMASK,
642 					(caddr_t) &ifctx->ireq, procp);
643 			if (error != 0)
644 				panic("bootpc_call:"
645 				      "set if netmask, error=%d",
646 				      error);
647 
648 		}
649 
650 		if (outstanding == 0 &&
651 		    (rtimo == 0 || time_second >= rtimo)) {
652 			error = 0;
653 			goto gotreply;
654 		}
655 
656 		/* Determine new timeout. */
657 		if (timo < MAX_RESEND_DELAY)
658 			timo++;
659 		else {
660 			printf("BOOTP timeout for server ");
661 			print_sin_addr(&dst);
662 			printf("\n");
663 		}
664 
665 		/*
666 		 * Wait for up to timo seconds for a reply.
667 		 * The socket receive timeout was set to 1 second.
668 		 */
669 		atimo = timo + time_second;
670 		while (time_second < atimo) {
671 			aio.iov_base = (caddr_t) &gctx->reply;
672 			aio.iov_len = sizeof(gctx->reply);
673 
674 			auio.uio_iov = &aio;
675 			auio.uio_iovcnt = 1;
676 			auio.uio_segflg = UIO_SYSSPACE;
677 			auio.uio_rw = UIO_READ;
678 			auio.uio_offset = 0;
679 			auio.uio_resid = sizeof(gctx->reply);
680 			auio.uio_procp = procp;
681 
682 			rcvflg = 0;
683 			error = soreceive(so, NULL, &auio,
684 					  NULL, NULL, &rcvflg);
685 			gctx->secs = time_second - gctx->starttime;
686 			for (ifctx = gctx->interfaces;
687 			     ifctx != NULL;
688 			     ifctx = ifctx->next) {
689 				if (ifctx->state == IF_BOOTP_RESOLVED)
690 					continue;
691 				if (ifctx->state == IF_BOOTP_FAILED)
692 					continue;
693 				ifctx->call.secs = htons(gctx->secs);
694 			}
695 			if (error == EWOULDBLOCK)
696 				continue;
697 			if (error != 0)
698 				goto out;
699 			len = sizeof(gctx->reply) - auio.uio_resid;
700 
701 			/* Do we have the required number of bytes ? */
702 			if (len < BOOTP_MIN_LEN)
703 				continue;
704 			gctx->replylen = len;
705 
706 			/* Is it a reply? */
707 			if (gctx->reply.op != BOOTP_REPLY)
708 				continue;
709 
710 			/* Is this an answer to our query */
711 			for (ifctx = gctx->interfaces;
712 			     ifctx != NULL;
713 			     ifctx = ifctx->next) {
714 				if (gctx->reply.xid != ifctx->call.xid)
715 					continue;
716 
717 				/* Same HW address size ? */
718 				if (gctx->reply.hlen != ifctx->call.hlen)
719 					continue;
720 
721 				/* Correct HW address ? */
722 				if (bcmp(gctx->reply.chaddr,
723 					 ifctx->call.chaddr,
724 					 ifctx->call.hlen) != 0)
725 					continue;
726 
727 				break;
728 			}
729 
730 			if (ifctx != NULL) {
731 				printf("Received BOOTP Reply packet"
732 				       " on %s from ",
733 				       ifctx->ireq.ifr_name);
734 				print_in_addr(gctx->reply.siaddr);
735 				if (gctx->reply.giaddr.s_addr !=
736 				    htonl(INADDR_ANY)) {
737 					printf(" via ");
738 					print_in_addr(gctx->reply.giaddr);
739 				}
740 				if (bootpc_received(gctx, ifctx) != 0) {
741 					printf(" (accepted)");
742 					if (ifctx->outstanding) {
743 						ifctx->outstanding = 0;
744 						outstanding--;
745 					}
746 					/* Network settle delay */
747 					if (outstanding == 0)
748 						atimo = time_second +
749 							BOOTP_SETTLE_DELAY;
750 				} else
751 					printf(" (ignored)");
752 				if (ifctx->gotrootpath) {
753 					gotrootpath = 1;
754 					rtimo = time_second +
755 						BOOTP_SETTLE_DELAY;
756 					printf(" (got root path)");
757 				} else
758 					printf(" (no root path)");
759 				printf("\n");
760 			}
761 		} /* while secs */
762 #ifdef BOOTP_TIMEOUT
763 		if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
764 			break;
765 #endif
766 		if (gotrootpath != 0) {
767 			gctx->gotrootpath = gotrootpath;
768 			if (rtimo != 0 && time_second >= rtimo)
769 				break;
770 		}
771 	} /* forever send/receive */
772 
773 	/*
774 	 * XXX: These are errors of varying seriousness being silently
775 	 * ignored
776 	 */
777 
778 	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
779 		if (ifctx->state != IF_BOOTP_RESOLVED) {
780 			printf("BOOTP timeout for interface %s\n",
781 			       ifctx->ireq.ifr_name);
782 		}
783 	}
784 	if (gctx->gotrootpath != 0) {
785 #if 0
786 		printf("Got a root path, ignoring remaining timeout\n");
787 #endif
788 		error = 0;
789 		goto out;
790 	}
791 #ifndef BOOTP_NFSROOT
792 	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
793 		if (ifctx->state == IF_BOOTP_RESOLVED) {
794 			error = 0;
795 			goto out;
796 		}
797 	}
798 #endif
799 	error = ETIMEDOUT;
800 	goto out;
801 
802 gotreply:
803 out:
804 	soclose(so);
805 	return error;
806 }
807 
808 
809 static int
810 bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
811 			struct bootpc_globalcontext *gctx,
812 			struct proc *procp)
813 {
814 	struct sockaddr_in *sin;
815 	int error;
816 
817 	struct ifreq *ireq;
818 	struct socket *so;
819 	struct ifaddr *ifa;
820 	struct sockaddr_dl *sdl;
821 
822 	error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0, procp);
823 	if (error != 0)
824 		panic("nfs_boot: socreate, error=%d", error);
825 
826 	ireq = &ifctx->ireq;
827 	so = ifctx->so;
828 
829 	/*
830 	 * Bring up the interface.
831 	 *
832 	 * Get the old interface flags and or IFF_UP into them; if
833 	 * IFF_UP set blindly, interface selection can be clobbered.
834 	 */
835 	error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp);
836 	if (error != 0)
837 		panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error);
838 	ireq->ifr_flags |= IFF_UP;
839 	error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp);
840 	if (error != 0)
841 		panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error);
842 
843 	/*
844 	 * Do enough of ifconfig(8) so that the chosen interface
845 	 * can talk to the servers.  (just set the address)
846 	 */
847 
848 	/* addr is 0.0.0.0 */
849 
850 	sin = (struct sockaddr_in *) &ireq->ifr_addr;
851 	clear_sinaddr(sin);
852 	error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, procp);
853 	if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
854 		panic("bootpc_fakeup_interface: "
855 		      "set if addr, error=%d", error);
856 
857 	/* netmask is 255.0.0.0 */
858 
859 	sin = (struct sockaddr_in *) &ireq->ifr_addr;
860 	clear_sinaddr(sin);
861 	sin->sin_addr.s_addr = htonl(0xff000000u);
862 	error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp);
863 	if (error != 0)
864 		panic("bootpc_fakeup_interface: set if netmask, error=%d",
865 		      error);
866 
867 	/* Broadcast is 255.255.255.255 */
868 
869 	sin = (struct sockaddr_in *)&ireq->ifr_addr;
870 	clear_sinaddr(sin);
871 	clear_sinaddr(&ifctx->broadcast);
872 	sin->sin_addr.s_addr = htonl(INADDR_BROADCAST);
873 	ifctx->broadcast.sin_addr.s_addr = sin->sin_addr.s_addr;
874 
875 	error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp);
876 	if (error != 0)
877 		panic("bootpc_fakeup_interface: "
878 		      "set if broadcast addr, error=%d",
879 		      error);
880 
881 	/* Get HW address */
882 
883 	sdl = NULL;
884 	for (ifa = TAILQ_FIRST(&ifctx->ifp->if_addrhead);
885 	     ifa != NULL;
886 	     ifa = TAILQ_NEXT(ifa,ifa_link))
887 		if (ifa->ifa_addr->sa_family == AF_LINK &&
888 		    (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) != NULL &&
889 		    sdl->sdl_type == IFT_ETHER)
890 			break;
891 
892 	if (sdl == NULL)
893 		panic("bootpc: Unable to find HW address for %s",
894 		      ifctx->ireq.ifr_name);
895 	ifctx->sdl = sdl;
896 
897 	return error;
898 }
899 
900 
901 static int
902 bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
903 			struct bootpc_globalcontext *gctx,
904 			struct proc *procp)
905 {
906 	int error;
907 	struct sockaddr_in defdst;
908 	struct sockaddr_in defmask;
909 	struct sockaddr_in *sin;
910 
911 	struct ifreq *ireq;
912 	struct socket *so;
913 	struct sockaddr_in *myaddr;
914 	struct sockaddr_in *netmask;
915 	struct sockaddr_in *gw;
916 
917 	ireq = &ifctx->ireq;
918 	so = ifctx->so;
919 	myaddr = &ifctx->myaddr;
920 	netmask = &ifctx->netmask;
921 	gw = &ifctx->gw;
922 
923 	if (ifctx->state != IF_BOOTP_RESOLVED) {
924 
925 		/* Shutdown interfaces where BOOTP failed */
926 
927 		printf("Shutdown interface %s\n", ifctx->ireq.ifr_name);
928 		error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp);
929 		if (error != 0)
930 			panic("bootpc_adjust_interface: "
931 			      "SIOCGIFFLAGS, error=%d", error);
932 		ireq->ifr_flags &= ~IFF_UP;
933 		error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp);
934 		if (error != 0)
935 			panic("bootpc_adjust_interface: "
936 			      "SIOCSIFFLAGS, error=%d", error);
937 
938 		sin = (struct sockaddr_in *) &ireq->ifr_addr;
939 		clear_sinaddr(sin);
940 		error = ifioctl(so, SIOCDIFADDR, (caddr_t) ireq, procp);
941 		if (error != 0 && (error != EEXIST ||
942 				   ifctx == gctx->interfaces))
943 			panic("bootpc_adjust_interface: "
944 			      "SIOCDIFADDR, error=%d", error);
945 
946 		return 0;
947 	}
948 
949 	printf("Adjusted interface %s\n", ifctx->ireq.ifr_name);
950 	/*
951 	 * Do enough of ifconfig(8) so that the chosen interface
952 	 * can talk to the servers.  (just set the address)
953 	 */
954 	bcopy(netmask, &ireq->ifr_addr, sizeof(*netmask));
955 	error = ifioctl(so, SIOCSIFNETMASK, (caddr_t) ireq, procp);
956 	if (error != 0)
957 		panic("bootpc_adjust_interface: "
958 		      "set if netmask, error=%d", error);
959 
960 	/* Broadcast is with host part of IP address all 1's */
961 
962 	sin = (struct sockaddr_in *) &ireq->ifr_addr;
963 	clear_sinaddr(sin);
964 	sin->sin_addr.s_addr = myaddr->sin_addr.s_addr |
965 		~ netmask->sin_addr.s_addr;
966 	error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t) ireq, procp);
967 	if (error != 0)
968 		panic("bootpc_adjust_interface: "
969 		      "set if broadcast addr, error=%d", error);
970 
971 	bcopy(myaddr, &ireq->ifr_addr, sizeof(*myaddr));
972 	error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, procp);
973 	if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
974 		panic("bootpc_adjust_interface: "
975 		      "set if addr, error=%d", error);
976 
977 	/* Add new default route */
978 
979 	if (ifctx->gotgw != 0 || gctx->gotgw == 0) {
980 		clear_sinaddr(&defdst);
981 		clear_sinaddr(&defmask);
982 		error = rtrequest(RTM_ADD,
983 				  (struct sockaddr *) &defdst,
984 				  (struct sockaddr *) gw,
985 				  (struct sockaddr *) &defmask,
986 				  (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
987 		if (error != 0) {
988 			printf("bootpc_adjust_interface: "
989 			       "add net route, error=%d\n", error);
990 			return error;
991 		}
992 	}
993 
994 	return 0;
995 }
996 
997 
998 static int
999 setfs(struct sockaddr_in *addr, char *path, char *p)
1000 {
1001 	unsigned int ip;
1002 	int val;
1003 
1004 	ip = 0;
1005 	if (((val = getdec(&p)) < 0) || (val > 255))
1006 		return 0;
1007 	ip = val << 24;
1008 	if (*p != '.')
1009 		return 0;
1010 	p++;
1011 	if (((val = getdec(&p)) < 0) || (val > 255))
1012 		return 0;
1013 	ip |= (val << 16);
1014 	if (*p != '.')
1015 		return 0;
1016 	p++;
1017 	if (((val = getdec(&p)) < 0) || (val > 255))
1018 		return 0;
1019 	ip |= (val << 8);
1020 	if (*p != '.')
1021 		return 0;
1022 	p++;
1023 	if (((val = getdec(&p)) < 0) || (val > 255))
1024 		return 0;
1025 	ip |= val;
1026 	if (*p != ':')
1027 		return 0;
1028 	p++;
1029 
1030 	addr->sin_addr.s_addr = htonl(ip);
1031 	addr->sin_len = sizeof(struct sockaddr_in);
1032 	addr->sin_family = AF_INET;
1033 
1034 	strncpy(path, p, MNAMELEN - 1);
1035 	return 1;
1036 }
1037 
1038 
1039 static int
1040 getdec(char **ptr)
1041 {
1042 	char *p;
1043 	int ret;
1044 
1045 	p = *ptr;
1046 	ret = 0;
1047 	if ((*p < '0') || (*p > '9'))
1048 		return -1;
1049 	while ((*p >= '0') && (*p <= '9')) {
1050 		ret = ret * 10 + (*p - '0');
1051 		p++;
1052 	}
1053 	*ptr = p;
1054 	return ret;
1055 }
1056 
1057 
1058 static char *
1059 substr(char *a, char *b)
1060 {
1061 	char *loc1;
1062 	char *loc2;
1063 
1064         while (*a != '\0') {
1065                 loc1 = a;
1066                 loc2 = b;
1067                 while (*loc1 == *loc2++) {
1068                         if (*loc1 == '\0')
1069 				return 0;
1070                         loc1++;
1071                         if (*loc2 == '\0')
1072 				return loc1;
1073                 }
1074 		a++;
1075         }
1076         return 0;
1077 }
1078 
1079 
1080 static void
1081 mountopts(struct nfs_args *args, char *p)
1082 {
1083 	char *tmp;
1084 
1085 	args->version = NFS_ARGSVERSION;
1086 	args->rsize = 8192;
1087 	args->wsize = 8192;
1088 	args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
1089 	args->sotype = SOCK_DGRAM;
1090 	if (p == NULL)
1091 		return;
1092 	if ((tmp = (char *)substr(p, "rsize=")))
1093 		args->rsize = getdec(&tmp);
1094 	if ((tmp = (char *)substr(p, "wsize=")))
1095 		args->wsize = getdec(&tmp);
1096 	if ((tmp = (char *)substr(p, "intr")))
1097 		args->flags |= NFSMNT_INT;
1098 	if ((tmp = (char *)substr(p, "soft")))
1099 		args->flags |= NFSMNT_SOFT;
1100 	if ((tmp = (char *)substr(p, "noconn")))
1101 		args->flags |= NFSMNT_NOCONN;
1102 	if ((tmp = (char *)substr(p, "tcp")))
1103 		args->sotype = SOCK_STREAM;
1104 }
1105 
1106 
1107 static int
1108 xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
1109 {
1110 	struct mbuf *m;
1111 	int alignedlen;
1112 
1113 	m = *mptr;
1114 	alignedlen = ( len + 3 ) & ~3;
1115 
1116 	if (m->m_len < alignedlen) {
1117 		m = m_pullup(m, alignedlen);
1118 		if (m == NULL) {
1119 			*mptr = NULL;
1120 			return EBADRPC;
1121 		}
1122 	}
1123 	bcopy(mtod(m, u_char *), buf, len);
1124 	m_adj(m, alignedlen);
1125 	*mptr = m;
1126 	return 0;
1127 }
1128 
1129 
1130 static int
1131 xdr_int_decode(struct mbuf **mptr, int *iptr)
1132 {
1133 	u_int32_t i;
1134 	if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
1135 		return EBADRPC;
1136 	*iptr = fxdr_unsigned(u_int32_t, i);
1137 	return 0;
1138 }
1139 
1140 
1141 static void
1142 print_sin_addr(struct sockaddr_in *sin)
1143 {
1144 	print_in_addr(sin->sin_addr);
1145 }
1146 
1147 
1148 static void
1149 print_in_addr(struct in_addr addr)
1150 {
1151 	unsigned int ip;
1152 
1153 	ip = ntohl(addr.s_addr);
1154 	printf("%d.%d.%d.%d",
1155 	       ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
1156 }
1157 
1158 static void
1159 bootpc_compose_query(ifctx, gctx, procp)
1160 	struct bootpc_ifcontext *ifctx;
1161 	struct bootpc_globalcontext *gctx;
1162 	struct proc *procp;
1163 {
1164 
1165 	gctx->gotrootpath = 0;
1166 	gctx->gotswappath = 0;
1167 	gctx->gotgw = 0;
1168 	ifctx->gotrootpath = 0;
1169 
1170 	bzero((caddr_t) &ifctx->call, sizeof(ifctx->call));
1171 
1172 	/* bootpc part */
1173 	ifctx->call.op = BOOTP_REQUEST; 	/* BOOTREQUEST */
1174 	ifctx->call.htype = 1;			/* 10mb ethernet */
1175 	ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */
1176 	ifctx->call.hops = 0;
1177 	ifctx->xid++;
1178 	ifctx->call.xid = txdr_unsigned(ifctx->xid);
1179 	bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen);
1180 
1181 	ifctx->call.vend[0] = 99;		/* RFC1048 cookie */
1182 	ifctx->call.vend[1] = 130;
1183 	ifctx->call.vend[2] = 83;
1184 	ifctx->call.vend[3] = 99;
1185 	ifctx->call.vend[4] = TAG_MAXMSGSIZE;
1186 	ifctx->call.vend[5] = 2;
1187 	ifctx->call.vend[6] = (sizeof(struct bootp_packet) >> 8) & 255;
1188 	ifctx->call.vend[7] = sizeof(struct bootp_packet) & 255;
1189 	ifctx->call.vend[8] = TAG_END;
1190 
1191 	ifctx->call.secs = 0;
1192 	ifctx->call.flags = htons(0x8000); /* We need an broadcast answer */
1193 }
1194 
1195 
1196 static int
1197 bootpc_hascookie(struct bootp_packet *bp)
1198 {
1199 	return (bp->vend[0] == 99 && bp->vend[1] == 130 &&
1200 		bp->vend[2] == 83 && bp->vend[3] == 99);
1201 }
1202 
1203 
1204 static void
1205 bootpc_tag_helper(struct bootpc_tagcontext *tctx,
1206 		  unsigned char *start,
1207 		  int len,
1208 		  int tag)
1209 {
1210 	unsigned char *j;
1211 	unsigned char *ej;
1212 	unsigned char code;
1213 
1214 	if (tctx->badtag != 0 || tctx->badopt != 0)
1215 		return;
1216 
1217 	j = start;
1218 	ej = j + len;
1219 
1220 	while (j < ej) {
1221 		code = *j++;
1222 		if (code == TAG_PAD)
1223 			continue;
1224 		if (code == TAG_END)
1225 			return;
1226 		if (j >= ej || j + *j + 1 > ej) {
1227 			tctx->badopt = 1;
1228 			return;
1229 		}
1230 		len = *j++;
1231 		if (code == tag) {
1232 			if (tctx->taglen + len > TAG_MAXLEN) {
1233 				tctx->badtag = 1;
1234 				return;
1235 			}
1236 			tctx->foundopt = 1;
1237 			if (len > 0)
1238 				memcpy(tctx->buf + tctx->taglen,
1239 				       j, len);
1240 			tctx->taglen += len;
1241 		}
1242 		if (code == TAG_OVERLOAD)
1243 			tctx->overload = *j;
1244 
1245 		j += len;
1246 	}
1247 }
1248 
1249 
1250 static unsigned char *
1251 bootpc_tag(struct bootpc_tagcontext *tctx,
1252 	   struct bootp_packet *bp,
1253 	   int len,
1254 	   int tag)
1255 {
1256 	unsigned char *j;
1257 	unsigned char *ej;
1258 
1259 	tctx->overload = 0;
1260 	tctx->badopt = 0;
1261 	tctx->badtag = 0;
1262 	tctx->foundopt = 0;
1263 	tctx->taglen = 0;
1264 
1265 	if (bootpc_hascookie(bp) == 0)
1266 		return NULL;
1267 
1268 	j = &bp->vend[4];
1269 	ej = (unsigned char *) bp + len;
1270 
1271 	bootpc_tag_helper(tctx, &bp->vend[4],
1272 			  (unsigned char *) bp + len - &bp->vend[4], tag);
1273 
1274 	if ((tctx->overload & OVERLOAD_FILE) != 0)
1275 		bootpc_tag_helper(tctx,
1276 				  (unsigned char *) bp->file,
1277 				  sizeof(bp->file),
1278 				  tag);
1279 	if ((tctx->overload & OVERLOAD_SNAME) != 0)
1280 		bootpc_tag_helper(tctx,
1281 				  (unsigned char *) bp->sname,
1282 				  sizeof(bp->sname),
1283 				  tag);
1284 
1285 	if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0)
1286 		return NULL;
1287 	tctx->buf[tctx->taglen] = '\0';
1288 	return tctx->buf;
1289 }
1290 
1291 
1292 static void
1293 bootpc_decode_reply(nd, ifctx, gctx)
1294 	struct nfsv3_diskless *nd;
1295 	struct bootpc_ifcontext *ifctx;
1296 	struct bootpc_globalcontext *gctx;
1297 {
1298 	char *p;
1299 	unsigned int ip;
1300 
1301 	ifctx->gotgw = 0;
1302 	ifctx->gotnetmask = 0;
1303 
1304 	clear_sinaddr(&ifctx->myaddr);
1305 	clear_sinaddr(&ifctx->netmask);
1306 	clear_sinaddr(&ifctx->gw);
1307 
1308 	ifctx->myaddr.sin_addr = ifctx->reply.yiaddr;
1309 
1310 	ip = ntohl(ifctx->myaddr.sin_addr.s_addr);
1311 	snprintf(gctx->lookup_path, sizeof(gctx->lookup_path),
1312 		 "swap.%d.%d.%d.%d",
1313 		 ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
1314 
1315 	printf("%s at ", ifctx->ireq.ifr_name);
1316 	print_sin_addr(&ifctx->myaddr);
1317 	printf(" server ");
1318 	print_in_addr(ifctx->reply.siaddr);
1319 
1320 	ifctx->gw.sin_addr = ifctx->reply.giaddr;
1321 	if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) {
1322 		printf(" via gateway ");
1323 		print_in_addr(ifctx->reply.giaddr);
1324 	}
1325 
1326 	/* This call used for the side effect (overload flag) */
1327 	(void) bootpc_tag(&gctx->tmptag,
1328 			  &ifctx->reply, ifctx->replylen, TAG_END);
1329 
1330 	if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0)
1331 		if (ifctx->reply.sname[0] != '\0')
1332 			printf(" server name %s", ifctx->reply.sname);
1333 	if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0)
1334 		if (ifctx->reply.file[0] != '\0')
1335 			printf(" boot file %s", ifctx->reply.file);
1336 
1337 	printf("\n");
1338 
1339 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1340 		       TAG_SUBNETMASK);
1341 	if (p != NULL) {
1342 		if (gctx->tag.taglen != 4)
1343 			panic("bootpc: subnet mask len is %d",
1344 			      gctx->tag.taglen);
1345 		bcopy(p, &ifctx->netmask.sin_addr, 4);
1346 		ifctx->gotnetmask = 1;
1347 		printf("subnet mask ");
1348 		print_sin_addr(&ifctx->netmask);
1349 		printf(" ");
1350 	}
1351 
1352 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1353 		       TAG_ROUTERS);
1354 	if (p != NULL) {
1355 		/* Routers */
1356 		if (gctx->tag.taglen % 4)
1357 			panic("bootpc: Router Len is %d", gctx->tag.taglen);
1358 		if (gctx->tag.taglen > 0) {
1359 			bcopy(p, &ifctx->gw.sin_addr, 4);
1360 			printf("router ");
1361 			print_sin_addr(&ifctx->gw);
1362 			printf(" ");
1363 			ifctx->gotgw = 1;
1364 			gctx->gotgw = 1;
1365 		}
1366 	}
1367 
1368 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1369 		       TAG_ROOT);
1370 	if (p != NULL) {
1371 		if (gctx->setrootfs != NULL) {
1372 			printf("rootfs %s (ignored) ", p);
1373 		} else 	if (setfs(&nd->root_saddr,
1374 				  nd->root_hostnam, p)) {
1375 			printf("rootfs %s ",p);
1376 			gctx->gotrootpath = 1;
1377 			ifctx->gotrootpath = 1;
1378 			gctx->setrootfs = ifctx;
1379 
1380 			p = bootpc_tag(&gctx->tag, &ifctx->reply,
1381 				       ifctx->replylen,
1382 				       TAG_ROOTOPTS);
1383 			if (p != NULL) {
1384 				mountopts(&nd->root_args, p);
1385 				printf("rootopts %s ", p);
1386 			}
1387 		} else
1388 			panic("Failed to set rootfs to %s",p);
1389 	}
1390 
1391 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1392 		       TAG_SWAP);
1393 	if (p != NULL) {
1394 		if (gctx->setswapfs != NULL) {
1395 			printf("swapfs %s (ignored) ", p);
1396 		} else 	if (setfs(&nd->swap_saddr,
1397 				  nd->swap_hostnam, p)) {
1398 			gctx->gotswappath = 1;
1399 			gctx->setswapfs = ifctx;
1400 			printf("swapfs %s ", p);
1401 
1402 			p = bootpc_tag(&gctx->tag, &ifctx->reply,
1403 				       ifctx->replylen,
1404 				       TAG_SWAPOPTS);
1405 			if (p != NULL) {
1406 				/* swap mount options */
1407 				mountopts(&nd->swap_args, p);
1408 				printf("swapopts %s ", p);
1409 			}
1410 
1411 			p = bootpc_tag(&gctx->tag, &ifctx->reply,
1412 				       ifctx->replylen,
1413 				       TAG_SWAPSIZE);
1414 			if (p != NULL) {
1415 				int swaplen;
1416 				if (gctx->tag.taglen != 4)
1417 					panic("bootpc: "
1418 					      "Expected 4 bytes for swaplen, "
1419 					      "not %d bytes",
1420 					      gctx->tag.taglen);
1421 				bcopy(p, &swaplen, 4);
1422 				nd->swap_nblks = ntohl(swaplen);
1423 				printf("swapsize %d KB ",
1424 				       nd->swap_nblks);
1425 			}
1426 		} else
1427 			panic("Failed to set swapfs to %s", p);
1428 	}
1429 
1430 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1431 		       TAG_HOSTNAME);
1432 	if (p != NULL) {
1433 		if (gctx->tag.taglen >= MAXHOSTNAMELEN)
1434 			panic("bootpc: hostname >= %d bytes",
1435 			      MAXHOSTNAMELEN);
1436 		if (gctx->sethostname != NULL) {
1437 			printf("hostname %s (ignored) ", p);
1438 		} else {
1439 			strcpy(nd->my_hostnam, p);
1440 			strcpy(hostname, p);
1441 			printf("hostname %s ",hostname);
1442 			gctx->sethostname = ifctx;
1443 		}
1444 	}
1445 
1446 	printf("\n");
1447 
1448 	if (ifctx->gotnetmask == 0) {
1449 		if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr)))
1450 			ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1451 		else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr)))
1452 			ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1453 		else
1454 			ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1455 	}
1456 	if (ifctx->gotgw == 0) {
1457 		/* Use proxyarp */
1458 		ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr;
1459 	}
1460 }
1461 
1462 void
1463 bootpc_init(void)
1464 {
1465 	struct bootpc_ifcontext *ifctx, *nctx;	/* Interface BOOTP contexts */
1466 	struct bootpc_globalcontext *gctx; 	/* Global BOOTP context */
1467 	struct ifnet *ifp;
1468 	int error;
1469 	struct nfsv3_diskless *nd;
1470 	struct proc *procp;
1471 
1472 	nd = &nfsv3_diskless;
1473 	procp = curproc;
1474 
1475 	/*
1476 	 * If already filled in, don't touch it here
1477 	 */
1478 	if (nfs_diskless_valid != 0)
1479 		return;
1480 
1481 	/*
1482 	 * Wait until arp entries can be handled.
1483 	 */
1484 	while (time_second == 0)
1485 		tsleep(&time_second, PZERO + 8, "arpkludge", 10);
1486 
1487 	gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK);
1488 	if (gctx == NULL)
1489 		panic("Failed to allocate bootp global context structure");
1490 
1491 	bzero(gctx, sizeof(*gctx));
1492 	gctx->xid = ~0xFFFF;
1493 	gctx->starttime = time_second;
1494 
1495 	ifctx = allocifctx(gctx);
1496 
1497 	/*
1498 	 * Find a network interface.
1499 	 */
1500 #ifdef BOOTP_WIRED_TO
1501 	printf("bootpc_init: wired to interface '%s'\n",
1502 	       __XSTRING(BOOTP_WIRED_TO));
1503 #endif
1504 	bzero(&ifctx->ireq, sizeof(ifctx->ireq));
1505 	for (ifp = TAILQ_FIRST(&ifnet);
1506 	     ifp != NULL;
1507 	     ifp = TAILQ_NEXT(ifp, if_link)) {
1508 		snprintf(ifctx->ireq.ifr_name, sizeof(ifctx->ireq.ifr_name),
1509 			 "%s%d", ifp->if_name, ifp->if_unit);
1510 #ifdef BOOTP_WIRED_TO
1511 		if (strcmp(ifctx->ireq.ifr_name,
1512 			   __XSTRING(BOOTP_WIRED_TO)) != 0)
1513 			continue;
1514 #else
1515 		if ((ifp->if_flags &
1516 		     (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
1517 		    IFF_BROADCAST)
1518 			continue;
1519 #endif
1520 		if (gctx->interfaces != NULL)
1521 			gctx->lastinterface->next = ifctx;
1522 		else
1523 			gctx->interfaces = ifctx;
1524 		ifctx->ifp = ifp;
1525 		gctx->lastinterface = ifctx;
1526 		ifctx = allocifctx(gctx);
1527 	}
1528 	free(ifctx, M_TEMP);
1529 
1530 	if (gctx->interfaces == NULL) {
1531 #ifdef BOOTP_WIRED_TO
1532 		panic("bootpc_init: Could not find interface specified "
1533 		      "by BOOTP_WIRED_TO: "
1534 		      __XSTRING(BOOTP_WIRED_TO));
1535 #else
1536 		panic("bootpc_init: no suitable interface");
1537 #endif
1538 	}
1539 
1540 	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1541 		bootpc_fakeup_interface(ifctx, gctx, procp);
1542 
1543 	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1544 		bootpc_compose_query(ifctx, gctx, procp);
1545 
1546 	ifctx = gctx->interfaces;
1547 	error = bootpc_call(gctx, procp);
1548 
1549 	if (error != 0) {
1550 #ifdef BOOTP_NFSROOT
1551 		panic("BOOTP call failed");
1552 #else
1553 		printf("BOOTP call failed\n");
1554 #endif
1555 	}
1556 
1557 	mountopts(&nd->root_args, NULL);
1558 
1559 	mountopts(&nd->swap_args, NULL);
1560 
1561 	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1562 		if (ifctx->state == IF_BOOTP_RESOLVED)
1563 			bootpc_decode_reply(nd, ifctx, gctx);
1564 
1565 	if (gctx->gotswappath == 0)
1566 		nd->swap_nblks = 0;
1567 #ifdef BOOTP_NFSROOT
1568 	if (gctx->gotrootpath == 0)
1569 		panic("bootpc: No root path offered");
1570 #endif
1571 
1572 	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
1573 		bootpc_adjust_interface(ifctx, gctx, procp);
1574 
1575 		soclose(ifctx->so);
1576 	}
1577 
1578 	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1579 		if (ifctx->gotrootpath != 0)
1580 			break;
1581 	if (ifctx == NULL) {
1582 		for (ifctx = gctx->interfaces;
1583 		     ifctx != NULL;
1584 		     ifctx = ifctx->next)
1585 			if (ifctx->state == IF_BOOTP_RESOLVED)
1586 				break;
1587 	}
1588 	if (ifctx == NULL)
1589 		goto out;
1590 
1591 	if (gctx->gotrootpath != 0) {
1592 
1593 		error = md_mount(&nd->root_saddr, nd->root_hostnam,
1594 				 nd->root_fh, &nd->root_fhsize,
1595 				 &nd->root_args, procp);
1596 		if (error != 0)
1597 			panic("nfs_boot: mountd root, error=%d", error);
1598 
1599 		if (gctx->gotswappath != 0) {
1600 
1601 			error = md_mount(&nd->swap_saddr,
1602 					 nd->swap_hostnam,
1603 					 nd->swap_fh, &nd->swap_fhsize,
1604 					 &nd->swap_args, procp);
1605 			if (error != 0)
1606 				panic("nfs_boot: mountd swap, error=%d",
1607 				      error);
1608 
1609 			error = md_lookup_swap(&nd->swap_saddr,
1610 					       gctx->lookup_path,
1611 					       nd->swap_fh, &nd->swap_fhsize,
1612 					       &nd->swap_args, procp);
1613 			if (error != 0)
1614 				panic("nfs_boot: lookup swap, error=%d",
1615 				      error);
1616 		}
1617 		nfs_diskless_valid = 3;
1618 	}
1619 
1620 	strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name);
1621 	bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr));
1622 	bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr));
1623 	((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
1624 		ifctx->myaddr.sin_addr.s_addr |
1625 		~ ifctx->netmask.sin_addr.s_addr;
1626 	bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask));
1627 
1628 out:
1629 	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = nctx) {
1630 		nctx = ifctx->next;
1631 		free(ifctx, M_TEMP);
1632 	}
1633 	free(gctx, M_TEMP);
1634 }
1635 
1636 
1637 /*
1638  * RPC: mountd/mount
1639  * Given a server pathname, get an NFS file handle.
1640  * Also, sets sin->sin_port to the NFS service port.
1641  */
1642 static int
1643 md_mount(struct sockaddr_in *mdsin,		/* mountd server address */
1644 	 char *path,
1645 	 u_char *fhp,
1646 	 int *fhsizep,
1647 	 struct nfs_args *args,
1648 	 struct proc *procp)
1649 {
1650 	struct mbuf *m;
1651 	int error;
1652 	int authunixok;
1653 	int authcount;
1654 	int authver;
1655 
1656 #ifdef BOOTP_NFSV3
1657 	/* First try NFS v3 */
1658 	/* Get port number for MOUNTD. */
1659 	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1660 			     &mdsin->sin_port, procp);
1661 	if (error == 0) {
1662 		m = xdr_string_encode(path, strlen(path));
1663 
1664 		/* Do RPC to mountd. */
1665 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1666 				  RPCMNT_MOUNT, &m, NULL, procp);
1667 	}
1668 	if (error == 0) {
1669 		args->flags |= NFSMNT_NFSV3;
1670 	} else {
1671 #endif
1672 		/* Fallback to NFS v2 */
1673 
1674 		/* Get port number for MOUNTD. */
1675 		error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1676 				     &mdsin->sin_port, procp);
1677 		if (error != 0)
1678 			return error;
1679 
1680 		m = xdr_string_encode(path, strlen(path));
1681 
1682 		/* Do RPC to mountd. */
1683 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1684 				  RPCMNT_MOUNT, &m, NULL, procp);
1685 		if (error != 0)
1686 			return error;	/* message already freed */
1687 
1688 #ifdef BOOTP_NFSV3
1689 	}
1690 #endif
1691 
1692 	if (xdr_int_decode(&m, &error) != 0 || error != 0)
1693 		goto bad;
1694 
1695 	if ((args->flags & NFSMNT_NFSV3) != 0) {
1696 		if (xdr_int_decode(&m, fhsizep) != 0 ||
1697 		    *fhsizep > NFSX_V3FHMAX ||
1698 		    *fhsizep <= 0)
1699 			goto bad;
1700 	} else
1701 		*fhsizep = NFSX_V2FH;
1702 
1703 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
1704 		goto bad;
1705 
1706 	if (args->flags & NFSMNT_NFSV3) {
1707 		if (xdr_int_decode(&m, &authcount) != 0)
1708 			goto bad;
1709 		authunixok = 0;
1710 		if (authcount < 0 || authcount > 100)
1711 			goto bad;
1712 		while (authcount > 0) {
1713 			if (xdr_int_decode(&m, &authver) != 0)
1714 				goto bad;
1715 			if (authver == RPCAUTH_UNIX)
1716 				authunixok = 1;
1717 			authcount--;
1718 		}
1719 		if (authunixok == 0)
1720 			goto bad;
1721 	}
1722 
1723 	/* Set port number for NFS use. */
1724 	error = krpc_portmap(mdsin, NFS_PROG,
1725 			     (args->flags &
1726 			      NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
1727 			     &mdsin->sin_port, procp);
1728 
1729 	goto out;
1730 
1731 bad:
1732 	error = EBADRPC;
1733 
1734 out:
1735 	m_freem(m);
1736 	return error;
1737 }
1738 
1739 
1740 static int
1741 md_lookup_swap(struct sockaddr_in *mdsin,	/* mountd server address */
1742 	       char *path,
1743 	       u_char *fhp,
1744 	       int *fhsizep,
1745 	       struct nfs_args *args,
1746 	       struct proc *procp)
1747 {
1748 	struct mbuf *m;
1749 	int error;
1750 	int size = -1;
1751 	int attribs_present;
1752 	int status;
1753 	union {
1754 		u_int32_t v2[17];
1755 		u_int32_t v3[21];
1756 	} fattribs;
1757 
1758 	m = m_get(M_WAIT,MT_DATA);
1759 	if (m == NULL)
1760 	  	return ENOBUFS;
1761 
1762 	if ((args->flags & NFSMNT_NFSV3) != 0) {
1763 		*mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
1764 		bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
1765 		m->m_len = *fhsizep + sizeof(u_int32_t);
1766 	} else {
1767 		bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
1768 		m->m_len = NFSX_V2FH;
1769 	}
1770 
1771 	m->m_next = xdr_string_encode(path, strlen(path));
1772 	if (m->m_next == NULL) {
1773 		error = ENOBUFS;
1774 		goto out;
1775 	}
1776 
1777 	/* Do RPC to nfsd. */
1778 	if ((args->flags & NFSMNT_NFSV3) != 0)
1779 		error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
1780 				  NFSPROC_LOOKUP, &m, NULL, procp);
1781 	else
1782 		error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
1783 				  NFSV2PROC_LOOKUP, &m, NULL, procp);
1784 	if (error != 0)
1785 		return error;	/* message already freed */
1786 
1787 	if (xdr_int_decode(&m, &status) != 0)
1788 		goto bad;
1789 	if (status != 0) {
1790 		error = ENOENT;
1791 		goto out;
1792 	}
1793 
1794 	if ((args->flags & NFSMNT_NFSV3) != 0) {
1795 		if (xdr_int_decode(&m, fhsizep) != 0 ||
1796 		    *fhsizep > NFSX_V3FHMAX ||
1797 		    *fhsizep <= 0)
1798 			goto bad;
1799 	} else
1800 		*fhsizep = NFSX_V2FH;
1801 
1802 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
1803 		goto bad;
1804 
1805 	if ((args->flags & NFSMNT_NFSV3) != 0) {
1806 		if (xdr_int_decode(&m, &attribs_present) != 0)
1807 			goto bad;
1808 		if (attribs_present != 0) {
1809 			if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
1810 					      sizeof(u_int32_t) * 21) != 0)
1811 				goto bad;
1812 			size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
1813 		}
1814 	} else {
1815 		if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
1816 				      sizeof(u_int32_t) * 17) != 0)
1817 			goto bad;
1818 		size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
1819 	}
1820 
1821 	if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
1822 		nfsv3_diskless.swap_nblks = size / 1024;
1823 		printf("md_lookup_swap: Swap size is %d KB\n",
1824 		       nfsv3_diskless.swap_nblks);
1825 	}
1826 
1827 	goto out;
1828 
1829 bad:
1830 	error = EBADRPC;
1831 
1832 out:
1833 	m_freem(m);
1834 	return error;
1835 }
1836