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