LINT build test. Aggregated source code adjustments to bring most of the
[dragonfly.git] / sys / vfs / nfs / bootp_subr.c
1 /* $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.9 2003/04/24 16:51:08 ambrisko Exp $     */
2 /* $DragonFly: src/sys/vfs/nfs/bootp_subr.c,v 1.4 2003/07/21 07:57:51 dillon Exp $      */
3
4 /*
5  * Copyright (c) 1995 Gordon Ross, Adam Glass
6  * Copyright (c) 1992 Regents of the University of California.
7  * All rights reserved.
8  *
9  * This software was developed by the Computer Systems Engineering group
10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
11  * contributed to Berkeley.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *      This product includes software developed by the University of
24  *      California, Lawrence Berkeley Laboratory and its contributors.
25  * 4. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  * based on:
42  *      nfs/krpc_subr.c
43  *      $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
44  */
45
46 #include "opt_bootp.h"
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/sockio.h>
52 #include <sys/proc.h>
53 #include <sys/malloc.h>
54 #include <sys/mount.h>
55 #include <sys/mbuf.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/sysctl.h>
59 #include <sys/uio.h>
60
61 #include <net/if.h>
62 #include <net/route.h>
63
64 #include <netinet/in.h>
65 #include <net/if_types.h>
66 #include <net/if_dl.h>
67
68 #include <nfs/rpcv2.h>
69 #include <nfs/nfsproto.h>
70 #include <nfs/nfs.h>
71 #include <nfs/nfsdiskless.h>
72 #include <nfs/krpc.h>
73 #include <nfs/xdr_subs.h>
74
75
76 #define BOOTP_MIN_LEN           300     /* Minimum size of bootp udp packet */
77
78 #ifndef BOOTP_SETTLE_DELAY
79 #define BOOTP_SETTLE_DELAY 3
80 #endif
81
82 /*
83  * What is the longest we will wait before re-sending a request?
84  * Note this is also the frequency of "RPC timeout" messages.
85  * The re-send loop count sup linearly to this maximum, so the
86  * first complaint will happen after (1+2+3+4+5)=15 seconds.
87  */
88 #define MAX_RESEND_DELAY 5      /* seconds */
89
90 /* Definitions from RFC951 */
91 struct bootp_packet {
92         u_int8_t op;
93         u_int8_t htype;
94         u_int8_t hlen;
95         u_int8_t hops;
96         u_int32_t xid;
97         u_int16_t secs;
98         u_int16_t flags;
99         struct in_addr ciaddr;
100         struct in_addr yiaddr;
101         struct in_addr siaddr;
102         struct in_addr giaddr;
103         unsigned char chaddr[16];
104         char sname[64];
105         char file[128];
106         unsigned char vend[1222];
107 };
108
109 struct bootpc_ifcontext {
110         struct bootpc_ifcontext *next;
111         struct bootp_packet call;
112         struct bootp_packet reply;
113         int replylen;
114         int overload;
115         struct socket *so;
116         struct ifreq ireq;
117         struct ifnet *ifp;
118         struct sockaddr_dl *sdl;
119         struct sockaddr_in myaddr;
120         struct sockaddr_in netmask;
121         struct sockaddr_in gw;
122         struct sockaddr_in broadcast;   /* Different for each interface */
123         int gotgw;
124         int gotnetmask;
125         int gotrootpath;
126         int outstanding;
127         int sentmsg;
128         u_int32_t xid;
129         enum {
130                 IF_BOOTP_UNRESOLVED,
131                 IF_BOOTP_RESOLVED,
132                 IF_BOOTP_FAILED,
133                 IF_DHCP_UNRESOLVED,
134                 IF_DHCP_OFFERED,
135                 IF_DHCP_RESOLVED,
136                 IF_DHCP_FAILED,
137         } state;
138         int dhcpquerytype;              /* dhcp type sent */
139         struct in_addr dhcpserver;
140         int gotdhcpserver;
141 };
142
143 #define TAG_MAXLEN 1024
144 struct bootpc_tagcontext {
145         char buf[TAG_MAXLEN + 1];
146         int overload;
147         int badopt;
148         int badtag;
149         int foundopt;
150         int taglen;
151 };
152
153 struct bootpc_globalcontext {
154         struct bootpc_ifcontext *interfaces;
155         struct bootpc_ifcontext *lastinterface;
156         u_int32_t xid;
157         int gotrootpath;
158         int gotswappath;
159         int gotgw;
160         int ifnum;
161         int secs;
162         int starttime;
163         struct bootp_packet reply;
164         int replylen;
165         struct bootpc_ifcontext *setswapfs;
166         struct bootpc_ifcontext *setrootfs;
167         struct bootpc_ifcontext *sethostname;
168         char lookup_path[24];
169         struct bootpc_tagcontext tmptag;
170         struct bootpc_tagcontext tag;
171 };
172
173 #define IPPORT_BOOTPC 68
174 #define IPPORT_BOOTPS 67
175
176 #define BOOTP_REQUEST 1
177 #define BOOTP_REPLY 2
178
179 /* Common tags */
180 #define TAG_PAD           0  /* Pad option, implicit length 1 */
181 #define TAG_SUBNETMASK    1  /* RFC 950 subnet mask */
182 #define TAG_ROUTERS       3  /* Routers (in order of preference) */
183 #define TAG_HOSTNAME     12  /* Client host name */
184 #define TAG_ROOT         17  /* Root path */
185
186 /* DHCP specific tags */
187 #define TAG_OVERLOAD     52  /* Option Overload */
188 #define TAG_MAXMSGSIZE   57  /* Maximum DHCP Message Size */
189
190 #define TAG_END         255  /* End Option (i.e. no more options) */
191
192 /* Overload values */
193 #define OVERLOAD_FILE     1
194 #define OVERLOAD_SNAME    2
195
196 /* Site specific tags: */
197 #define TAG_SWAP        128
198 #define TAG_SWAPSIZE    129
199 #define TAG_ROOTOPTS    130
200 #define TAG_SWAPOPTS    131
201 #define TAG_COOKIE      134     /* ascii info for userland, exported via sysctl */
202
203 #define TAG_DHCP_MSGTYPE 53
204 #define TAG_DHCP_REQ_ADDR 50
205 #define TAG_DHCP_SERVERID 54
206 #define TAG_DHCP_LEASETIME 51
207
208 #define TAG_VENDOR_INDENTIFIER 60
209
210 #define DHCP_NOMSG    0
211 #define DHCP_DISCOVER 1
212 #define DHCP_OFFER    2
213 #define DHCP_REQUEST  3
214 #define DHCP_ACK      5
215
216 extern int nfs_diskless_valid;
217 extern struct nfsv3_diskless nfsv3_diskless;
218 static char bootp_cookie[128];
219 SYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD,
220         bootp_cookie, 0, "Cookie (T134) supplied by bootp server");
221
222 /* mountd RPC */
223 static int md_mount(struct sockaddr_in *mdsin, char *path,
224                     u_char *fhp, int *fhsizep,
225                     struct nfs_args *args,struct thread *td);
226 static int md_lookup_swap(struct sockaddr_in *mdsin,char *path,
227                           u_char *fhp, int *fhsizep,
228                           struct nfs_args *args,
229                           struct thread *td);
230 static int setfs(struct sockaddr_in *addr, char *path, char *p);
231 static int getdec(char **ptr);
232 static char *substr(char *a,char *b);
233 static void mountopts(struct nfs_args *args, char *p);
234 static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
235 static int xdr_int_decode(struct mbuf **ptr, int *iptr);
236 static void print_in_addr(struct in_addr addr);
237 static void print_sin_addr(struct sockaddr_in *addr);
238 static void clear_sinaddr(struct sockaddr_in *sin);
239 static
240 struct bootpc_ifcontext *allocifctx(struct bootpc_globalcontext *gctx);
241 static void bootpc_compose_query(struct bootpc_ifcontext *ifctx,
242                                  struct bootpc_globalcontext *gctx,
243                                  struct thread *td);
244 static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx,
245                                  struct bootp_packet *bp, int len, int tag);
246 static void bootpc_tag_helper(struct bootpc_tagcontext *tctx,
247                               unsigned char *start, int len, int tag);
248
249 #ifdef BOOTP_DEBUG
250 void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma);
251 void bootpboot_p_ma(struct sockaddr *ma);
252 void bootpboot_p_rtentry(struct rtentry *rt);
253 void bootpboot_p_tree(struct radix_node *rn);
254 void bootpboot_p_rtlist(void);
255 void bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa);
256 void bootpboot_p_iflist(void);
257 #endif
258
259 static int  bootpc_call(struct bootpc_globalcontext *gctx,
260                         struct thread *td);
261
262 static int bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
263                                    struct bootpc_globalcontext *gctx,
264                                    struct thread *td);
265
266 static int bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
267                                    struct bootpc_globalcontext *gctx,
268                                    struct thread *td);
269
270 static void bootpc_decode_reply(struct nfsv3_diskless *nd,
271                                 struct bootpc_ifcontext *ifctx,
272                                 struct bootpc_globalcontext *gctx);
273
274 static int bootpc_received(struct bootpc_globalcontext *gctx,
275                            struct bootpc_ifcontext *ifctx);
276
277 static __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx);
278 static __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx);
279 static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx);
280
281 void bootpc_init(void);
282
283 /*
284  * In order to have multiple active interfaces with address 0.0.0.0
285  * and be able to send data to a selected interface, we perform
286  * some tricks:
287  * 
288  *  - The 'broadcast' address is different for each interface.
289  *
290  *  - We temporarily add routing pointing 255.255.255.255 to the
291  *    selected interface broadcast address, thus the packet sent
292  *    goes to that interface.
293  */
294
295 #ifdef BOOTP_DEBUG
296 void
297 bootpboot_p_sa(struct sockaddr *sa,
298                struct sockaddr *ma)
299 {
300         if (sa == NULL) {
301                 printf("(sockaddr *) <null>");
302                 return;
303         }
304         switch (sa->sa_family) {
305         case AF_INET:
306         {
307                 struct sockaddr_in *sin;
308                 
309                 sin = (struct sockaddr_in *) sa;
310                 printf("inet ");
311                 print_sin_addr(sin);
312                 if (ma != NULL) {
313                         sin = (struct sockaddr_in *) ma;
314                         printf(" mask ");
315                         print_sin_addr(sin);
316                 }
317         }
318         break;
319         case AF_LINK:
320         {
321                 struct sockaddr_dl *sli;
322                 int i;
323                 
324                 sli = (struct sockaddr_dl *) sa;
325                 printf("link %.*s ", sli->sdl_nlen, sli->sdl_data);
326                 for (i = 0; i < sli->sdl_alen; i++) {
327                         if (i > 0)
328                                 printf(":");
329                         printf("%x", ((unsigned char *) LLADDR(sli))[i]);
330                 }
331         }
332         break;
333         default:
334                 printf("af%d", sa->sa_family);
335         }
336 }
337
338
339 void
340 bootpboot_p_ma(struct sockaddr *ma)
341 {
342         if (ma == NULL) {
343                 printf("<null>");
344                 return;
345         }
346         printf("%x", *(int *)ma);
347 }
348
349
350 void
351 bootpboot_p_rtentry(struct rtentry *rt)
352 {
353         bootpboot_p_sa(rt_key(rt), rt_mask(rt));
354         printf(" ");
355         bootpboot_p_ma(rt->rt_genmask);
356         printf(" ");
357         bootpboot_p_sa(rt->rt_gateway, NULL);
358         printf(" ");
359         printf("flags %x", (unsigned short) rt->rt_flags);
360         printf(" %d", (int) rt->rt_rmx.rmx_expire);
361         printf(" %s%d\n", rt->rt_ifp->if_name, rt->rt_ifp->if_unit);
362 }
363
364
365 void
366 bootpboot_p_tree(struct radix_node *rn)
367 {
368         while (rn != NULL) {
369                 if (rn->rn_bit < 0) {
370                         if ((rn->rn_flags & RNF_ROOT) != 0) {
371                         } else {
372                                 bootpboot_p_rtentry((struct rtentry *) rn);
373                         }
374                         rn = rn->rn_dupedkey;
375                 } else {
376                         bootpboot_p_tree(rn->rn_left);
377                         bootpboot_p_tree(rn->rn_right);
378                         return;
379                 }
380         }
381 }
382
383
384 void
385 bootpboot_p_rtlist(void)
386 {
387         printf("Routing table:\n");
388         bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop);
389 }
390
391
392 void
393 bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa)
394 {
395         printf("%s%d flags %x, addr ",
396                ifp->if_name,
397                ifp->if_unit,
398                (unsigned short) ifp->if_flags);
399         print_sin_addr((struct sockaddr_in *) ifa->ifa_addr);
400         printf(", broadcast ");
401         print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr);
402         printf(", netmask ");
403         print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask);
404         printf("\n");
405 }
406
407
408 void
409 bootpboot_p_iflist(void)
410 {
411         struct ifnet *ifp;
412         struct ifaddr *ifa;
413         
414         printf("Interface list:\n");
415         for (ifp = TAILQ_FIRST(&ifnet);
416              ifp != NULL;
417              ifp = TAILQ_NEXT(ifp, if_link)) {
418                 for (ifa = TAILQ_FIRST(&ifp->if_addrhead);
419                      ifa != NULL;
420                      ifa = TAILQ_NEXT(ifa, ifa_link))
421                         if (ifa->ifa_addr->sa_family == AF_INET)
422                                 bootpboot_p_if(ifp, ifa);
423         }
424 }
425 #endif /* defined(BOOTP_DEBUG) */
426
427
428 static void
429 clear_sinaddr(struct sockaddr_in *sin)
430 {
431         bzero(sin, sizeof(*sin));
432         sin->sin_len = sizeof(*sin);
433         sin->sin_family = AF_INET;
434         sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */
435         sin->sin_port = 0;
436 }
437
438
439 static struct bootpc_ifcontext *
440 allocifctx(struct bootpc_globalcontext *gctx)
441 {
442         struct bootpc_ifcontext *ifctx;
443         ifctx = (struct bootpc_ifcontext *) malloc(sizeof(*ifctx),
444                                                    M_TEMP, M_WAITOK);
445         if (ifctx == NULL)
446                 panic("Failed to allocate bootp interface context structure");
447         
448         bzero(ifctx, sizeof(*ifctx));
449         ifctx->xid = gctx->xid;
450 #ifdef BOOTP_NO_DHCP
451         ifctx->state = IF_BOOTP_UNRESOLVED;
452 #else
453         ifctx->state = IF_DHCP_UNRESOLVED;
454 #endif
455         gctx->xid += 0x100;
456         return ifctx;
457 }
458
459
460 static __inline int
461 bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx)
462 {
463         if (ifctx->state == IF_BOOTP_RESOLVED ||
464             ifctx->state == IF_DHCP_RESOLVED)
465                 return 1;
466         return 0;
467 }
468
469
470 static __inline int
471 bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx)
472 {
473         if (ifctx->state == IF_BOOTP_UNRESOLVED ||
474             ifctx->state == IF_DHCP_UNRESOLVED)
475                 return 1;
476         return 0;
477 }
478
479
480 static __inline int
481 bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx)
482 {
483         if (ifctx->state == IF_BOOTP_FAILED ||
484             ifctx->state == IF_DHCP_FAILED)
485                 return 1;
486         return 0;
487 }
488
489
490 static int
491 bootpc_received(struct bootpc_globalcontext *gctx,
492                 struct bootpc_ifcontext *ifctx)
493 {
494         unsigned char dhcpreplytype;
495         char *p;
496         /*
497          * Need timeout for fallback to less
498          * desirable alternative.
499          */
500
501
502         /* This call used for the side effect (badopt flag) */
503         (void) bootpc_tag(&gctx->tmptag, &gctx->reply,
504                           gctx->replylen,
505                           TAG_END);
506
507         /* If packet is invalid, ignore it */
508         if (gctx->tmptag.badopt != 0)
509                 return 0;
510         
511         p = bootpc_tag(&gctx->tmptag, &gctx->reply,
512                        gctx->replylen, TAG_DHCP_MSGTYPE);
513         if (p != NULL)
514                 dhcpreplytype = *p;
515         else
516                 dhcpreplytype = DHCP_NOMSG;
517         
518         switch (ifctx->dhcpquerytype) {
519         case DHCP_DISCOVER:
520                 if (dhcpreplytype != DHCP_OFFER         /* Normal DHCP offer */
521 #ifndef BOOTP_FORCE_DHCP
522                     && dhcpreplytype != DHCP_NOMSG      /* Fallback to BOOTP */
523 #endif
524                         )
525                         return 0;
526                 break;
527         case DHCP_REQUEST:
528                 if (dhcpreplytype != DHCP_ACK)
529                         return 0;
530         case DHCP_NOMSG:
531         }
532                 
533         
534         /* Ignore packet unless it gives us a root tag we didn't have */
535         
536         if ((ifctx->state == IF_BOOTP_RESOLVED ||
537              (ifctx->dhcpquerytype == DHCP_DISCOVER &&
538               (ifctx->state == IF_DHCP_OFFERED ||
539                ifctx->state == IF_DHCP_RESOLVED))) &&
540             (bootpc_tag(&gctx->tmptag, &ifctx->reply,
541                         ifctx->replylen,
542                         TAG_ROOT) != NULL ||
543              bootpc_tag(&gctx->tmptag, &gctx->reply,
544                         gctx->replylen,
545                         TAG_ROOT) == NULL))
546                 return 0;
547         
548         bcopy(&gctx->reply,
549               &ifctx->reply,
550               gctx->replylen);
551         ifctx->replylen = gctx->replylen;
552         
553         /* XXX: Only reset if 'perfect' response */
554         if (ifctx->state == IF_BOOTP_UNRESOLVED)
555                 ifctx->state = IF_BOOTP_RESOLVED;
556         else if (ifctx->state == IF_DHCP_UNRESOLVED &&
557                  ifctx->dhcpquerytype == DHCP_DISCOVER) {
558                 if (dhcpreplytype == DHCP_OFFER)
559                         ifctx->state = IF_DHCP_OFFERED;
560                 else
561                         ifctx->state = IF_BOOTP_RESOLVED;       /* Fallback */
562         } else if (ifctx->state == IF_DHCP_OFFERED &&
563                    ifctx->dhcpquerytype == DHCP_REQUEST)
564                 ifctx->state = IF_DHCP_RESOLVED;
565         
566         
567         if (ifctx->dhcpquerytype == DHCP_DISCOVER &&
568             ifctx->state != IF_BOOTP_RESOLVED) {
569                 p = bootpc_tag(&gctx->tmptag, &ifctx->reply,
570                                ifctx->replylen, TAG_DHCP_SERVERID);
571                 if (p != NULL && gctx->tmptag.taglen == 4) {
572                         memcpy(&ifctx->dhcpserver, p, 4);
573                         ifctx->gotdhcpserver = 1;
574                 } else
575                         ifctx->gotdhcpserver = 0;
576                 return 1;
577         }
578         
579         ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
580                                          ifctx->replylen,
581                                          TAG_ROOT) != NULL);
582         ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
583                                    ifctx->replylen,
584                                    TAG_ROUTERS) != NULL);
585         ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
586                                         ifctx->replylen,
587                                         TAG_SUBNETMASK) != NULL);
588         return 1;
589 }
590
591 static int
592 bootpc_call(struct bootpc_globalcontext *gctx,
593             struct thread *td)
594 {
595         struct socket *so;
596         struct sockaddr_in *sin, dst;
597         struct uio auio;
598         struct sockopt sopt;
599         struct iovec aio;
600         int error, on, rcvflg, timo, len;
601         time_t atimo;
602         time_t rtimo;
603         struct timeval tv;
604         struct bootpc_ifcontext *ifctx;
605         int outstanding;
606         int gotrootpath;
607         int retry;
608         const char *s;
609         
610         /*
611          * Create socket and set its recieve timeout.
612          */
613         error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td);
614         if (error != 0)
615                 goto out;
616         
617         tv.tv_sec = 1;
618         tv.tv_usec = 0;
619         bzero(&sopt, sizeof(sopt));
620         sopt.sopt_level = SOL_SOCKET;
621         sopt.sopt_name = SO_RCVTIMEO;
622         sopt.sopt_val = &tv;
623         sopt.sopt_valsize = sizeof tv;
624         
625         error = sosetopt(so, &sopt);
626         if (error != 0)
627                 goto out;
628         
629         /*
630          * Enable broadcast.
631          */
632         on = 1;
633         sopt.sopt_name = SO_BROADCAST;
634         sopt.sopt_val = &on;
635         sopt.sopt_valsize = sizeof on;
636
637         error = sosetopt(so, &sopt);
638         if (error != 0)
639                 goto out;
640
641         /*
642          * Disable routing.
643          */
644
645         on = 1;
646         sopt.sopt_name = SO_DONTROUTE;
647         sopt.sopt_val = &on;
648         sopt.sopt_valsize = sizeof on;
649
650         error = sosetopt(so, &sopt);
651         if (error != 0)
652                 goto out;
653         
654         /*
655          * Bind the local endpoint to a bootp client port.
656          */
657         sin = &dst;
658         clear_sinaddr(sin);
659         sin->sin_port = htons(IPPORT_BOOTPC);
660         error = sobind(so, (struct sockaddr *)sin, td);
661         if (error != 0) {
662                 printf("bind failed\n");
663                 goto out;
664         }
665         
666         /*
667          * Setup socket address for the server.
668          */
669         sin = &dst;
670         clear_sinaddr(sin);
671         sin->sin_addr.s_addr = INADDR_BROADCAST;
672         sin->sin_port = htons(IPPORT_BOOTPS);
673         
674         /*
675          * Send it, repeatedly, until a reply is received,
676          * but delay each re-send by an increasing amount.
677          * If the delay hits the maximum, start complaining.
678          */
679         timo = 0;
680         rtimo = 0;
681         for (;;) {
682                 
683                 outstanding = 0;
684                 gotrootpath = 0;
685
686                 for (ifctx = gctx->interfaces;
687                      ifctx != NULL;
688                      ifctx = ifctx->next) {
689                         if (bootpc_ifctx_isresolved(ifctx) != 0 &&
690                             bootpc_tag(&gctx->tmptag, &ifctx->reply,
691                                        ifctx->replylen,
692                                        TAG_ROOT) != NULL)
693                                 gotrootpath = 1;
694                 }
695                 
696                 for (ifctx = gctx->interfaces;
697                      ifctx != NULL;
698                      ifctx = ifctx->next) {
699                         ifctx->outstanding = 0;
700                         if (bootpc_ifctx_isresolved(ifctx)  != 0 &&
701                             gotrootpath != 0) {
702                                 continue;
703                         }
704                         if (bootpc_ifctx_isfailed(ifctx) != 0)
705                                 continue;
706
707                         outstanding++;
708                         ifctx->outstanding = 1;
709
710                         /* Proceed to next step in DHCP negotiation */
711                         if ((ifctx->state == IF_DHCP_OFFERED &&
712                              ifctx->dhcpquerytype != DHCP_REQUEST) ||
713                             (ifctx->state == IF_DHCP_UNRESOLVED &&
714                              ifctx->dhcpquerytype != DHCP_DISCOVER) ||
715                             (ifctx->state == IF_BOOTP_UNRESOLVED &&
716                              ifctx->dhcpquerytype != DHCP_NOMSG)) {
717                                 ifctx->sentmsg = 0;
718                                 bootpc_compose_query(ifctx, gctx, td);
719                         }
720                         
721                         /* Send BOOTP request (or re-send). */
722                 
723                         if (ifctx->sentmsg == 0) {
724                                 switch(ifctx->dhcpquerytype) {
725                                 case DHCP_DISCOVER:
726                                         s = "DHCP Discover";
727                                         break;
728                                 case DHCP_REQUEST:
729                                         s = "DHCP Request";
730                                         break;
731                                 case DHCP_NOMSG:
732                                 default:
733                                         s = "BOOTP Query";
734                                         break;
735                                 }
736                                 printf("Sending %s packet from "
737                                        "interface %s (%*D)\n",
738                                        s,
739                                        ifctx->ireq.ifr_name,
740                                        ifctx->sdl->sdl_alen,
741                                        (unsigned char *) LLADDR(ifctx->sdl),
742                                        ":");
743                                 ifctx->sentmsg = 1;
744                         }
745
746                         aio.iov_base = (caddr_t) &ifctx->call;
747                         aio.iov_len = sizeof(ifctx->call);
748                         
749                         auio.uio_iov = &aio;
750                         auio.uio_iovcnt = 1;
751                         auio.uio_segflg = UIO_SYSSPACE;
752                         auio.uio_rw = UIO_WRITE;
753                         auio.uio_offset = 0;
754                         auio.uio_resid = sizeof(ifctx->call);
755                         auio.uio_td = td;
756                         
757                         /* Set netmask to 0.0.0.0 */
758                         
759                         sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
760                         clear_sinaddr(sin);
761                         error = ifioctl(ifctx->so, SIOCSIFNETMASK,
762                                         (caddr_t) &ifctx->ireq, td);
763                         if (error != 0)
764                                 panic("bootpc_call:"
765                                       "set if netmask, error=%d",
766                                       error);
767         
768                         error = sosend(so, (struct sockaddr *) &dst,
769                                        &auio, NULL, NULL, 0, td);
770                         if (error != 0) {
771                                 printf("bootpc_call: sosend: %d state %08x\n",
772                                        error, (int) so->so_state);
773                         }
774
775                         /* XXX: Is this needed ? */
776                         tsleep(&error, 0, "bootpw", 10);
777                         
778                         /* Set netmask to 255.0.0.0 */
779                         
780                         sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
781                         clear_sinaddr(sin);
782                         sin->sin_addr.s_addr = htonl(0xff000000u);
783                         error = ifioctl(ifctx->so, SIOCSIFNETMASK,
784                                         (caddr_t) &ifctx->ireq, td);
785                         if (error != 0)
786                                 panic("bootpc_call:"
787                                       "set if netmask, error=%d",
788                                       error);
789                         
790                 }
791                 
792                 if (outstanding == 0 &&
793                     (rtimo == 0 || time_second >= rtimo)) {
794                         error = 0;
795                         goto gotreply;
796                 }
797                 
798                 /* Determine new timeout. */
799                 if (timo < MAX_RESEND_DELAY)
800                         timo++;
801                 else {
802                         printf("DHCP/BOOTP timeout for server ");
803                         print_sin_addr(&dst);
804                         printf("\n");
805                 }
806                 
807                 /*
808                  * Wait for up to timo seconds for a reply.
809                  * The socket receive timeout was set to 1 second.
810                  */
811                 atimo = timo + time_second;
812                 while (time_second < atimo) {
813                         aio.iov_base = (caddr_t) &gctx->reply;
814                         aio.iov_len = sizeof(gctx->reply);
815                         
816                         auio.uio_iov = &aio;
817                         auio.uio_iovcnt = 1;
818                         auio.uio_segflg = UIO_SYSSPACE;
819                         auio.uio_rw = UIO_READ;
820                         auio.uio_offset = 0;
821                         auio.uio_resid = sizeof(gctx->reply);
822                         auio.uio_td = td;
823                         
824                         rcvflg = 0;
825                         error = soreceive(so, NULL, &auio,
826                                           NULL, NULL, &rcvflg);
827                         gctx->secs = time_second - gctx->starttime;
828                         for (ifctx = gctx->interfaces;
829                              ifctx != NULL;
830                              ifctx = ifctx->next) {
831                                 if (bootpc_ifctx_isresolved(ifctx) != 0 ||
832                                     bootpc_ifctx_isfailed(ifctx) != 0)
833                                         continue;
834                                 
835                                 ifctx->call.secs = htons(gctx->secs);
836                         }
837                         if (error == EWOULDBLOCK)
838                                 continue;
839                         if (error != 0)
840                                 goto out;
841                         len = sizeof(gctx->reply) - auio.uio_resid;
842                         
843                         /* Do we have the required number of bytes ? */
844                         if (len < BOOTP_MIN_LEN)
845                                 continue;
846                         gctx->replylen = len;
847                         
848                         /* Is it a reply? */
849                         if (gctx->reply.op != BOOTP_REPLY)
850                                 continue;
851                         
852                         /* Is this an answer to our query */
853                         for (ifctx = gctx->interfaces;
854                              ifctx != NULL;
855                              ifctx = ifctx->next) {
856                                 if (gctx->reply.xid != ifctx->call.xid)
857                                         continue;
858                                 
859                                 /* Same HW address size ? */
860                                 if (gctx->reply.hlen != ifctx->call.hlen)
861                                         continue;
862                                 
863                                 /* Correct HW address ? */
864                                 if (bcmp(gctx->reply.chaddr,
865                                          ifctx->call.chaddr,
866                                          ifctx->call.hlen) != 0)
867                                         continue;
868
869                                 break;
870                         }
871
872                         if (ifctx != NULL) {
873                                 s =  bootpc_tag(&gctx->tmptag,
874                                                 &gctx->reply,
875                                                 gctx->replylen,
876                                                 TAG_DHCP_MSGTYPE);
877                                 if (s != NULL) {
878                                         switch (*s) {
879                                         case DHCP_OFFER:
880                                                 s = "DHCP Offer";
881                                                 break;
882                                         case DHCP_ACK:
883                                                 s = "DHCP Ack";
884                                                 break;
885                                         default:
886                                                 s = "DHCP (unexpected)";
887                                                 break;
888                                         }
889                                 } else
890                                         s = "BOOTP Reply";
891
892                                 printf("Received %s packet"
893                                        " on %s from ",
894                                        s,
895                                        ifctx->ireq.ifr_name);
896                                 print_in_addr(gctx->reply.siaddr);
897                                 if (gctx->reply.giaddr.s_addr !=
898                                     htonl(INADDR_ANY)) {
899                                         printf(" via ");
900                                         print_in_addr(gctx->reply.giaddr);
901                                 }
902                                 if (bootpc_received(gctx, ifctx) != 0) {
903                                         printf(" (accepted)");
904                                         if (ifctx->outstanding) {
905                                                 ifctx->outstanding = 0;
906                                                 outstanding--;
907                                         }
908                                         /* Network settle delay */
909                                         if (outstanding == 0)
910                                                 atimo = time_second +
911                                                         BOOTP_SETTLE_DELAY;
912                                 } else
913                                         printf(" (ignored)");
914                                 if (ifctx->gotrootpath) {
915                                         gotrootpath = 1;
916                                         rtimo = time_second +
917                                                 BOOTP_SETTLE_DELAY;
918                                         printf(" (got root path)");
919                                 } else
920                                         printf(" (no root path)");
921                                 printf("\n");
922                         }
923                 } /* while secs */
924 #ifdef BOOTP_TIMEOUT
925                 if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
926                         break;
927 #endif
928                 /* Force a retry if halfway in DHCP negotiation */
929                 retry = 0;
930                 for (ifctx = gctx->interfaces; ifctx != NULL;
931                      ifctx = ifctx->next) {
932                         if (ifctx->state == IF_DHCP_OFFERED) {
933                                 if (ifctx->dhcpquerytype == DHCP_DISCOVER)
934                                         retry = 1;
935                                 else
936                                         ifctx->state = IF_DHCP_UNRESOLVED;
937                         }
938                 }
939                 
940                 if (retry != 0)
941                         continue;
942                 
943                 if (gotrootpath != 0) {
944                         gctx->gotrootpath = gotrootpath;
945                         if (rtimo != 0 && time_second >= rtimo)
946                                 break;
947                 }
948         } /* forever send/receive */
949         
950         /* 
951          * XXX: These are errors of varying seriousness being silently
952          * ignored
953          */
954
955         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
956                 if (bootpc_ifctx_isresolved(ifctx) == 0) {
957                         printf("%s timeout for interface %s\n",
958                                ifctx->dhcpquerytype != DHCP_NOMSG ?
959                                "DHCP" : "BOOTP",
960                                ifctx->ireq.ifr_name);
961                 }
962         }
963         if (gctx->gotrootpath != 0) {
964 #if 0
965                 printf("Got a root path, ignoring remaining timeout\n");
966 #endif
967                 error = 0;
968                 goto out;
969         }
970 #ifndef BOOTP_NFSROOT
971         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
972                 if (bootpc_ifctx_isresolved(ifctx) != 0) {
973                         error = 0;
974                         goto out;
975                 }
976         }
977 #endif
978         error = ETIMEDOUT;
979         goto out;
980         
981 gotreply:
982 out:
983         soclose(so);
984         return error;
985 }
986
987
988 static int
989 bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
990                         struct bootpc_globalcontext *gctx,
991                         struct thread *td)
992 {
993         struct sockaddr_in *sin;
994         int error;
995         
996         struct ifreq *ireq;
997         struct socket *so;
998         struct ifaddr *ifa;
999         struct sockaddr_dl *sdl;
1000
1001         error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0, td);
1002         if (error != 0)
1003                 panic("nfs_boot: socreate, error=%d", error);
1004         
1005         ireq = &ifctx->ireq;
1006         so = ifctx->so;
1007
1008         /*
1009          * Bring up the interface.
1010          *
1011          * Get the old interface flags and or IFF_UP into them; if
1012          * IFF_UP set blindly, interface selection can be clobbered.
1013          */
1014         error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td);
1015         if (error != 0)
1016                 panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error);
1017         ireq->ifr_flags |= IFF_UP;
1018         error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td);
1019         if (error != 0)
1020                 panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error);
1021         
1022         /*
1023          * Do enough of ifconfig(8) so that the chosen interface
1024          * can talk to the servers.  (just set the address)
1025          */
1026         
1027         /* addr is 0.0.0.0 */
1028         
1029         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1030         clear_sinaddr(sin);
1031         error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td);
1032         if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
1033                 panic("bootpc_fakeup_interface: "
1034                       "set if addr, error=%d", error);
1035         
1036         /* netmask is 255.0.0.0 */
1037         
1038         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1039         clear_sinaddr(sin);
1040         sin->sin_addr.s_addr = htonl(0xff000000u);
1041         error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, td);
1042         if (error != 0)
1043                 panic("bootpc_fakeup_interface: set if netmask, error=%d",
1044                       error);
1045         
1046         /* Broadcast is 255.255.255.255 */
1047         
1048         sin = (struct sockaddr_in *)&ireq->ifr_addr;
1049         clear_sinaddr(sin);
1050         clear_sinaddr(&ifctx->broadcast);
1051         sin->sin_addr.s_addr = htonl(INADDR_BROADCAST);
1052         ifctx->broadcast.sin_addr.s_addr = sin->sin_addr.s_addr;
1053         
1054         error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, td);
1055         if (error != 0 && error != EADDRNOTAVAIL)
1056                 panic("bootpc_fakeup_interface: "
1057                       "set if broadcast addr, error=%d",
1058                       error);
1059         error = 0;
1060         
1061         /* Get HW address */
1062         
1063         sdl = NULL;
1064         for (ifa = TAILQ_FIRST(&ifctx->ifp->if_addrhead);
1065              ifa != NULL;
1066              ifa = TAILQ_NEXT(ifa,ifa_link))
1067                 if (ifa->ifa_addr->sa_family == AF_LINK &&
1068                     (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) != NULL &&
1069                     sdl->sdl_type == IFT_ETHER)
1070                         break;
1071         
1072         if (sdl == NULL)
1073                 panic("bootpc: Unable to find HW address for %s",
1074                       ifctx->ireq.ifr_name);
1075         ifctx->sdl = sdl;
1076         
1077         return error;
1078 }
1079
1080
1081 static int
1082 bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
1083                         struct bootpc_globalcontext *gctx,
1084                         struct thread *td)
1085 {
1086         int error;
1087         struct sockaddr_in defdst;
1088         struct sockaddr_in defmask;
1089         struct sockaddr_in *sin;
1090         
1091         struct ifreq *ireq;
1092         struct socket *so;
1093         struct sockaddr_in *myaddr;
1094         struct sockaddr_in *netmask;
1095         struct sockaddr_in *gw;
1096
1097         ireq = &ifctx->ireq;
1098         so = ifctx->so;
1099         myaddr = &ifctx->myaddr;
1100         netmask = &ifctx->netmask;
1101         gw = &ifctx->gw;
1102
1103         if (bootpc_ifctx_isresolved(ifctx) == 0) {
1104
1105                 /* Shutdown interfaces where BOOTP failed */
1106                 
1107                 printf("Shutdown interface %s\n", ifctx->ireq.ifr_name);
1108                 error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td);
1109                 if (error != 0)
1110                         panic("bootpc_adjust_interface: "
1111                               "SIOCGIFFLAGS, error=%d", error);
1112                 ireq->ifr_flags &= ~IFF_UP;
1113                 error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td);
1114                 if (error != 0)
1115                         panic("bootpc_adjust_interface: "
1116                               "SIOCSIFFLAGS, error=%d", error);
1117                 
1118                 sin = (struct sockaddr_in *) &ireq->ifr_addr;
1119                 clear_sinaddr(sin);
1120                 error = ifioctl(so, SIOCDIFADDR, (caddr_t) ireq, td);
1121                 if (error != 0 && (error != EADDRNOTAVAIL ||
1122                                    ifctx == gctx->interfaces))
1123                         panic("bootpc_adjust_interface: "
1124                               "SIOCDIFADDR, error=%d", error);
1125                 
1126                 return 0;
1127         }
1128
1129         printf("Adjusted interface %s\n", ifctx->ireq.ifr_name);
1130         /*
1131          * Do enough of ifconfig(8) so that the chosen interface
1132          * can talk to the servers.  (just set the address)
1133          */
1134         bcopy(netmask, &ireq->ifr_addr, sizeof(*netmask));
1135         error = ifioctl(so, SIOCSIFNETMASK, (caddr_t) ireq, td);
1136         if (error != 0)
1137                 panic("bootpc_adjust_interface: "
1138                       "set if netmask, error=%d", error);
1139         
1140         /* Broadcast is with host part of IP address all 1's */
1141         
1142         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1143         clear_sinaddr(sin);
1144         sin->sin_addr.s_addr = myaddr->sin_addr.s_addr |
1145                 ~ netmask->sin_addr.s_addr;
1146         error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t) ireq, td);
1147         if (error != 0)
1148                 panic("bootpc_adjust_interface: "
1149                       "set if broadcast addr, error=%d", error);
1150         
1151         bcopy(myaddr, &ireq->ifr_addr, sizeof(*myaddr));
1152         error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td);
1153         if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
1154                 panic("bootpc_adjust_interface: "
1155                       "set if addr, error=%d", error);
1156         
1157         /* Add new default route */
1158
1159         if (ifctx->gotgw != 0 || gctx->gotgw == 0) {
1160                 clear_sinaddr(&defdst);
1161                 clear_sinaddr(&defmask);
1162                 error = rtrequest(RTM_ADD,
1163                                   (struct sockaddr *) &defdst,
1164                                   (struct sockaddr *) gw,
1165                                   (struct sockaddr *) &defmask,
1166                                   (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
1167                 if (error != 0) {
1168                         printf("bootpc_adjust_interface: "
1169                                "add net route, error=%d\n", error);
1170                         return error;
1171                 }
1172         }
1173         
1174         return 0;
1175 }
1176
1177
1178 static int
1179 setfs(struct sockaddr_in *addr, char *path, char *p)
1180 {
1181         unsigned int ip;
1182         int val;
1183         
1184         ip = 0;
1185         if (((val = getdec(&p)) < 0) || (val > 255))
1186                 return 0;
1187         ip = val << 24;
1188         if (*p != '.')
1189                 return 0;
1190         p++;
1191         if (((val = getdec(&p)) < 0) || (val > 255))
1192                 return 0;
1193         ip |= (val << 16);
1194         if (*p != '.')
1195                 return 0;
1196         p++;
1197         if (((val = getdec(&p)) < 0) || (val > 255))
1198                 return 0;
1199         ip |= (val << 8);
1200         if (*p != '.')
1201                 return 0;
1202         p++;
1203         if (((val = getdec(&p)) < 0) || (val > 255))
1204                 return 0;
1205         ip |= val;
1206         if (*p != ':')
1207                 return 0;
1208         p++;
1209         
1210         addr->sin_addr.s_addr = htonl(ip);
1211         addr->sin_len = sizeof(struct sockaddr_in);
1212         addr->sin_family = AF_INET;
1213         
1214         strncpy(path, p, MNAMELEN - 1);
1215         return 1;
1216 }
1217
1218
1219 static int
1220 getdec(char **ptr)
1221 {
1222         char *p;
1223         int ret;
1224
1225         p = *ptr;
1226         ret = 0;
1227         if ((*p < '0') || (*p > '9'))
1228                 return -1;
1229         while ((*p >= '0') && (*p <= '9')) {
1230                 ret = ret * 10 + (*p - '0');
1231                 p++;
1232         }
1233         *ptr = p;
1234         return ret;
1235 }
1236
1237
1238 static char *
1239 substr(char *a, char *b)
1240 {
1241         char *loc1;
1242         char *loc2;
1243         
1244         while (*a != '\0') {
1245                 loc1 = a;
1246                 loc2 = b;
1247                 while (*loc1 == *loc2++) {
1248                         if (*loc1 == '\0')
1249                                 return 0;
1250                         loc1++;
1251                         if (*loc2 == '\0')
1252                                 return loc1;
1253                 }
1254                 a++;
1255         }
1256         return 0;
1257 }
1258
1259
1260 static void
1261 mountopts(struct nfs_args *args, char *p)
1262 {
1263         char *tmp;
1264         
1265         args->version = NFS_ARGSVERSION;
1266         args->rsize = 8192;
1267         args->wsize = 8192;
1268         args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
1269         args->sotype = SOCK_DGRAM;
1270         if (p == NULL)
1271                 return;
1272         if ((tmp = (char *)substr(p, "rsize=")))
1273                 args->rsize = getdec(&tmp);
1274         if ((tmp = (char *)substr(p, "wsize=")))
1275                 args->wsize = getdec(&tmp);
1276         if ((tmp = (char *)substr(p, "intr")))
1277                 args->flags |= NFSMNT_INT;
1278         if ((tmp = (char *)substr(p, "soft")))
1279                 args->flags |= NFSMNT_SOFT;
1280         if ((tmp = (char *)substr(p, "noconn")))
1281                 args->flags |= NFSMNT_NOCONN;
1282         if ((tmp = (char *)substr(p, "tcp")))
1283                 args->sotype = SOCK_STREAM;
1284 }
1285
1286
1287 static int
1288 xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
1289 {
1290         struct mbuf *m;
1291         int alignedlen;
1292         
1293         m = *mptr;
1294         alignedlen = ( len + 3 ) & ~3;
1295         
1296         if (m->m_len < alignedlen) {
1297                 m = m_pullup(m, alignedlen);
1298                 if (m == NULL) {
1299                         *mptr = NULL;
1300                         return EBADRPC;
1301                 }
1302         }
1303         bcopy(mtod(m, u_char *), buf, len);
1304         m_adj(m, alignedlen);
1305         *mptr = m;
1306         return 0;
1307 }
1308
1309
1310 static int
1311 xdr_int_decode(struct mbuf **mptr, int *iptr)
1312 {
1313         u_int32_t i;
1314         if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
1315                 return EBADRPC;
1316         *iptr = fxdr_unsigned(u_int32_t, i);
1317         return 0;
1318 }
1319
1320
1321 static void
1322 print_sin_addr(struct sockaddr_in *sin)
1323 {
1324         print_in_addr(sin->sin_addr);
1325 }
1326
1327
1328 static void
1329 print_in_addr(struct in_addr addr)
1330 {
1331         unsigned int ip;
1332         
1333         ip = ntohl(addr.s_addr);
1334         printf("%d.%d.%d.%d",
1335                ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
1336 }
1337
1338 static void
1339 bootpc_compose_query(ifctx, gctx, td)
1340         struct bootpc_ifcontext *ifctx;
1341         struct bootpc_globalcontext *gctx;
1342         struct thread *td;
1343 {
1344         unsigned char *vendp;
1345         unsigned char vendor_client[64];
1346         uint32_t leasetime;
1347         uint8_t vendor_client_len;
1348
1349         ifctx->gotrootpath = 0;
1350
1351         bzero((caddr_t) &ifctx->call, sizeof(ifctx->call));
1352         
1353         /* bootpc part */
1354         ifctx->call.op = BOOTP_REQUEST;         /* BOOTREQUEST */
1355         ifctx->call.htype = 1;                  /* 10mb ethernet */
1356         ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */
1357         ifctx->call.hops = 0;
1358         if (bootpc_ifctx_isunresolved(ifctx) != 0)
1359                 ifctx->xid++;
1360         ifctx->call.xid = txdr_unsigned(ifctx->xid);
1361         bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen);
1362         
1363         vendp = ifctx->call.vend;
1364         *vendp++ = 99;          /* RFC1048 cookie */
1365         *vendp++ = 130;
1366         *vendp++ = 83;
1367         *vendp++ = 99;
1368         *vendp++ = TAG_MAXMSGSIZE;
1369         *vendp++ = 2;
1370         *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255;
1371         *vendp++ = sizeof(struct bootp_packet) & 255;
1372
1373         snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s",
1374                 ostype, MACHINE, osrelease);
1375         vendor_client_len = strlen(vendor_client);
1376         *vendp++ = TAG_VENDOR_INDENTIFIER;
1377         *vendp++ = vendor_client_len;
1378         memcpy(vendp, vendor_client, vendor_client_len);
1379         vendp += vendor_client_len;;
1380         ifctx->dhcpquerytype = DHCP_NOMSG;
1381         switch (ifctx->state) {
1382         case IF_DHCP_UNRESOLVED:
1383                 *vendp++ = TAG_DHCP_MSGTYPE;
1384                 *vendp++ = 1;
1385                 *vendp++ = DHCP_DISCOVER;
1386                 ifctx->dhcpquerytype = DHCP_DISCOVER;
1387                 ifctx->gotdhcpserver = 0;
1388                 break;
1389         case IF_DHCP_OFFERED:
1390                 *vendp++ = TAG_DHCP_MSGTYPE;
1391                 *vendp++ = 1;
1392                 *vendp++ = DHCP_REQUEST;
1393                 ifctx->dhcpquerytype = DHCP_REQUEST;
1394                 *vendp++ = TAG_DHCP_REQ_ADDR;
1395                 *vendp++ = 4;
1396                 memcpy(vendp, &ifctx->reply.yiaddr, 4);
1397                 vendp += 4;
1398                 if (ifctx->gotdhcpserver != 0) {
1399                         *vendp++ = TAG_DHCP_SERVERID;
1400                         *vendp++ = 4;
1401                         memcpy(vendp, &ifctx->dhcpserver, 4);
1402                         vendp += 4;
1403                 }
1404                 *vendp++ = TAG_DHCP_LEASETIME;
1405                 *vendp++ = 4;
1406                 leasetime = htonl(300);
1407                 memcpy(vendp, &leasetime, 4);
1408                 vendp += 4;
1409         default:
1410                 ;
1411         }
1412         *vendp = TAG_END;
1413         
1414         ifctx->call.secs = 0;
1415         ifctx->call.flags = htons(0x8000); /* We need an broadcast answer */
1416 }
1417
1418
1419 static int
1420 bootpc_hascookie(struct bootp_packet *bp)
1421 {
1422         return (bp->vend[0] == 99 && bp->vend[1] == 130 &&
1423                 bp->vend[2] == 83 && bp->vend[3] == 99);
1424 }
1425
1426
1427 static void
1428 bootpc_tag_helper(struct bootpc_tagcontext *tctx,
1429                   unsigned char *start,
1430                   int len,
1431                   int tag)
1432 {
1433         unsigned char *j;
1434         unsigned char *ej;
1435         unsigned char code;
1436
1437         if (tctx->badtag != 0 || tctx->badopt != 0)
1438                 return;
1439         
1440         j = start;
1441         ej = j + len;
1442         
1443         while (j < ej) {
1444                 code = *j++;
1445                 if (code == TAG_PAD)
1446                         continue;
1447                 if (code == TAG_END)
1448                         return;
1449                 if (j >= ej || j + *j + 1 > ej) {
1450                         tctx->badopt = 1;
1451                         return;
1452                 }
1453                 len = *j++;
1454                 if (code == tag) {
1455                         if (tctx->taglen + len > TAG_MAXLEN) {
1456                                 tctx->badtag = 1;
1457                                 return;
1458                         }
1459                         tctx->foundopt = 1;
1460                         if (len > 0)
1461                                 memcpy(tctx->buf + tctx->taglen,
1462                                        j, len);
1463                         tctx->taglen += len;
1464                 }
1465                 if (code == TAG_OVERLOAD)
1466                         tctx->overload = *j;
1467                 
1468                 j += len;
1469         }
1470 }
1471
1472
1473 static unsigned char *
1474 bootpc_tag(struct bootpc_tagcontext *tctx,
1475            struct bootp_packet *bp,
1476            int len,
1477            int tag)
1478 {
1479         unsigned char *j;
1480         unsigned char *ej;
1481
1482         tctx->overload = 0;
1483         tctx->badopt = 0;
1484         tctx->badtag = 0;
1485         tctx->foundopt = 0;
1486         tctx->taglen = 0;
1487
1488         if (bootpc_hascookie(bp) == 0)
1489                 return NULL;
1490         
1491         j = &bp->vend[4];
1492         ej = (unsigned char *) bp + len;
1493
1494         bootpc_tag_helper(tctx, &bp->vend[4],
1495                           (unsigned char *) bp + len - &bp->vend[4], tag);
1496         
1497         if ((tctx->overload & OVERLOAD_FILE) != 0)
1498                 bootpc_tag_helper(tctx,
1499                                   (unsigned char *) bp->file,
1500                                   sizeof(bp->file),
1501                                   tag);
1502         if ((tctx->overload & OVERLOAD_SNAME) != 0)
1503                 bootpc_tag_helper(tctx,
1504                                   (unsigned char *) bp->sname,
1505                                   sizeof(bp->sname),
1506                                   tag);
1507         
1508         if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0)
1509                 return NULL;
1510         tctx->buf[tctx->taglen] = '\0';
1511         return tctx->buf;
1512 }
1513
1514
1515 static void
1516 bootpc_decode_reply(nd, ifctx, gctx)
1517         struct nfsv3_diskless *nd;
1518         struct bootpc_ifcontext *ifctx;
1519         struct bootpc_globalcontext *gctx;
1520 {
1521         char *p;
1522         unsigned int ip;
1523
1524         ifctx->gotgw = 0;
1525         ifctx->gotnetmask = 0;
1526
1527         clear_sinaddr(&ifctx->myaddr);
1528         clear_sinaddr(&ifctx->netmask);
1529         clear_sinaddr(&ifctx->gw);
1530         
1531         ifctx->myaddr.sin_addr = ifctx->reply.yiaddr;
1532         
1533         ip = ntohl(ifctx->myaddr.sin_addr.s_addr);
1534         snprintf(gctx->lookup_path, sizeof(gctx->lookup_path),
1535                  "swap.%d.%d.%d.%d",
1536                  ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
1537         
1538         printf("%s at ", ifctx->ireq.ifr_name);
1539         print_sin_addr(&ifctx->myaddr);
1540         printf(" server ");
1541         print_in_addr(ifctx->reply.siaddr);
1542         
1543         ifctx->gw.sin_addr = ifctx->reply.giaddr;
1544         if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) {
1545                 printf(" via gateway ");
1546                 print_in_addr(ifctx->reply.giaddr);
1547         }
1548
1549         /* This call used for the side effect (overload flag) */
1550         (void) bootpc_tag(&gctx->tmptag,
1551                           &ifctx->reply, ifctx->replylen, TAG_END);
1552         
1553         if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0)
1554                 if (ifctx->reply.sname[0] != '\0')
1555                         printf(" server name %s", ifctx->reply.sname);
1556         if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0)
1557                 if (ifctx->reply.file[0] != '\0')
1558                         printf(" boot file %s", ifctx->reply.file);
1559         
1560         printf("\n");
1561
1562         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1563                        TAG_SUBNETMASK);
1564         if (p != NULL) {
1565                 if (gctx->tag.taglen != 4)
1566                         panic("bootpc: subnet mask len is %d",
1567                               gctx->tag.taglen);
1568                 bcopy(p, &ifctx->netmask.sin_addr, 4);
1569                 ifctx->gotnetmask = 1;
1570                 printf("subnet mask ");
1571                 print_sin_addr(&ifctx->netmask);
1572                 printf(" ");
1573         }
1574         
1575         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1576                        TAG_ROUTERS);
1577         if (p != NULL) {
1578                 /* Routers */
1579                 if (gctx->tag.taglen % 4)
1580                         panic("bootpc: Router Len is %d", gctx->tag.taglen);
1581                 if (gctx->tag.taglen > 0) {
1582                         bcopy(p, &ifctx->gw.sin_addr, 4);
1583                         printf("router ");
1584                         print_sin_addr(&ifctx->gw);
1585                         printf(" ");
1586                         ifctx->gotgw = 1;
1587                         gctx->gotgw = 1;
1588                 }
1589         }
1590         
1591         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1592                        TAG_ROOT);
1593         if (p != NULL) {
1594                 if (gctx->setrootfs != NULL) {
1595                         printf("rootfs %s (ignored) ", p);
1596                 } else  if (setfs(&nd->root_saddr,
1597                                   nd->root_hostnam, p)) {
1598                         printf("rootfs %s ",p);
1599                         gctx->gotrootpath = 1;
1600                         ifctx->gotrootpath = 1;
1601                         gctx->setrootfs = ifctx;
1602                         
1603                         p = bootpc_tag(&gctx->tag, &ifctx->reply,
1604                                        ifctx->replylen,
1605                                        TAG_ROOTOPTS);
1606                         if (p != NULL) {
1607                                 mountopts(&nd->root_args, p);
1608                                 printf("rootopts %s ", p);
1609                         }
1610                 } else
1611                         panic("Failed to set rootfs to %s",p);
1612         }
1613
1614         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1615                        TAG_SWAP);
1616         if (p != NULL) {
1617                 if (gctx->setswapfs != NULL) {
1618                         printf("swapfs %s (ignored) ", p);
1619                 } else  if (setfs(&nd->swap_saddr,
1620                                   nd->swap_hostnam, p)) {
1621                         gctx->gotswappath = 1;
1622                         gctx->setswapfs = ifctx;
1623                         printf("swapfs %s ", p);
1624
1625                         p = bootpc_tag(&gctx->tag, &ifctx->reply,
1626                                        ifctx->replylen,
1627                                        TAG_SWAPOPTS);
1628                         if (p != NULL) {
1629                                 /* swap mount options */
1630                                 mountopts(&nd->swap_args, p);
1631                                 printf("swapopts %s ", p);
1632                         }
1633                         
1634                         p = bootpc_tag(&gctx->tag, &ifctx->reply,
1635                                        ifctx->replylen,
1636                                        TAG_SWAPSIZE);
1637                         if (p != NULL) {
1638                                 int swaplen;
1639                                 if (gctx->tag.taglen != 4)
1640                                         panic("bootpc: "
1641                                               "Expected 4 bytes for swaplen, "
1642                                               "not %d bytes",
1643                                               gctx->tag.taglen);
1644                                 bcopy(p, &swaplen, 4);
1645                                 nd->swap_nblks = ntohl(swaplen);
1646                                 printf("swapsize %d KB ",
1647                                        nd->swap_nblks);
1648                         }
1649                 } else
1650                         panic("Failed to set swapfs to %s", p);
1651         }
1652
1653         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1654                        TAG_HOSTNAME);
1655         if (p != NULL) {
1656                 if (gctx->tag.taglen >= MAXHOSTNAMELEN)
1657                         panic("bootpc: hostname >= %d bytes",
1658                               MAXHOSTNAMELEN);
1659                 if (gctx->sethostname != NULL) {
1660                         printf("hostname %s (ignored) ", p);
1661                 } else {
1662                         strcpy(nd->my_hostnam, p);
1663                         strcpy(hostname, p);
1664                         printf("hostname %s ",hostname);
1665                         gctx->sethostname = ifctx;
1666                 }
1667         }
1668         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1669                        TAG_COOKIE);
1670         if (p != NULL) {        /* store in a sysctl variable */
1671                 int i, l = sizeof(bootp_cookie) - 1;
1672                 for (i = 0; i < l && p[i] != '\0'; i++)
1673                         bootp_cookie[i] = p[i];
1674                 p[i] = '\0';
1675         }
1676
1677         printf("\n");
1678         
1679         if (ifctx->gotnetmask == 0) {
1680                 if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr)))
1681                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1682                 else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr)))
1683                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1684                 else
1685                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1686         }
1687         if (ifctx->gotgw == 0) {
1688                 /* Use proxyarp */
1689                 ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr;
1690         }
1691 }
1692
1693 void
1694 bootpc_init(void)
1695 {
1696         struct bootpc_ifcontext *ifctx, *nctx;  /* Interface BOOTP contexts */
1697         struct bootpc_globalcontext *gctx;      /* Global BOOTP context */
1698         struct ifnet *ifp;
1699         int error;
1700         struct nfsv3_diskless *nd;
1701         struct thread *td;
1702
1703         nd = &nfsv3_diskless;
1704         td = curthread;
1705         
1706         /*
1707          * If already filled in, don't touch it here
1708          */
1709         if (nfs_diskless_valid != 0)
1710                 return;
1711
1712         /*
1713          * Wait until arp entries can be handled.
1714          */
1715         while (time_second == 0)
1716                 tsleep(&time_second, 0, "arpkludge", 10);
1717         
1718         gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK);
1719         if (gctx == NULL)
1720                 panic("Failed to allocate bootp global context structure");
1721         
1722         bzero(gctx, sizeof(*gctx));
1723         gctx->xid = ~0xFFFF;
1724         gctx->starttime = time_second;
1725         
1726         ifctx = allocifctx(gctx);
1727
1728         /*
1729          * Find a network interface.
1730          */
1731 #ifdef BOOTP_WIRED_TO
1732         printf("bootpc_init: wired to interface '%s'\n",
1733                __XSTRING(BOOTP_WIRED_TO));
1734 #endif
1735         bzero(&ifctx->ireq, sizeof(ifctx->ireq));
1736         for (ifp = TAILQ_FIRST(&ifnet);
1737              ifp != NULL;
1738              ifp = TAILQ_NEXT(ifp, if_link)) {
1739                 snprintf(ifctx->ireq.ifr_name, sizeof(ifctx->ireq.ifr_name),
1740                          "%s%d", ifp->if_name, ifp->if_unit);
1741 #ifdef BOOTP_WIRED_TO
1742                 if (strcmp(ifctx->ireq.ifr_name,
1743                            __XSTRING(BOOTP_WIRED_TO)) != 0)
1744                         continue;
1745 #else
1746                 if ((ifp->if_flags &
1747                      (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
1748                     IFF_BROADCAST)
1749                         continue;
1750 #endif
1751                 if (gctx->interfaces != NULL)
1752                         gctx->lastinterface->next = ifctx;
1753                 else
1754                         gctx->interfaces = ifctx;
1755                 ifctx->ifp = ifp;
1756                 gctx->lastinterface = ifctx;
1757                 ifctx = allocifctx(gctx);
1758         }
1759         free(ifctx, M_TEMP);
1760         
1761         if (gctx->interfaces == NULL) {
1762 #ifdef BOOTP_WIRED_TO
1763                 panic("bootpc_init: Could not find interface specified "
1764                       "by BOOTP_WIRED_TO: "
1765                       __XSTRING(BOOTP_WIRED_TO));
1766 #else
1767                 panic("bootpc_init: no suitable interface");
1768 #endif
1769         }
1770                 
1771         gctx->gotrootpath = 0;
1772         gctx->gotswappath = 0;
1773         gctx->gotgw = 0;
1774         
1775         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1776                 bootpc_fakeup_interface(ifctx, gctx, td);
1777         
1778         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1779                 bootpc_compose_query(ifctx, gctx, td);
1780         
1781         ifctx = gctx->interfaces;
1782         error = bootpc_call(gctx, td);
1783         
1784         if (error != 0) {
1785 #ifdef BOOTP_NFSROOT
1786                 panic("BOOTP call failed");
1787 #else
1788                 printf("BOOTP call failed\n");
1789 #endif
1790         }
1791         
1792         mountopts(&nd->root_args, NULL);
1793         
1794         mountopts(&nd->swap_args, NULL);
1795
1796         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1797                 if (bootpc_ifctx_isresolved(ifctx) != 0)
1798                         bootpc_decode_reply(nd, ifctx, gctx);
1799         
1800         if (gctx->gotswappath == 0)
1801                 nd->swap_nblks = 0;
1802 #ifdef BOOTP_NFSROOT
1803         if (gctx->gotrootpath == 0)
1804                 panic("bootpc: No root path offered");
1805 #endif
1806         
1807         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
1808                 bootpc_adjust_interface(ifctx, gctx, td);
1809                 
1810                 soclose(ifctx->so);
1811         }
1812
1813         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1814                 if (ifctx->gotrootpath != 0)
1815                         break;
1816         if (ifctx == NULL) {
1817                 for (ifctx = gctx->interfaces;
1818                      ifctx != NULL;
1819                      ifctx = ifctx->next)
1820                         if (bootpc_ifctx_isresolved(ifctx) != 0)
1821                                 break;
1822         }
1823         if (ifctx == NULL)
1824                 goto out;
1825         
1826         if (gctx->gotrootpath != 0) {
1827                 
1828                 error = md_mount(&nd->root_saddr, nd->root_hostnam,
1829                                  nd->root_fh, &nd->root_fhsize,
1830                                  &nd->root_args, td);
1831                 if (error != 0)
1832                         panic("nfs_boot: mountd root, error=%d", error);
1833     
1834                 if (gctx->gotswappath != 0) {
1835                         
1836                         error = md_mount(&nd->swap_saddr,
1837                                          nd->swap_hostnam,
1838                                          nd->swap_fh, &nd->swap_fhsize,
1839                                          &nd->swap_args, td);
1840                         if (error != 0)
1841                                 panic("nfs_boot: mountd swap, error=%d",
1842                                       error);
1843                         
1844                         error = md_lookup_swap(&nd->swap_saddr,
1845                                                gctx->lookup_path,
1846                                                nd->swap_fh, &nd->swap_fhsize,
1847                                                &nd->swap_args, td);
1848                         if (error != 0)
1849                                 panic("nfs_boot: lookup swap, error=%d",
1850                                       error);
1851                 }
1852                 nfs_diskless_valid = 3;
1853         }
1854         
1855         strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name);
1856         bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr));
1857         bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr));
1858         ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
1859                 ifctx->myaddr.sin_addr.s_addr |
1860                 ~ ifctx->netmask.sin_addr.s_addr;
1861         bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask));
1862         
1863 out:
1864         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = nctx) {
1865                 nctx = ifctx->next;
1866                 free(ifctx, M_TEMP);
1867         }
1868         free(gctx, M_TEMP);
1869 }
1870
1871
1872 /*
1873  * RPC: mountd/mount
1874  * Given a server pathname, get an NFS file handle.
1875  * Also, sets sin->sin_port to the NFS service port.
1876  */
1877 static int
1878 md_mount(struct sockaddr_in *mdsin,             /* mountd server address */
1879          char *path,
1880          u_char *fhp,
1881          int *fhsizep,
1882          struct nfs_args *args,
1883          struct thread *td)
1884 {
1885         struct mbuf *m;
1886         int error;
1887         int authunixok;
1888         int authcount;
1889         int authver;
1890         
1891 #ifdef BOOTP_NFSV3
1892         /* First try NFS v3 */
1893         /* Get port number for MOUNTD. */
1894         error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1895                              &mdsin->sin_port, td);
1896         if (error == 0) {
1897                 m = xdr_string_encode(path, strlen(path));
1898                 
1899                 /* Do RPC to mountd. */
1900                 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1901                                   RPCMNT_MOUNT, &m, NULL, td);
1902         }
1903         if (error == 0) {
1904                 args->flags |= NFSMNT_NFSV3;
1905         } else {
1906 #endif
1907                 /* Fallback to NFS v2 */
1908                 
1909                 /* Get port number for MOUNTD. */
1910                 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1911                                      &mdsin->sin_port, td);
1912                 if (error != 0)
1913                         return error;
1914                 
1915                 m = xdr_string_encode(path, strlen(path));
1916                 
1917                 /* Do RPC to mountd. */
1918                 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1919                                   RPCMNT_MOUNT, &m, NULL, td);
1920                 if (error != 0)
1921                         return error;   /* message already freed */
1922                 
1923 #ifdef BOOTP_NFSV3
1924         }
1925 #endif
1926
1927         if (xdr_int_decode(&m, &error) != 0 || error != 0)
1928                 goto bad;
1929         
1930         if ((args->flags & NFSMNT_NFSV3) != 0) {
1931                 if (xdr_int_decode(&m, fhsizep) != 0 ||
1932                     *fhsizep > NFSX_V3FHMAX ||
1933                     *fhsizep <= 0)
1934                         goto bad;
1935         } else
1936                 *fhsizep = NFSX_V2FH;
1937
1938         if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
1939                 goto bad;
1940
1941         if (args->flags & NFSMNT_NFSV3) {
1942                 if (xdr_int_decode(&m, &authcount) != 0)
1943                         goto bad;
1944                 authunixok = 0;
1945                 if (authcount < 0 || authcount > 100)
1946                         goto bad;
1947                 while (authcount > 0) {
1948                         if (xdr_int_decode(&m, &authver) != 0)
1949                                 goto bad;
1950                         if (authver == RPCAUTH_UNIX)
1951                                 authunixok = 1;
1952                         authcount--;
1953                 }
1954                 if (authunixok == 0)
1955                         goto bad;
1956         }
1957           
1958         /* Set port number for NFS use. */
1959         error = krpc_portmap(mdsin, NFS_PROG,
1960                              (args->flags &
1961                               NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
1962                              &mdsin->sin_port, td);
1963         
1964         goto out;
1965         
1966 bad:
1967         error = EBADRPC;
1968         
1969 out:
1970         m_freem(m);
1971         return error;
1972 }
1973
1974
1975 static int
1976 md_lookup_swap(struct sockaddr_in *mdsin,       /* mountd server address */
1977                char *path,
1978                u_char *fhp,
1979                int *fhsizep,
1980                struct nfs_args *args,
1981                struct thread *td)
1982 {
1983         struct mbuf *m;
1984         int error;
1985         int size = -1;
1986         int attribs_present;
1987         int status;
1988         union {
1989                 u_int32_t v2[17];
1990                 u_int32_t v3[21];
1991         } fattribs;
1992         
1993         m = m_get(M_WAIT,MT_DATA);
1994         if (m == NULL)
1995                 return ENOBUFS;
1996         
1997         if ((args->flags & NFSMNT_NFSV3) != 0) {
1998                 *mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
1999                 bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
2000                 m->m_len = *fhsizep + sizeof(u_int32_t);
2001         } else {
2002                 bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
2003                 m->m_len = NFSX_V2FH;
2004         }
2005         
2006         m->m_next = xdr_string_encode(path, strlen(path));
2007         if (m->m_next == NULL) {
2008                 error = ENOBUFS;
2009                 goto out;
2010         }
2011
2012         /* Do RPC to nfsd. */
2013         if ((args->flags & NFSMNT_NFSV3) != 0)
2014                 error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
2015                                   NFSPROC_LOOKUP, &m, NULL, td);
2016         else
2017                 error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
2018                                   NFSV2PROC_LOOKUP, &m, NULL, td);
2019         if (error != 0)
2020                 return error;   /* message already freed */
2021
2022         if (xdr_int_decode(&m, &status) != 0)
2023                 goto bad;
2024         if (status != 0) {
2025                 error = ENOENT;
2026                 goto out;
2027         }
2028         
2029         if ((args->flags & NFSMNT_NFSV3) != 0) {
2030                 if (xdr_int_decode(&m, fhsizep) != 0 ||
2031                     *fhsizep > NFSX_V3FHMAX ||
2032                     *fhsizep <= 0)
2033                         goto bad;
2034         } else
2035                 *fhsizep = NFSX_V2FH;
2036         
2037         if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
2038                 goto bad;
2039         
2040         if ((args->flags & NFSMNT_NFSV3) != 0) {
2041                 if (xdr_int_decode(&m, &attribs_present) != 0)
2042                         goto bad;
2043                 if (attribs_present != 0) {
2044                         if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
2045                                               sizeof(u_int32_t) * 21) != 0)
2046                                 goto bad;
2047                         size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
2048                 }
2049         } else {
2050                 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
2051                                       sizeof(u_int32_t) * 17) != 0)
2052                         goto bad;
2053                 size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
2054         }
2055           
2056         if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
2057                 nfsv3_diskless.swap_nblks = size / 1024;
2058                 printf("md_lookup_swap: Swap size is %d KB\n",
2059                        nfsv3_diskless.swap_nblks);
2060         }
2061         
2062         goto out;
2063         
2064 bad:
2065         error = EBADRPC;
2066         
2067 out:
2068         m_freem(m);
2069         return error;
2070 }