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