xref: /freebsd/sys/nfs/bootp_subr.c (revision ce834215a70ff69e7e222827437116eee2f9ac6f)
1 /*	$Id: bootp_subr.c,v 1.3 1997/05/14 01:31:54 tegge Exp $	*/
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 <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/conf.h>
49 #include <sys/sockio.h>
50 #include <sys/proc.h>
51 #include <sys/mount.h>
52 #include <sys/mbuf.h>
53 #include <sys/reboot.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 
57 #include <net/if.h>
58 #include <net/route.h>
59 
60 #include <netinet/in.h>
61 #include <net/if_types.h>
62 #include <net/if_dl.h>
63 #include <netinet/if_ether.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 MIN_REPLY_HDR 16	/* xid, dir, astat, errno */
74 
75 /*
76  * What is the longest we will wait before re-sending a request?
77  * Note this is also the frequency of "RPC timeout" messages.
78  * The re-send loop count sup linearly to this maximum, so the
79  * first complaint will happen after (1+2+3+4+5)=15 seconds.
80  */
81 #define	MAX_RESEND_DELAY 5	/* seconds */
82 
83 /* Definitions from RFC951 */
84 struct bootp_packet {
85   u_int8_t op;
86   u_int8_t htype;
87   u_int8_t hlen;
88   u_int8_t hops;
89   u_int32_t xid;
90   u_int16_t secs;
91   u_int16_t flags;
92   struct in_addr ciaddr;
93   struct in_addr yiaddr;
94   struct in_addr siaddr;
95   struct in_addr giaddr;
96   unsigned char chaddr[16];
97   char sname[64];
98   char file[128];
99   unsigned char vend[256];
100 };
101 
102 #define IPPORT_BOOTPC 68
103 #define IPPORT_BOOTPS 67
104 
105 extern int nfs_diskless_valid;
106 extern struct nfsv3_diskless nfsv3_diskless;
107 
108 /* mountd RPC */
109 static int md_mount __P((struct sockaddr_in *mdsin, char *path,
110 	u_char *fhp, int *fhsizep, struct nfs_args *args,struct proc *procp));
111 static int md_lookup_swap __P((struct sockaddr_in *mdsin,char *path,
112 			       u_char *fhp, int *fhsizep,
113 			       struct nfs_args *args,
114 			       struct proc *procp));
115 static int setfs __P((struct sockaddr_in *addr, char *path, char *p));
116 static int getdec __P((char **ptr));
117 static char *substr __P((char *a,char *b));
118 static void mountopts __P((struct nfs_args *args, char *p));
119 static int xdr_opaque_decode __P((struct mbuf **ptr,u_char *buf,
120 				  int len));
121 static int xdr_int_decode __P((struct mbuf **ptr,int *iptr));
122 static void printip __P((char *prefix,struct in_addr addr));
123 
124 #ifdef BOOTP_DEBUG
125 void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma);
126 void bootpboot_p_ma(struct sockaddr *ma);
127 void bootpboot_p_rtentry(struct rtentry *rt);
128 void bootpboot_p_tree(struct radix_node *rn);
129 void bootpboot_p_rtlist(void);
130 void bootpboot_p_iflist(void);
131 #endif
132 
133 int  bootpc_call(struct bootp_packet *call,
134 		 struct bootp_packet *reply,
135 		 struct proc *procp);
136 
137 int bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so,
138 			struct proc *procp);
139 
140 int
141 bootpc_adjust_interface(struct ifreq *ireq,struct socket *so,
142 			struct sockaddr_in *myaddr,
143 			struct sockaddr_in *netmask,
144 			struct sockaddr_in *gw,
145 			struct proc *procp);
146 
147 void bootpc_init(void);
148 
149 #ifdef BOOTP_DEBUG
150 void bootpboot_p_sa(sa,ma)
151      struct sockaddr *sa;
152      struct sockaddr *ma;
153 {
154   if (!sa) {
155     printf("(sockaddr *) <null>");
156     return;
157   }
158   switch (sa->sa_family) {
159   case AF_INET:
160     {
161       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
162       printf("inet %x",ntohl(sin->sin_addr.s_addr));
163       if (ma) {
164 	struct sockaddr_in *sin = (struct sockaddr_in *) ma;
165 	printf(" mask %x",ntohl(sin->sin_addr.s_addr));
166       }
167     }
168   break;
169   case AF_LINK:
170     {
171       struct sockaddr_dl *sli = (struct sockaddr_dl *) sa;
172       int i;
173       printf("link %.*s ",sli->sdl_nlen,sli->sdl_data);
174       for (i=0;i<sli->sdl_alen;i++) {
175 	if (i>0)
176 	  printf(":");
177 	printf("%x",(unsigned char) sli->sdl_data[i+sli->sdl_nlen]);
178       }
179     }
180   break;
181   default:
182     printf("af%d",sa->sa_family);
183   }
184 }
185 
186 void bootpboot_p_ma(ma)
187      struct sockaddr *ma;
188 {
189   if (!ma) {
190     printf("<null>");
191     return;
192   }
193   printf("%x",*(int*)ma);
194 }
195 
196 void bootpboot_p_rtentry(rt)
197      struct rtentry *rt;
198 {
199   bootpboot_p_sa(rt_key(rt),rt_mask(rt));
200   printf(" ");
201   bootpboot_p_ma(rt->rt_genmask);
202   printf(" ");
203   bootpboot_p_sa(rt->rt_gateway,NULL);
204   printf(" ");
205   printf("flags %x",(unsigned short) rt->rt_flags);
206   printf(" %d",rt->rt_rmx.rmx_expire);
207   printf(" %s%d\n",rt->rt_ifp->if_name,rt->rt_ifp->if_unit);
208 }
209 void  bootpboot_p_tree(rn)
210      struct radix_node *rn;
211 {
212   while (rn) {
213     if (rn->rn_b < 0) {
214       if (rn->rn_flags & RNF_ROOT) {
215       } else {
216 	bootpboot_p_rtentry((struct rtentry *) rn);
217       }
218       rn = rn->rn_dupedkey;
219     } else {
220       bootpboot_p_tree(rn->rn_l);
221       bootpboot_p_tree(rn->rn_r);
222       return;
223     }
224 
225   }
226 }
227 
228 void bootpboot_p_rtlist(void)
229 {
230   printf("Routing table:\n");
231   bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop);
232 }
233 
234 void bootpboot_p_iflist(void)
235 {
236   struct ifnet *ifp;
237   struct ifaddr *ifa;
238   printf("Interface list:\n");
239   for (ifp = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link))
240     {
241       for (ifa = TAILQ_FIRST(&ifp->if_addrhead) ;ifa;
242 	   ifa=TAILQ_NEXT(ifa,ifa_link))
243 	if (ifa->ifa_addr->sa_family == AF_INET ) {
244 	  printf("%s%d flags %x, addr %x, bcast %x, net %x\n",
245 		 ifp->if_name,ifp->if_unit,
246 		 (unsigned short) ifp->if_flags,
247 		 ntohl(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr),
248 		 ntohl(((struct sockaddr_in *) ifa->ifa_dstaddr)->sin_addr.s_addr),
249 		 ntohl(((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr)
250 		 );
251 	}
252     }
253 }
254 #endif
255 
256 int
257 bootpc_call(call,reply,procp)
258      struct bootp_packet *call;
259      struct bootp_packet *reply;	/* output */
260      struct proc *procp;
261 {
262 	struct socket *so;
263 	struct sockaddr_in *sin,sa;
264 	struct mbuf *m, *nam;
265 	struct uio auio;
266 	struct iovec aio;
267 	int error, rcvflg, timo, secs, len;
268 	u_int tport;
269 
270 	/* Free at end if not null. */
271 	nam = NULL;
272 
273 	/*
274 	 * Create socket and set its recieve timeout.
275 	 */
276 	if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)))
277 		goto out;
278 
279 	m = m_get(M_WAIT, MT_SOOPTS);
280 	if (m == NULL) {
281 		error = ENOBUFS;
282 		goto out;
283 	} else {
284 		struct timeval *tv;
285 		tv = mtod(m, struct timeval *);
286 		m->m_len = sizeof(*tv);
287 		tv->tv_sec = 1;
288 		tv->tv_usec = 0;
289 		if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m, procp)))
290 			goto out;
291 	}
292 
293 	/*
294 	 * Enable broadcast.
295 	 */
296 	{
297 		int *on;
298 		m = m_get(M_WAIT, MT_SOOPTS);
299 		if (m == NULL) {
300 			error = ENOBUFS;
301 			goto out;
302 		}
303 		on = mtod(m, int *);
304 		m->m_len = sizeof(*on);
305 		*on = 1;
306 		if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m, procp)))
307 			goto out;
308 	}
309 
310 	/*
311 	 * Bind the local endpoint to a bootp client port.
312 	 */
313 	m = m_getclr(M_WAIT, MT_SONAME);
314 	sin = mtod(m, struct sockaddr_in *);
315 	sin->sin_len = m->m_len = sizeof(*sin);
316 	sin->sin_family = AF_INET;
317 	sin->sin_addr.s_addr = INADDR_ANY;
318 	sin->sin_port = htons(IPPORT_BOOTPC);
319 	error = sobind(so, m, procp);
320 	m_freem(m);
321 	if (error) {
322 		printf("bind failed\n");
323 		goto out;
324 	}
325 
326 	/*
327 	 * Setup socket address for the server.
328 	 */
329 	nam = m_get(M_WAIT, MT_SONAME);
330 	if (nam == NULL) {
331 		error = ENOBUFS;
332 		goto out;
333 	}
334 	sin = mtod(nam, struct sockaddr_in *);
335 	sin-> sin_len = sizeof(*sin);
336 	sin-> sin_family = AF_INET;
337 	sin->sin_addr.s_addr = INADDR_BROADCAST;
338 	sin->sin_port = htons(IPPORT_BOOTPS);
339 
340 	nam->m_len = sizeof(*sin);
341 
342 	/*
343 	 * Send it, repeatedly, until a reply is received,
344 	 * but delay each re-send by an increasing amount.
345 	 * If the delay hits the maximum, start complaining.
346 	 */
347 	timo = 0;
348 	for (;;) {
349 		/* Send BOOTP request (or re-send). */
350 
351 		aio.iov_base = (caddr_t) call;
352 		aio.iov_len = sizeof(*call);
353 
354 		auio.uio_iov = &aio;
355 		auio.uio_iovcnt = 1;
356 		auio.uio_segflg = UIO_SYSSPACE;
357 		auio.uio_rw = UIO_WRITE;
358 		auio.uio_offset = 0;
359 		auio.uio_resid = sizeof(*call);
360 		auio.uio_procp = procp;
361 
362 		error = sosend(so, nam, &auio, NULL, NULL, 0);
363 		if (error) {
364 			printf("bootpc_call: sosend: %d\n", error);
365 			goto out;
366 		}
367 
368 		/* Determine new timeout. */
369 		if (timo < MAX_RESEND_DELAY)
370 			timo++;
371 		else
372 			printf("BOOTP timeout for server 0x%x\n",
373 			       ntohl(sin->sin_addr.s_addr));
374 
375 		/*
376 		 * Wait for up to timo seconds for a reply.
377 		 * The socket receive timeout was set to 1 second.
378 		 */
379 		secs = timo;
380 		while (secs > 0) {
381 			aio.iov_base = (caddr_t) reply;
382 			aio.iov_len = sizeof(*reply);
383 
384 			auio.uio_iov = &aio;
385 			auio.uio_iovcnt = 1;
386 			auio.uio_segflg = UIO_SYSSPACE;
387 			auio.uio_rw = UIO_READ;
388 			auio.uio_offset = 0;
389 			auio.uio_resid = sizeof(*reply);
390 			auio.uio_procp = procp;
391 
392 			rcvflg = 0;
393 			error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg);
394 			if (error == EWOULDBLOCK) {
395 				secs--;
396 				call->secs=htons(ntohs(call->secs)+1);
397 				continue;
398 			}
399 			if (error)
400 				goto out;
401 			len = sizeof(*reply) - auio.uio_resid;
402 
403 			/* Does the reply contain at least a header? */
404 			if (len < MIN_REPLY_HDR)
405 				continue;
406 
407 			/* Is it the right reply? */
408 			if (reply->op != 2)
409 			  continue;
410 
411 			if (reply->xid != call->xid)
412 				continue;
413 
414 			if (reply->hlen != call->hlen)
415 			  continue;
416 
417 			if (bcmp(reply->chaddr,call->chaddr,call->hlen))
418 			  continue;
419 
420 			goto gotreply;	/* break two levels */
421 
422 		} /* while secs */
423 	} /* forever send/receive */
424 
425 	error = ETIMEDOUT;
426 	goto out;
427 
428  gotreply:
429  out:
430 	if (nam) m_freem(nam);
431 	soclose(so);
432 	return error;
433 }
434 
435 int
436 bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so,
437 			struct proc *procp)
438 {
439   struct sockaddr_in *sin;
440   int error;
441   struct sockaddr_in dst;
442   struct sockaddr_in gw;
443   struct sockaddr_in mask;
444 
445   /*
446    * Bring up the interface.
447    *
448    * Get the old interface flags and or IFF_UP into them; if
449    * IFF_UP set blindly, interface selection can be clobbered.
450    */
451   error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp);
452   if (error)
453     panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error);
454   ireq->ifr_flags |= IFF_UP;
455   error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp);
456   if (error)
457     panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error);
458 
459   /*
460    * Do enough of ifconfig(8) so that the chosen interface
461    * can talk to the servers.  (just set the address)
462    */
463 
464   /* addr is 0.0.0.0 */
465 
466   sin = (struct sockaddr_in *)&ireq->ifr_addr;
467   bzero((caddr_t)sin, sizeof(*sin));
468   sin->sin_len = sizeof(*sin);
469   sin->sin_family = AF_INET;
470   sin->sin_addr.s_addr = INADDR_ANY;
471   error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp);
472   if (error)
473     panic("bootpc_fakeup_interface: set if addr, error=%d", error);
474 
475   /* netmask is 0.0.0.0 */
476 
477   sin = (struct sockaddr_in *)&ireq->ifr_addr;
478   bzero((caddr_t)sin, sizeof(*sin));
479   sin->sin_len = sizeof(*sin);
480   sin->sin_family = AF_INET;
481   sin->sin_addr.s_addr = INADDR_ANY;
482   error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp);
483   if (error)
484     panic("bootpc_fakeup_interface: set if net addr, error=%d", error);
485 
486   /* Broadcast is 255.255.255.255 */
487 
488   sin = (struct sockaddr_in *)&ireq->ifr_addr;
489   bzero((caddr_t)sin, sizeof(*sin));
490   sin->sin_len = sizeof(*sin);
491   sin->sin_family = AF_INET;
492   sin->sin_addr.s_addr = INADDR_BROADCAST;
493   error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp);
494   if (error)
495     panic("bootpc_fakeup_interface: set if broadcast addr, error=%d", error);
496 
497   /* Add default route to 0.0.0.0 so we can send data */
498 
499   bzero((caddr_t) &dst, sizeof(dst));
500   dst.sin_len=sizeof(dst);
501   dst.sin_family=AF_INET;
502   dst.sin_addr.s_addr = htonl(0);
503 
504   bzero((caddr_t) &gw, sizeof(gw));
505   gw.sin_len=sizeof(gw);
506   gw.sin_family=AF_INET;
507   gw.sin_addr.s_addr = htonl(0x0);
508 
509   bzero((caddr_t) &mask, sizeof(mask));
510   mask.sin_len=sizeof(mask);
511   mask.sin_family=AF_INET;
512   mask.sin_addr.s_addr = htonl(0);
513 
514   error = rtrequest(RTM_ADD,
515 		    (struct sockaddr *) &dst,
516 		    (struct sockaddr *) &gw,
517 		    (struct sockaddr *) &mask,
518 		    RTF_UP | RTF_STATIC
519 		    , NULL);
520   if (error)
521     printf("bootpc_fakeup_interface: add default route, error=%d\n", error);
522   return error;
523 }
524 
525 int
526 bootpc_adjust_interface(struct ifreq *ireq,struct socket *so,
527 			struct sockaddr_in *myaddr,
528 			struct sockaddr_in *netmask,
529 			struct sockaddr_in *gw,
530 			struct proc *procp)
531 {
532   int error;
533   struct sockaddr_in oldgw;
534   struct sockaddr_in olddst;
535   struct sockaddr_in oldmask;
536   struct sockaddr_in *sin;
537 
538   /* Remove old default route to 0.0.0.0 */
539 
540   bzero((caddr_t) &olddst, sizeof(olddst));
541   olddst.sin_len=sizeof(olddst);
542   olddst.sin_family=AF_INET;
543   olddst.sin_addr.s_addr = INADDR_ANY;
544 
545   bzero((caddr_t) &oldgw, sizeof(oldgw));
546   oldgw.sin_len=sizeof(oldgw);
547   oldgw.sin_family=AF_INET;
548   oldgw.sin_addr.s_addr = INADDR_ANY;
549 
550   bzero((caddr_t) &oldmask, sizeof(oldmask));
551   oldmask.sin_len=sizeof(oldmask);
552   oldmask.sin_family=AF_INET;
553   oldmask.sin_addr.s_addr = INADDR_ANY;
554 
555   error = rtrequest(RTM_DELETE,
556 		    (struct sockaddr *) &olddst,
557 		    (struct sockaddr *) &oldgw,
558 		    (struct sockaddr *) &oldmask,
559 		    (RTF_UP | RTF_STATIC), NULL);
560   if (error) {
561     printf("nfs_boot: del default route, error=%d\n", error);
562     return error;
563   }
564 
565   /*
566    * Do enough of ifconfig(8) so that the chosen interface
567    * can talk to the servers.  (just set the address)
568    */
569   bcopy(netmask,&ireq->ifr_addr,sizeof(*netmask));
570   error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp);
571   if (error)
572     panic("nfs_boot: set if netmask, error=%d", error);
573 
574   /* Broadcast is with host part of IP address all 1's */
575 
576   sin = (struct sockaddr_in *)&ireq->ifr_addr;
577   bzero((caddr_t)sin, sizeof(*sin));
578   sin->sin_len = sizeof(*sin);
579   sin->sin_family = AF_INET;
580   sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr;
581   error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp);
582   if (error)
583     panic("bootpc_call: set if broadcast addr, error=%d", error);
584 
585   bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr));
586   error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp);
587   if (error)
588     panic("nfs_boot: set if addr, error=%d", error);
589 
590   /* Add new default route */
591 
592   error = rtrequest(RTM_ADD,
593 		    (struct sockaddr *) &olddst,
594 		    (struct sockaddr *) gw,
595 		    (struct sockaddr *) &oldmask,
596 		    (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
597   if (error) {
598     printf("nfs_boot: add net route, error=%d\n", error);
599     return error;
600   }
601 
602   return 0;
603 }
604 
605 static int setfs(addr, path, p)
606 	struct sockaddr_in *addr;
607 	char *path;
608 	char *p;
609 {
610 	unsigned ip = 0;
611 	int val;
612 
613 	if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
614 	ip = val << 24;
615 	if (*p != '.') return(0);
616 	p++;
617 	if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
618 	ip |= (val << 16);
619 	if (*p != '.') return(0);
620 	p++;
621 	if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
622 	ip |= (val << 8);
623 	if (*p != '.') return(0);
624 	p++;
625 	if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
626 	ip |= val;
627 	if (*p != ':') return(0);
628 	p++;
629 
630 	addr->sin_addr.s_addr = htonl(ip);
631 	addr->sin_len = sizeof(struct sockaddr_in);
632 	addr->sin_family = AF_INET;
633 
634 	strncpy(path,p,MNAMELEN-1);
635 	return(1);
636 }
637 
638 static int getdec(ptr)
639 	char **ptr;
640 {
641 	char *p = *ptr;
642 	int ret=0;
643 	if ((*p < '0') || (*p > '9')) return(-1);
644 	while ((*p >= '0') && (*p <= '9')) {
645 		ret = ret*10 + (*p - '0');
646 		p++;
647 	}
648 	*ptr = p;
649 	return(ret);
650 }
651 
652 static char *substr(a,b)
653 	char *a,*b;
654 {
655 	char *loc1;
656 	char *loc2;
657 
658         while (*a != '\0') {
659                 loc1 = a;
660                 loc2 = b;
661                 while (*loc1 == *loc2++) {
662                         if (*loc1 == '\0') return (0);
663                         loc1++;
664                         if (*loc2 == '\0') return (loc1);
665                 }
666         a++;
667         }
668         return (0);
669 }
670 
671 static void mountopts(args,p)
672 	struct nfs_args *args;
673 	char *p;
674 {
675 	char *tmp;
676 
677 	args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
678 	args->sotype = SOCK_DGRAM;
679 	if ((tmp = (char *)substr(p,"rsize=")))
680 		args->rsize=getdec(&tmp);
681 	if ((tmp = (char *)substr(p,"wsize=")))
682 		args->wsize=getdec(&tmp);
683 	if ((tmp = (char *)substr(p,"intr")))
684 		args->flags |= NFSMNT_INT;
685 	if ((tmp = (char *)substr(p,"soft")))
686 		args->flags |= NFSMNT_SOFT;
687 	if ((tmp = (char *)substr(p,"noconn")))
688 		args->flags |= NFSMNT_NOCONN;
689 	if ((tmp = (char *)substr(p, "tcp")))
690 	    args->sotype = SOCK_STREAM;
691 }
692 
693 static int xdr_opaque_decode(mptr,buf,len)
694      struct mbuf **mptr;
695      u_char *buf;
696      int len;
697 {
698   struct mbuf *m;
699   int alignedlen;
700 
701   m = *mptr;
702   alignedlen = ( len + 3 ) & ~3;
703 
704   if (m->m_len < alignedlen) {
705     m = m_pullup(m,alignedlen);
706     if (m == NULL) {
707       *mptr = NULL;
708       return EBADRPC;
709     }
710   }
711   bcopy(mtod(m,u_char *),buf,len);
712   m_adj(m,alignedlen);
713   *mptr = m;
714   return 0;
715 }
716 
717 static int xdr_int_decode(mptr,iptr)
718      struct mbuf **mptr;
719      int *iptr;
720 {
721   u_int32_t i;
722   if (xdr_opaque_decode(mptr,(u_char *) &i,sizeof(u_int32_t)))
723     return EBADRPC;
724   *iptr = fxdr_unsigned(u_int32_t,i);
725   return 0;
726 }
727 
728 static void printip(char *prefix,struct in_addr addr)
729 {
730   unsigned int ip;
731 
732   ip = ntohl(addr.s_addr);
733 
734   printf("%s is %d.%d.%d.%d\n",prefix,
735 	 ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 );
736 }
737 
738 void
739 bootpc_init(void)
740 {
741   struct bootp_packet call;
742   struct bootp_packet reply;
743   static u_int32_t xid = ~0xFF;
744 
745   struct ifreq ireq;
746   struct ifnet *ifp;
747   struct socket *so;
748   int error;
749   int code,ncode,len;
750   int i,j;
751   char *p;
752   unsigned int ip;
753 
754   struct sockaddr_in myaddr;
755   struct sockaddr_in netmask;
756   struct sockaddr_in gw;
757   int gotgw=0;
758   int gotnetmask=0;
759   int gotrootpath=0;
760   int gotswappath=0;
761   char lookup_path[24];
762 
763 #define EALEN 6
764   unsigned char ea[EALEN];
765   struct ifaddr *ifa;
766   struct sockaddr_dl *sdl = NULL;
767   char *delim;
768 
769   struct nfsv3_diskless *nd = &nfsv3_diskless;
770   struct proc *procp = curproc;
771 
772   /*
773    * If already filled in, don't touch it here
774    */
775   if (nfs_diskless_valid)
776     return;
777 
778   /*
779    * Bump time if 0.
780    */
781   if (!time.tv_sec)
782     time.tv_sec++;
783 
784   /*
785    * Find a network interface.
786    */
787   for (ifp = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link))
788     if ((ifp->if_flags &
789       (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
790 	break;
791   if (ifp == NULL)
792     panic("bootpc_init: no suitable interface");
793   bzero(&ireq,sizeof(ireq));
794   sprintf(ireq.ifr_name, "%s%d", ifp->if_name,ifp->if_unit);
795   strcpy(nd->myif.ifra_name,ireq.ifr_name);
796   printf("bootpc_init: using network interface '%s'\n",
797 	 ireq.ifr_name);
798 
799   if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0)
800     panic("nfs_boot: socreate, error=%d", error);
801 
802   bootpc_fakeup_interface(&ireq,so,procp);
803 
804   printf("Bootpc testing starting\n");
805 
806   /* Get HW address */
807 
808   for (ifa = TAILQ_FIRST(&ifp->if_addrhead) ;ifa;
809        ifa=TAILQ_NEXT(ifa,ifa_link))
810     if (ifa->ifa_addr->sa_family == AF_LINK &&
811 	(sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
812 	sdl->sdl_type == IFT_ETHER)
813       break;
814 
815   if (!sdl)
816     panic("bootpc: Unable to find HW address");
817   if (sdl->sdl_alen != EALEN )
818     panic("bootpc: HW address len is %d, expected value is %d",
819 	  sdl->sdl_alen,EALEN);
820 
821   printf("bootpc hw address is ");
822   delim="";
823   for (j=0;j<sdl->sdl_alen;j++) {
824     printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]);
825     delim=":";
826   }
827   printf("\n");
828 
829 #if 0
830   bootpboot_p_iflist();
831   bootpboot_p_rtlist();
832 #endif
833 
834   bzero((caddr_t) &call, sizeof(call));
835 
836   /* bootpc part */
837   call.op = 1; 			/* BOOTREQUEST */
838   call.htype= 1;		/* 10mb ethernet */
839   call.hlen=sdl->sdl_alen;	/* Hardware address length */
840   call.hops=0;
841   xid++;
842   call.xid = txdr_unsigned(xid);
843   bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen);
844 
845   call.vend[0]=99;
846   call.vend[1]=130;
847   call.vend[2]=83;
848   call.vend[3]=99;
849   call.vend[4]=255;
850 
851   call.secs = 0;
852   call.flags = htons(0x8000); /* We need an broadcast answer */
853 
854   error = bootpc_call(&call,&reply,procp);
855 
856   if (error) {
857 #ifdef BOOTP_NFSROOT
858     panic("BOOTP call failed");
859 #endif
860     return;
861   }
862 
863   bzero(&myaddr,sizeof(myaddr));
864   bzero(&netmask,sizeof(netmask));
865   bzero(&gw,sizeof(gw));
866 
867   myaddr.sin_len = sizeof(myaddr);
868   myaddr.sin_family = AF_INET;
869 
870   netmask.sin_len = sizeof(netmask);
871   netmask.sin_family = AF_INET;
872 
873   gw.sin_len = sizeof(gw);
874   gw.sin_family= AF_INET;
875 
876   nd->root_args.version = NFS_ARGSVERSION;
877   nd->root_args.rsize = 8192;
878   nd->root_args.wsize = 8192;
879   nd->root_args.sotype = SOCK_DGRAM;
880   nd->root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT);
881 
882   nd->swap_saddr.sin_len = sizeof(gw);
883   nd->swap_saddr.sin_family = AF_INET;
884 
885   nd->swap_args.version = NFS_ARGSVERSION;
886   nd->swap_args.rsize = 8192;
887   nd->swap_args.wsize = 8192;
888   nd->swap_args.sotype = SOCK_DGRAM;
889   nd->swap_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT);
890 
891   myaddr.sin_addr = reply.yiaddr;
892 
893   ip = ntohl(myaddr.sin_addr.s_addr);
894   sprintf(lookup_path,"swap.%d.%d.%d.%d",
895 	  ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 );
896 
897   printip("My ip address",myaddr.sin_addr);
898 
899   printip("Server ip address",reply.siaddr);
900 
901   gw.sin_addr = reply.giaddr;
902   printip("Gateway ip address",reply.giaddr);
903 
904   if (reply.sname[0])
905     printf("Server name is %s\n",reply.sname);
906   if (reply.file[0])
907     printf("boot file is %s\n",reply.file);
908   if (reply.vend[0]==99 && reply.vend[1]==130 &&
909       reply.vend[2]==83 && reply.vend[3]==99) {
910     j=4;
911     ncode = reply.vend[j];
912     while (j<sizeof(reply.vend)) {
913       code = reply.vend[j] = ncode;
914       if (code==255)
915 	break;
916       if (code==0) {
917 	j++;
918 	continue;
919       }
920       len = reply.vend[j+1];
921       j+=2;
922       if (len+j>=sizeof(reply.vend)) {
923 	printf("Truncated field");
924 	break;
925       }
926       ncode = reply.vend[j+len];
927       reply.vend[j+len]='\0';
928       p = &reply.vend[j];
929       switch (code) {
930       case 1:
931 	if (len!=4)
932 	  panic("bootpc: subnet mask len is %d",len);
933 	bcopy(&reply.vend[j],&netmask.sin_addr,4);
934 	gotnetmask=1;
935 	printip("Subnet mask",netmask.sin_addr);
936 	break;
937       case 6:	/* Domain Name servers. Unused */
938       case 16:	/* Swap server IP address. unused */
939       case 2:
940 	/* Time offset */
941 	break;
942       case 3:
943 	/* Routers */
944 	if (len % 4)
945 	  panic("bootpc: Router Len is %d",len);
946 	if (len > 0) {
947 	  bcopy(&reply.vend[j],&gw.sin_addr,4);
948 	  printip("Router",gw.sin_addr);
949 	  gotgw=1;
950 	}
951 	break;
952       case 17:
953 	if (setfs(&nd->root_saddr, nd->root_hostnam, p)) {
954 	  printf("rootfs is %s\n",p);
955 	  gotrootpath=1;
956 	} else
957 	  panic("Failed to set rootfs to %s",p);
958 	break;
959       case 12:
960 	if (len>=MAXHOSTNAMELEN)
961 	  panic("bootpc: hostname  >=%d bytes",MAXHOSTNAMELEN);
962 	strncpy(nd->my_hostnam,&reply.vend[j],len);
963 	nd->my_hostnam[len]=0;
964 	strncpy(hostname,&reply.vend[j],len);
965 	hostname[len]=0;
966 	printf("Hostname is %s\n",hostname);
967 	break;
968       case 128:
969 	if (setfs(&nd->swap_saddr, nd->swap_hostnam, p)) {
970 	  gotswappath=1;
971 	  printf("swapfs is %s\n",p);
972 	} else
973 	  panic("Failed to set swapfs to %s",p);
974 	break;
975       case 129:
976 	{
977 	  int swaplen;
978 	  if (len!=4)
979 	    panic("bootpc: Expected 4 bytes for swaplen, not %d bytes",len);
980 	  bcopy(&reply.vend[j],&swaplen,4);
981 	  nd->swap_nblks = ntohl(swaplen);
982 	  printf("bootpc: Swap size is %d KB\n",nd->swap_nblks);
983 	}
984 	break;
985       case 130:	/* root mount options */
986 	mountopts(&nd->root_args,p);
987 	break;
988       case 131:	/* swap mount options */
989 	mountopts(&nd->swap_args,p);
990 	break;
991       default:
992 	printf("Ignoring field type %d\n",code);
993       }
994       j+=len;
995     }
996   }
997 
998   if (!gotswappath)
999     nd->swap_nblks = 0;
1000 #ifdef BOOTP_NFSROOT
1001   if (!gotrootpath)
1002     panic("bootpc: No root path offered");
1003 #endif
1004 
1005   if (!gotnetmask) {
1006     if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr)))
1007       netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1008     else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr)))
1009       netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1010     else
1011       netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1012   }
1013   if (!gotgw) {
1014     /* Use proxyarp */
1015     gw.sin_addr.s_addr = myaddr.sin_addr.s_addr;
1016   }
1017 
1018 #if 0
1019   bootpboot_p_iflist();
1020   bootpboot_p_rtlist();
1021 #endif
1022   error = bootpc_adjust_interface(&ireq,so,
1023 				  &myaddr,&netmask,&gw,procp);
1024 
1025   soclose(so);
1026 
1027 #if 0
1028   bootpboot_p_iflist();
1029   bootpboot_p_rtlist();
1030 #endif
1031 
1032   if (gotrootpath) {
1033 
1034     error = md_mount(&nd->root_saddr, nd->root_hostnam,
1035 		     nd->root_fh, &nd->root_fhsize,
1036 		     &nd->root_args,procp);
1037     if (error)
1038       panic("nfs_boot: mountd root, error=%d", error);
1039 
1040     if (gotswappath) {
1041 
1042       error = md_mount(&nd->swap_saddr,
1043 		       nd->swap_hostnam,
1044 		       nd->swap_fh, &nd->swap_fhsize,&nd->swap_args,procp);
1045       if (error)
1046 	panic("nfs_boot: mountd swap, error=%d", error);
1047 
1048       error = md_lookup_swap(&nd->swap_saddr,lookup_path,nd->swap_fh,
1049 			     &nd->swap_fhsize, &nd->swap_args,procp);
1050       if (error)
1051 	panic("nfs_boot: lookup swap, error=%d", error);
1052     }
1053     nfs_diskless_valid = 3;
1054   }
1055 
1056 
1057   bcopy(&myaddr,&nd->myif.ifra_addr,sizeof(myaddr));
1058   bcopy(&myaddr,&nd->myif.ifra_broadaddr,sizeof(myaddr));
1059   ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
1060     myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
1061   bcopy(&netmask,&nd->myif.ifra_mask,sizeof(netmask));
1062 
1063 #if 0
1064   bootpboot_p_iflist();
1065   bootpboot_p_rtlist();
1066 #endif
1067   return;
1068 }
1069 
1070 /*
1071  * RPC: mountd/mount
1072  * Given a server pathname, get an NFS file handle.
1073  * Also, sets sin->sin_port to the NFS service port.
1074  */
1075 static int
1076 md_mount(mdsin, path, fhp, fhsizep, args, procp)
1077 	struct sockaddr_in *mdsin;		/* mountd server address */
1078 	char *path;
1079 	u_char *fhp;
1080 	int *fhsizep;
1081 	struct nfs_args *args;
1082 	struct proc *procp;
1083 {
1084 	struct mbuf *m;
1085 	int error;
1086 	int authunixok;
1087 	int authcount;
1088 	int authver;
1089 
1090 #ifdef BOOTP_NFSV3
1091 	/* First try NFS v3 */
1092 	/* Get port number for MOUNTD. */
1093 	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1094 						 &mdsin->sin_port, procp);
1095 	if (!error) {
1096 	  m = xdr_string_encode(path, strlen(path));
1097 
1098 	  /* Do RPC to mountd. */
1099 	  error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1100 			    RPCMNT_MOUNT, &m, NULL, curproc);
1101 	}
1102 	if (!error) {
1103 	  args->flags |= NFSMNT_NFSV3;
1104 	} else {
1105 #endif
1106 	  /* Fallback to NFS v2 */
1107 
1108 	  /* Get port number for MOUNTD. */
1109 	  error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1110 			       &mdsin->sin_port, procp);
1111 	  if (error) return error;
1112 
1113 	  m = xdr_string_encode(path, strlen(path));
1114 
1115 	  /* Do RPC to mountd. */
1116 	  error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1117 			    RPCMNT_MOUNT, &m, NULL, curproc);
1118 	  if (error)
1119 	    return error;	/* message already freed */
1120 
1121 #ifdef BOOTP_NFSV3
1122 	}
1123 #endif
1124 
1125 	if (xdr_int_decode(&m,&error) || error)
1126 	  goto bad;
1127 
1128 	if (args->flags & NFSMNT_NFSV3) {
1129 	  if (xdr_int_decode(&m,fhsizep) ||
1130 	      *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0 )
1131 	    goto bad;
1132 	} else
1133 	  *fhsizep = NFSX_V2FH;
1134 
1135 	if (xdr_opaque_decode(&m,fhp,*fhsizep))
1136 	  goto bad;
1137 
1138 	if (args->flags & NFSMNT_NFSV3) {
1139 	  if (xdr_int_decode(&m,&authcount))
1140 	    goto bad;
1141 	  authunixok = 0;
1142 	  if (authcount<0 || authcount>100)
1143 	    goto bad;
1144 	  while (authcount>0) {
1145 	    if (xdr_int_decode(&m,&authver))
1146 	      goto bad;
1147 	    if (authver == RPCAUTH_UNIX)
1148 	      authunixok = 1;
1149 	    authcount--;
1150 	  }
1151 	  if (!authunixok)
1152 	    goto bad;
1153 	}
1154 
1155 	/* Set port number for NFS use. */
1156 	error = krpc_portmap(mdsin, NFS_PROG,
1157 			     (args->flags & NFSMNT_NFSV3)?NFS_VER3:NFS_VER2,
1158 			     &mdsin->sin_port, procp);
1159 
1160 	goto out;
1161 
1162 bad:
1163 	error = EBADRPC;
1164 
1165 out:
1166 	m_freem(m);
1167 	return error;
1168 }
1169 
1170 
1171 static int md_lookup_swap(mdsin, path, fhp, fhsizep, args, procp)
1172 	struct sockaddr_in *mdsin;		/* mountd server address */
1173 	char *path;
1174 	u_char *fhp;
1175 	int *fhsizep;
1176 	struct nfs_args *args;
1177 	struct proc *procp;
1178 {
1179 	struct mbuf *m;
1180 	int error;
1181 	int size = -1;
1182 	int attribs_present;
1183 	int status;
1184 	union {
1185 	  u_int32_t v2[17];
1186 	  u_int32_t v3[21];
1187 	} fattribs;
1188 
1189 	m = m_get(M_WAIT,MT_DATA);
1190 	if (!m)
1191 	  	return ENOBUFS;
1192 
1193 	if (args->flags & NFSMNT_NFSV3) {
1194 	  *mtod(m,u_int32_t *) = txdr_unsigned(*fhsizep);
1195 	  bcopy(fhp,mtod(m,u_char *)+sizeof(u_int32_t),*fhsizep);
1196 	  m->m_len = *fhsizep + sizeof(u_int32_t);
1197 	} else {
1198 	  bcopy(fhp,mtod(m,u_char *),NFSX_V2FH);
1199 	  m->m_len = NFSX_V2FH;
1200 	}
1201 
1202 	m->m_next = xdr_string_encode(path, strlen(path));
1203 	if (!m->m_next) {
1204 	  error = ENOBUFS;
1205 	  goto out;
1206 	}
1207 
1208 	/* Do RPC to nfsd. */
1209 	if (args->flags & NFSMNT_NFSV3)
1210 	  error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
1211 			    NFSPROC_LOOKUP, &m, NULL, procp);
1212 	else
1213 	  error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
1214 			    NFSV2PROC_LOOKUP, &m, NULL, procp);
1215 	if (error)
1216 	  return error;	/* message already freed */
1217 
1218 	if (xdr_int_decode(&m,&status))
1219 	  goto bad;
1220 	if (status) {
1221 	  error = ENOENT;
1222 	  goto out;
1223 	}
1224 
1225 	if (args->flags & NFSMNT_NFSV3) {
1226 	  if (xdr_int_decode(&m,fhsizep) ||
1227 	      *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0 )
1228 	    goto bad;
1229 	} else
1230 	  *fhsizep = NFSX_V2FH;
1231 
1232 	if (xdr_opaque_decode(&m, fhp, *fhsizep))
1233 	  goto bad;
1234 
1235 	if (args->flags & NFSMNT_NFSV3) {
1236 	  if (xdr_int_decode(&m,&attribs_present))
1237 	    goto bad;
1238 	  if (attribs_present) {
1239 	    if (xdr_opaque_decode(&m,(u_char *) &fattribs.v3,
1240 				  sizeof(u_int32_t)*21))
1241 	      goto bad;
1242 	    size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
1243 	  }
1244 	} else {
1245   	  if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
1246 				sizeof(u_int32_t)*17))
1247 	    goto bad;
1248 	  size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
1249 	}
1250 
1251 	if (!nfsv3_diskless.swap_nblks && size!= -1) {
1252 	  nfsv3_diskless.swap_nblks = size/1024;
1253 	  printf("md_lookup_swap: Swap size is %d KB\n",
1254 		 nfsv3_diskless.swap_nblks);
1255 	}
1256 
1257 	goto out;
1258 
1259 bad:
1260 	error = EBADRPC;
1261 
1262 out:
1263 	m_freem(m);
1264 	return error;
1265 }
1266