Deleted Added
sdiff udiff text old ( 26581 ) new ( 28270 )
full compact
1/* $Id: bootp_subr.c,v 1.3 1997/05/14 01:31:54 tegge 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 MIN_REPLY_HDR 16 /* xid, dir, astat, errno */
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
133int bootpc_call(struct bootp_packet *call,
134 struct bootp_packet *reply,
135 struct proc *procp);
136
137int bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so,
138 struct proc *procp);
139
140int
141bootpc_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
147void bootpc_init(void);
148
149#ifdef BOOTP_DEBUG
150void 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
186void 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
196void 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}
209void 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
228void bootpboot_p_rtlist(void)
229{
230 printf("Routing table:\n");
231 bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop);
232}
233
234void 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
256int
257bootpc_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, procp)))
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, procp)))
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, procp);
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 /* Does the reply contain at least a header? */
404 if (len < MIN_REPLY_HDR)
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
435int
436bootpc_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
525int
526bootpc_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
605static 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
638static int getdec(ptr)
639 char **ptr;
640{
641 char *p = *ptr;
642 int ret=0;
643 if ((*p < '0') || (*p > '9')) return(-1);
644 while ((*p >= '0') && (*p <= '9')) {
645 ret = ret*10 + (*p - '0');
646 p++;
647 }
648 *ptr = p;
649 return(ret);
650}
651
652static 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
671static 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
693static 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
717static 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
728static 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
738void
739bootpc_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 = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link))
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 = TAILQ_FIRST(&ifp->if_addrhead) ;ifa;
809 ifa=TAILQ_NEXT(ifa,ifa_link))
810 if (ifa->ifa_addr->sa_family == AF_LINK &&
811 (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
812 sdl->sdl_type == IFT_ETHER)
813 break;
814
815 if (!sdl)
816 panic("bootpc: Unable to find HW address");
817 if (sdl->sdl_alen != EALEN )
818 panic("bootpc: HW address len is %d, expected value is %d",
819 sdl->sdl_alen,EALEN);
820
821 printf("bootpc hw address is ");
822 delim="";
823 for (j=0;j<sdl->sdl_alen;j++) {
824 printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]);
825 delim=":";
826 }
827 printf("\n");
828
829#if 0
830 bootpboot_p_iflist();
831 bootpboot_p_rtlist();
832#endif
833
834 bzero((caddr_t) &call, sizeof(call));
835
836 /* bootpc part */
837 call.op = 1; /* BOOTREQUEST */
838 call.htype= 1; /* 10mb ethernet */
839 call.hlen=sdl->sdl_alen; /* Hardware address length */
840 call.hops=0;
841 xid++;
842 call.xid = txdr_unsigned(xid);
843 bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen);
844
845 call.vend[0]=99;
846 call.vend[1]=130;
847 call.vend[2]=83;
848 call.vend[3]=99;
849 call.vend[4]=255;
850
851 call.secs = 0;
852 call.flags = htons(0x8000); /* We need an broadcast answer */
853
854 error = bootpc_call(&call,&reply,procp);
855
856 if (error) {
857#ifdef BOOTP_NFSROOT
858 panic("BOOTP call failed");
859#endif
860 return;
861 }
862
863 bzero(&myaddr,sizeof(myaddr));
864 bzero(&netmask,sizeof(netmask));
865 bzero(&gw,sizeof(gw));
866
867 myaddr.sin_len = sizeof(myaddr);
868 myaddr.sin_family = AF_INET;
869
870 netmask.sin_len = sizeof(netmask);
871 netmask.sin_family = AF_INET;
872
873 gw.sin_len = sizeof(gw);
874 gw.sin_family= AF_INET;
875
876 nd->root_args.version = NFS_ARGSVERSION;
877 nd->root_args.rsize = 8192;
878 nd->root_args.wsize = 8192;
879 nd->root_args.sotype = SOCK_DGRAM;
880 nd->root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT);
881
882 nd->swap_saddr.sin_len = sizeof(gw);
883 nd->swap_saddr.sin_family = AF_INET;
884
885 nd->swap_args.version = NFS_ARGSVERSION;
886 nd->swap_args.rsize = 8192;
887 nd->swap_args.wsize = 8192;
888 nd->swap_args.sotype = SOCK_DGRAM;
889 nd->swap_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT);
890
891 myaddr.sin_addr = reply.yiaddr;
892
893 ip = ntohl(myaddr.sin_addr.s_addr);
894 sprintf(lookup_path,"swap.%d.%d.%d.%d",
895 ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 );
896
897 printip("My ip address",myaddr.sin_addr);
898
899 printip("Server ip address",reply.siaddr);
900
901 gw.sin_addr = reply.giaddr;
902 printip("Gateway ip address",reply.giaddr);
903
904 if (reply.sname[0])
905 printf("Server name is %s\n",reply.sname);
906 if (reply.file[0])
907 printf("boot file is %s\n",reply.file);
908 if (reply.vend[0]==99 && reply.vend[1]==130 &&
909 reply.vend[2]==83 && reply.vend[3]==99) {
910 j=4;
911 ncode = reply.vend[j];
912 while (j<sizeof(reply.vend)) {
913 code = reply.vend[j] = ncode;
914 if (code==255)
915 break;
916 if (code==0) {
917 j++;
918 continue;
919 }
920 len = reply.vend[j+1];
921 j+=2;
922 if (len+j>=sizeof(reply.vend)) {
923 printf("Truncated field");
924 break;
925 }
926 ncode = reply.vend[j+len];
927 reply.vend[j+len]='\0';
928 p = &reply.vend[j];
929 switch (code) {
930 case 1:
931 if (len!=4)
932 panic("bootpc: subnet mask len is %d",len);
933 bcopy(&reply.vend[j],&netmask.sin_addr,4);
934 gotnetmask=1;
935 printip("Subnet mask",netmask.sin_addr);
936 break;
937 case 6: /* Domain Name servers. Unused */
938 case 16: /* Swap server IP address. unused */
939 case 2:
940 /* Time offset */
941 break;
942 case 3:
943 /* Routers */
944 if (len % 4)
945 panic("bootpc: Router Len is %d",len);
946 if (len > 0) {
947 bcopy(&reply.vend[j],&gw.sin_addr,4);
948 printip("Router",gw.sin_addr);
949 gotgw=1;
950 }
951 break;
952 case 17:
953 if (setfs(&nd->root_saddr, nd->root_hostnam, p)) {
954 printf("rootfs is %s\n",p);
955 gotrootpath=1;
956 } else
957 panic("Failed to set rootfs to %s",p);
958 break;
959 case 12:
960 if (len>=MAXHOSTNAMELEN)
961 panic("bootpc: hostname >=%d bytes",MAXHOSTNAMELEN);
962 strncpy(nd->my_hostnam,&reply.vend[j],len);
963 nd->my_hostnam[len]=0;
964 strncpy(hostname,&reply.vend[j],len);
965 hostname[len]=0;
966 printf("Hostname is %s\n",hostname);
967 break;
968 case 128:
969 if (setfs(&nd->swap_saddr, nd->swap_hostnam, p)) {
970 gotswappath=1;
971 printf("swapfs is %s\n",p);
972 } else
973 panic("Failed to set swapfs to %s",p);
974 break;
975 case 129:
976 {
977 int swaplen;
978 if (len!=4)
979 panic("bootpc: Expected 4 bytes for swaplen, not %d bytes",len);
980 bcopy(&reply.vend[j],&swaplen,4);
981 nd->swap_nblks = ntohl(swaplen);
982 printf("bootpc: Swap size is %d KB\n",nd->swap_nblks);
983 }
984 break;
985 case 130: /* root mount options */
986 mountopts(&nd->root_args,p);
987 break;
988 case 131: /* swap mount options */
989 mountopts(&nd->swap_args,p);
990 break;
991 default:
992 printf("Ignoring field type %d\n",code);
993 }
994 j+=len;
995 }
996 }
997
998 if (!gotswappath)
999 nd->swap_nblks = 0;
1000#ifdef BOOTP_NFSROOT
1001 if (!gotrootpath)
1002 panic("bootpc: No root path offered");
1003#endif
1004
1005 if (!gotnetmask) {
1006 if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr)))
1007 netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1008 else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr)))
1009 netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1010 else
1011 netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1012 }
1013 if (!gotgw) {
1014 /* Use proxyarp */
1015 gw.sin_addr.s_addr = myaddr.sin_addr.s_addr;
1016 }
1017
1018#if 0
1019 bootpboot_p_iflist();
1020 bootpboot_p_rtlist();
1021#endif
1022 error = bootpc_adjust_interface(&ireq,so,
1023 &myaddr,&netmask,&gw,procp);
1024
1025 soclose(so);
1026
1027#if 0
1028 bootpboot_p_iflist();
1029 bootpboot_p_rtlist();
1030#endif
1031
1032 if (gotrootpath) {
1033
1034 error = md_mount(&nd->root_saddr, nd->root_hostnam,
1035 nd->root_fh, &nd->root_fhsize,
1036 &nd->root_args,procp);
1037 if (error)
1038 panic("nfs_boot: mountd root, error=%d", error);
1039
1040 if (gotswappath) {
1041
1042 error = md_mount(&nd->swap_saddr,
1043 nd->swap_hostnam,
1044 nd->swap_fh, &nd->swap_fhsize,&nd->swap_args,procp);
1045 if (error)
1046 panic("nfs_boot: mountd swap, error=%d", error);
1047
1048 error = md_lookup_swap(&nd->swap_saddr,lookup_path,nd->swap_fh,
1049 &nd->swap_fhsize, &nd->swap_args,procp);
1050 if (error)
1051 panic("nfs_boot: lookup swap, error=%d", error);
1052 }
1053 nfs_diskless_valid = 3;
1054 }
1055
1056
1057 bcopy(&myaddr,&nd->myif.ifra_addr,sizeof(myaddr));
1058 bcopy(&myaddr,&nd->myif.ifra_broadaddr,sizeof(myaddr));
1059 ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
1060 myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
1061 bcopy(&netmask,&nd->myif.ifra_mask,sizeof(netmask));
1062
1063#if 0
1064 bootpboot_p_iflist();
1065 bootpboot_p_rtlist();
1066#endif
1067 return;
1068}
1069
1070/*
1071 * RPC: mountd/mount
1072 * Given a server pathname, get an NFS file handle.
1073 * Also, sets sin->sin_port to the NFS service port.
1074 */
1075static int
1076md_mount(mdsin, path, fhp, fhsizep, args, procp)
1077 struct sockaddr_in *mdsin; /* mountd server address */
1078 char *path;
1079 u_char *fhp;
1080 int *fhsizep;
1081 struct nfs_args *args;
1082 struct proc *procp;
1083{
1084 struct mbuf *m;
1085 int error;
1086 int authunixok;
1087 int authcount;
1088 int authver;
1089
1090#ifdef BOOTP_NFSV3
1091 /* First try NFS v3 */
1092 /* Get port number for MOUNTD. */
1093 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1094 &mdsin->sin_port, procp);
1095 if (!error) {
1096 m = xdr_string_encode(path, strlen(path));
1097
1098 /* Do RPC to mountd. */
1099 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1100 RPCMNT_MOUNT, &m, NULL, curproc);
1101 }
1102 if (!error) {
1103 args->flags |= NFSMNT_NFSV3;
1104 } else {
1105#endif
1106 /* Fallback to NFS v2 */
1107
1108 /* Get port number for MOUNTD. */
1109 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1110 &mdsin->sin_port, procp);
1111 if (error) return error;
1112
1113 m = xdr_string_encode(path, strlen(path));
1114
1115 /* Do RPC to mountd. */
1116 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1117 RPCMNT_MOUNT, &m, NULL, curproc);
1118 if (error)
1119 return error; /* message already freed */
1120
1121#ifdef BOOTP_NFSV3
1122 }
1123#endif
1124
1125 if (xdr_int_decode(&m,&error) || error)
1126 goto bad;
1127
1128 if (args->flags & NFSMNT_NFSV3) {
1129 if (xdr_int_decode(&m,fhsizep) ||
1130 *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0 )
1131 goto bad;
1132 } else
1133 *fhsizep = NFSX_V2FH;
1134
1135 if (xdr_opaque_decode(&m,fhp,*fhsizep))
1136 goto bad;
1137
1138 if (args->flags & NFSMNT_NFSV3) {
1139 if (xdr_int_decode(&m,&authcount))
1140 goto bad;
1141 authunixok = 0;
1142 if (authcount<0 || authcount>100)
1143 goto bad;
1144 while (authcount>0) {
1145 if (xdr_int_decode(&m,&authver))
1146 goto bad;
1147 if (authver == RPCAUTH_UNIX)
1148 authunixok = 1;
1149 authcount--;
1150 }
1151 if (!authunixok)
1152 goto bad;
1153 }
1154
1155 /* Set port number for NFS use. */
1156 error = krpc_portmap(mdsin, NFS_PROG,
1157 (args->flags & NFSMNT_NFSV3)?NFS_VER3:NFS_VER2,
1158 &mdsin->sin_port, procp);
1159
1160 goto out;
1161
1162bad:
1163 error = EBADRPC;
1164
1165out:
1166 m_freem(m);
1167 return error;
1168}
1169
1170
1171static int md_lookup_swap(mdsin, path, fhp, fhsizep, args, procp)
1172 struct sockaddr_in *mdsin; /* mountd server address */
1173 char *path;
1174 u_char *fhp;
1175 int *fhsizep;
1176 struct nfs_args *args;
1177 struct proc *procp;
1178{
1179 struct mbuf *m;
1180 int error;
1181 int size = -1;
1182 int attribs_present;
1183 int status;
1184 union {
1185 u_int32_t v2[17];
1186 u_int32_t v3[21];
1187 } fattribs;
1188
1189 m = m_get(M_WAIT,MT_DATA);
1190 if (!m)
1191 return ENOBUFS;
1192
1193 if (args->flags & NFSMNT_NFSV3) {
1194 *mtod(m,u_int32_t *) = txdr_unsigned(*fhsizep);
1195 bcopy(fhp,mtod(m,u_char *)+sizeof(u_int32_t),*fhsizep);
1196 m->m_len = *fhsizep + sizeof(u_int32_t);
1197 } else {
1198 bcopy(fhp,mtod(m,u_char *),NFSX_V2FH);
1199 m->m_len = NFSX_V2FH;
1200 }
1201
1202 m->m_next = xdr_string_encode(path, strlen(path));
1203 if (!m->m_next) {
1204 error = ENOBUFS;
1205 goto out;
1206 }
1207
1208 /* Do RPC to nfsd. */
1209 if (args->flags & NFSMNT_NFSV3)
1210 error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
1211 NFSPROC_LOOKUP, &m, NULL, procp);
1212 else
1213 error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
1214 NFSV2PROC_LOOKUP, &m, NULL, procp);
1215 if (error)
1216 return error; /* message already freed */
1217
1218 if (xdr_int_decode(&m,&status))
1219 goto bad;
1220 if (status) {
1221 error = ENOENT;
1222 goto out;
1223 }
1224
1225 if (args->flags & NFSMNT_NFSV3) {
1226 if (xdr_int_decode(&m,fhsizep) ||
1227 *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0 )
1228 goto bad;
1229 } else
1230 *fhsizep = NFSX_V2FH;
1231
1232 if (xdr_opaque_decode(&m, fhp, *fhsizep))
1233 goto bad;
1234
1235 if (args->flags & NFSMNT_NFSV3) {
1236 if (xdr_int_decode(&m,&attribs_present))
1237 goto bad;
1238 if (attribs_present) {
1239 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v3,
1240 sizeof(u_int32_t)*21))
1241 goto bad;
1242 size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
1243 }
1244 } else {
1245 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
1246 sizeof(u_int32_t)*17))
1247 goto bad;
1248 size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
1249 }
1250
1251 if (!nfsv3_diskless.swap_nblks && size!= -1) {
1252 nfsv3_diskless.swap_nblks = size/1024;
1253 printf("md_lookup_swap: Swap size is %d KB\n",
1254 nfsv3_diskless.swap_nblks);
1255 }
1256
1257 goto out;
1258
1259bad:
1260 error = EBADRPC;
1261
1262out:
1263 m_freem(m);
1264 return error;
1265}