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