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