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