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