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