if_xname support Part 2b/2: Convert remaining netif devices and implement full
[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.6 2004/01/06 03:21:18 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 "rpcv2.h"
69 #include "nfsproto.h"
70 #include "nfs.h"
71 #include "nfsdiskless.h"
72 #include "krpc.h"
73 #include "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\n", if_name(rt->rt_ifp));
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 flags %x, addr ",
396                if_name(ifp),
397                (unsigned short) ifp->if_flags);
398         print_sin_addr((struct sockaddr_in *) ifa->ifa_addr);
399         printf(", broadcast ");
400         print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr);
401         printf(", netmask ");
402         print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask);
403         printf("\n");
404 }
405
406
407 void
408 bootpboot_p_iflist(void)
409 {
410         struct ifnet *ifp;
411         struct ifaddr *ifa;
412         
413         printf("Interface list:\n");
414         for (ifp = TAILQ_FIRST(&ifnet);
415              ifp != NULL;
416              ifp = TAILQ_NEXT(ifp, if_link)) {
417                 for (ifa = TAILQ_FIRST(&ifp->if_addrhead);
418                      ifa != NULL;
419                      ifa = TAILQ_NEXT(ifa, ifa_link))
420                         if (ifa->ifa_addr->sa_family == AF_INET)
421                                 bootpboot_p_if(ifp, ifa);
422         }
423 }
424 #endif /* defined(BOOTP_DEBUG) */
425
426
427 static void
428 clear_sinaddr(struct sockaddr_in *sin)
429 {
430         bzero(sin, sizeof(*sin));
431         sin->sin_len = sizeof(*sin);
432         sin->sin_family = AF_INET;
433         sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */
434         sin->sin_port = 0;
435 }
436
437
438 static struct bootpc_ifcontext *
439 allocifctx(struct bootpc_globalcontext *gctx)
440 {
441         struct bootpc_ifcontext *ifctx;
442         ifctx = (struct bootpc_ifcontext *) malloc(sizeof(*ifctx),
443                                                    M_TEMP, M_WAITOK);
444         if (ifctx == NULL)
445                 panic("Failed to allocate bootp interface context structure");
446         
447         bzero(ifctx, sizeof(*ifctx));
448         ifctx->xid = gctx->xid;
449 #ifdef BOOTP_NO_DHCP
450         ifctx->state = IF_BOOTP_UNRESOLVED;
451 #else
452         ifctx->state = IF_DHCP_UNRESOLVED;
453 #endif
454         gctx->xid += 0x100;
455         return ifctx;
456 }
457
458
459 static __inline int
460 bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx)
461 {
462         if (ifctx->state == IF_BOOTP_RESOLVED ||
463             ifctx->state == IF_DHCP_RESOLVED)
464                 return 1;
465         return 0;
466 }
467
468
469 static __inline int
470 bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx)
471 {
472         if (ifctx->state == IF_BOOTP_UNRESOLVED ||
473             ifctx->state == IF_DHCP_UNRESOLVED)
474                 return 1;
475         return 0;
476 }
477
478
479 static __inline int
480 bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx)
481 {
482         if (ifctx->state == IF_BOOTP_FAILED ||
483             ifctx->state == IF_DHCP_FAILED)
484                 return 1;
485         return 0;
486 }
487
488
489 static int
490 bootpc_received(struct bootpc_globalcontext *gctx,
491                 struct bootpc_ifcontext *ifctx)
492 {
493         unsigned char dhcpreplytype;
494         char *p;
495         /*
496          * Need timeout for fallback to less
497          * desirable alternative.
498          */
499
500
501         /* This call used for the side effect (badopt flag) */
502         (void) bootpc_tag(&gctx->tmptag, &gctx->reply,
503                           gctx->replylen,
504                           TAG_END);
505
506         /* If packet is invalid, ignore it */
507         if (gctx->tmptag.badopt != 0)
508                 return 0;
509         
510         p = bootpc_tag(&gctx->tmptag, &gctx->reply,
511                        gctx->replylen, TAG_DHCP_MSGTYPE);
512         if (p != NULL)
513                 dhcpreplytype = *p;
514         else
515                 dhcpreplytype = DHCP_NOMSG;
516         
517         switch (ifctx->dhcpquerytype) {
518         case DHCP_DISCOVER:
519                 if (dhcpreplytype != DHCP_OFFER         /* Normal DHCP offer */
520 #ifndef BOOTP_FORCE_DHCP
521                     && dhcpreplytype != DHCP_NOMSG      /* Fallback to BOOTP */
522 #endif
523                         )
524                         return 0;
525                 break;
526         case DHCP_REQUEST:
527                 if (dhcpreplytype != DHCP_ACK)
528                         return 0;
529         case DHCP_NOMSG:
530         }
531                 
532         
533         /* Ignore packet unless it gives us a root tag we didn't have */
534         
535         if ((ifctx->state == IF_BOOTP_RESOLVED ||
536              (ifctx->dhcpquerytype == DHCP_DISCOVER &&
537               (ifctx->state == IF_DHCP_OFFERED ||
538                ifctx->state == IF_DHCP_RESOLVED))) &&
539             (bootpc_tag(&gctx->tmptag, &ifctx->reply,
540                         ifctx->replylen,
541                         TAG_ROOT) != NULL ||
542              bootpc_tag(&gctx->tmptag, &gctx->reply,
543                         gctx->replylen,
544                         TAG_ROOT) == NULL))
545                 return 0;
546         
547         bcopy(&gctx->reply,
548               &ifctx->reply,
549               gctx->replylen);
550         ifctx->replylen = gctx->replylen;
551         
552         /* XXX: Only reset if 'perfect' response */
553         if (ifctx->state == IF_BOOTP_UNRESOLVED)
554                 ifctx->state = IF_BOOTP_RESOLVED;
555         else if (ifctx->state == IF_DHCP_UNRESOLVED &&
556                  ifctx->dhcpquerytype == DHCP_DISCOVER) {
557                 if (dhcpreplytype == DHCP_OFFER)
558                         ifctx->state = IF_DHCP_OFFERED;
559                 else
560                         ifctx->state = IF_BOOTP_RESOLVED;       /* Fallback */
561         } else if (ifctx->state == IF_DHCP_OFFERED &&
562                    ifctx->dhcpquerytype == DHCP_REQUEST)
563                 ifctx->state = IF_DHCP_RESOLVED;
564         
565         
566         if (ifctx->dhcpquerytype == DHCP_DISCOVER &&
567             ifctx->state != IF_BOOTP_RESOLVED) {
568                 p = bootpc_tag(&gctx->tmptag, &ifctx->reply,
569                                ifctx->replylen, TAG_DHCP_SERVERID);
570                 if (p != NULL && gctx->tmptag.taglen == 4) {
571                         memcpy(&ifctx->dhcpserver, p, 4);
572                         ifctx->gotdhcpserver = 1;
573                 } else
574                         ifctx->gotdhcpserver = 0;
575                 return 1;
576         }
577         
578         ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
579                                          ifctx->replylen,
580                                          TAG_ROOT) != NULL);
581         ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
582                                    ifctx->replylen,
583                                    TAG_ROUTERS) != NULL);
584         ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
585                                         ifctx->replylen,
586                                         TAG_SUBNETMASK) != NULL);
587         return 1;
588 }
589
590 static int
591 bootpc_call(struct bootpc_globalcontext *gctx,
592             struct thread *td)
593 {
594         struct socket *so;
595         struct sockaddr_in *sin, dst;
596         struct uio auio;
597         struct sockopt sopt;
598         struct iovec aio;
599         int error, on, rcvflg, timo, len;
600         time_t atimo;
601         time_t rtimo;
602         struct timeval tv;
603         struct bootpc_ifcontext *ifctx;
604         int outstanding;
605         int gotrootpath;
606         int retry;
607         const char *s;
608         
609         /*
610          * Create socket and set its recieve timeout.
611          */
612         error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td);
613         if (error != 0)
614                 goto out;
615         
616         tv.tv_sec = 1;
617         tv.tv_usec = 0;
618         bzero(&sopt, sizeof(sopt));
619         sopt.sopt_level = SOL_SOCKET;
620         sopt.sopt_name = SO_RCVTIMEO;
621         sopt.sopt_val = &tv;
622         sopt.sopt_valsize = sizeof tv;
623         
624         error = sosetopt(so, &sopt);
625         if (error != 0)
626                 goto out;
627         
628         /*
629          * Enable broadcast.
630          */
631         on = 1;
632         sopt.sopt_name = SO_BROADCAST;
633         sopt.sopt_val = &on;
634         sopt.sopt_valsize = sizeof on;
635
636         error = sosetopt(so, &sopt);
637         if (error != 0)
638                 goto out;
639
640         /*
641          * Disable routing.
642          */
643
644         on = 1;
645         sopt.sopt_name = SO_DONTROUTE;
646         sopt.sopt_val = &on;
647         sopt.sopt_valsize = sizeof on;
648
649         error = sosetopt(so, &sopt);
650         if (error != 0)
651                 goto out;
652         
653         /*
654          * Bind the local endpoint to a bootp client port.
655          */
656         sin = &dst;
657         clear_sinaddr(sin);
658         sin->sin_port = htons(IPPORT_BOOTPC);
659         error = sobind(so, (struct sockaddr *)sin, td);
660         if (error != 0) {
661                 printf("bind failed\n");
662                 goto out;
663         }
664         
665         /*
666          * Setup socket address for the server.
667          */
668         sin = &dst;
669         clear_sinaddr(sin);
670         sin->sin_addr.s_addr = INADDR_BROADCAST;
671         sin->sin_port = htons(IPPORT_BOOTPS);
672         
673         /*
674          * Send it, repeatedly, until a reply is received,
675          * but delay each re-send by an increasing amount.
676          * If the delay hits the maximum, start complaining.
677          */
678         timo = 0;
679         rtimo = 0;
680         for (;;) {
681                 
682                 outstanding = 0;
683                 gotrootpath = 0;
684
685                 for (ifctx = gctx->interfaces;
686                      ifctx != NULL;
687                      ifctx = ifctx->next) {
688                         if (bootpc_ifctx_isresolved(ifctx) != 0 &&
689                             bootpc_tag(&gctx->tmptag, &ifctx->reply,
690                                        ifctx->replylen,
691                                        TAG_ROOT) != NULL)
692                                 gotrootpath = 1;
693                 }
694                 
695                 for (ifctx = gctx->interfaces;
696                      ifctx != NULL;
697                      ifctx = ifctx->next) {
698                         ifctx->outstanding = 0;
699                         if (bootpc_ifctx_isresolved(ifctx)  != 0 &&
700                             gotrootpath != 0) {
701                                 continue;
702                         }
703                         if (bootpc_ifctx_isfailed(ifctx) != 0)
704                                 continue;
705
706                         outstanding++;
707                         ifctx->outstanding = 1;
708
709                         /* Proceed to next step in DHCP negotiation */
710                         if ((ifctx->state == IF_DHCP_OFFERED &&
711                              ifctx->dhcpquerytype != DHCP_REQUEST) ||
712                             (ifctx->state == IF_DHCP_UNRESOLVED &&
713                              ifctx->dhcpquerytype != DHCP_DISCOVER) ||
714                             (ifctx->state == IF_BOOTP_UNRESOLVED &&
715                              ifctx->dhcpquerytype != DHCP_NOMSG)) {
716                                 ifctx->sentmsg = 0;
717                                 bootpc_compose_query(ifctx, gctx, td);
718                         }
719                         
720                         /* Send BOOTP request (or re-send). */
721                 
722                         if (ifctx->sentmsg == 0) {
723                                 switch(ifctx->dhcpquerytype) {
724                                 case DHCP_DISCOVER:
725                                         s = "DHCP Discover";
726                                         break;
727                                 case DHCP_REQUEST:
728                                         s = "DHCP Request";
729                                         break;
730                                 case DHCP_NOMSG:
731                                 default:
732                                         s = "BOOTP Query";
733                                         break;
734                                 }
735                                 printf("Sending %s packet from "
736                                        "interface %s (%*D)\n",
737                                        s,
738                                        ifctx->ireq.ifr_name,
739                                        ifctx->sdl->sdl_alen,
740                                        (unsigned char *) LLADDR(ifctx->sdl),
741                                        ":");
742                                 ifctx->sentmsg = 1;
743                         }
744
745                         aio.iov_base = (caddr_t) &ifctx->call;
746                         aio.iov_len = sizeof(ifctx->call);
747                         
748                         auio.uio_iov = &aio;
749                         auio.uio_iovcnt = 1;
750                         auio.uio_segflg = UIO_SYSSPACE;
751                         auio.uio_rw = UIO_WRITE;
752                         auio.uio_offset = 0;
753                         auio.uio_resid = sizeof(ifctx->call);
754                         auio.uio_td = td;
755                         
756                         /* Set netmask to 0.0.0.0 */
757                         
758                         sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
759                         clear_sinaddr(sin);
760                         error = ifioctl(ifctx->so, SIOCSIFNETMASK,
761                                         (caddr_t) &ifctx->ireq, td);
762                         if (error != 0)
763                                 panic("bootpc_call:"
764                                       "set if netmask, error=%d",
765                                       error);
766         
767                         error = sosend(so, (struct sockaddr *) &dst,
768                                        &auio, NULL, NULL, 0, td);
769                         if (error != 0) {
770                                 printf("bootpc_call: sosend: %d state %08x\n",
771                                        error, (int) so->so_state);
772                         }
773
774                         /* XXX: Is this needed ? */
775                         tsleep(&error, 0, "bootpw", 10);
776                         
777                         /* Set netmask to 255.0.0.0 */
778                         
779                         sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
780                         clear_sinaddr(sin);
781                         sin->sin_addr.s_addr = htonl(0xff000000u);
782                         error = ifioctl(ifctx->so, SIOCSIFNETMASK,
783                                         (caddr_t) &ifctx->ireq, td);
784                         if (error != 0)
785                                 panic("bootpc_call:"
786                                       "set if netmask, error=%d",
787                                       error);
788                         
789                 }
790                 
791                 if (outstanding == 0 &&
792                     (rtimo == 0 || time_second >= rtimo)) {
793                         error = 0;
794                         goto gotreply;
795                 }
796                 
797                 /* Determine new timeout. */
798                 if (timo < MAX_RESEND_DELAY)
799                         timo++;
800                 else {
801                         printf("DHCP/BOOTP timeout for server ");
802                         print_sin_addr(&dst);
803                         printf("\n");
804                 }
805                 
806                 /*
807                  * Wait for up to timo seconds for a reply.
808                  * The socket receive timeout was set to 1 second.
809                  */
810                 atimo = timo + time_second;
811                 while (time_second < atimo) {
812                         aio.iov_base = (caddr_t) &gctx->reply;
813                         aio.iov_len = sizeof(gctx->reply);
814                         
815                         auio.uio_iov = &aio;
816                         auio.uio_iovcnt = 1;
817                         auio.uio_segflg = UIO_SYSSPACE;
818                         auio.uio_rw = UIO_READ;
819                         auio.uio_offset = 0;
820                         auio.uio_resid = sizeof(gctx->reply);
821                         auio.uio_td = td;
822                         
823                         rcvflg = 0;
824                         error = soreceive(so, NULL, &auio,
825                                           NULL, NULL, &rcvflg);
826                         gctx->secs = time_second - gctx->starttime;
827                         for (ifctx = gctx->interfaces;
828                              ifctx != NULL;
829                              ifctx = ifctx->next) {
830                                 if (bootpc_ifctx_isresolved(ifctx) != 0 ||
831                                     bootpc_ifctx_isfailed(ifctx) != 0)
832                                         continue;
833                                 
834                                 ifctx->call.secs = htons(gctx->secs);
835                         }
836                         if (error == EWOULDBLOCK)
837                                 continue;
838                         if (error != 0)
839                                 goto out;
840                         len = sizeof(gctx->reply) - auio.uio_resid;
841                         
842                         /* Do we have the required number of bytes ? */
843                         if (len < BOOTP_MIN_LEN)
844                                 continue;
845                         gctx->replylen = len;
846                         
847                         /* Is it a reply? */
848                         if (gctx->reply.op != BOOTP_REPLY)
849                                 continue;
850                         
851                         /* Is this an answer to our query */
852                         for (ifctx = gctx->interfaces;
853                              ifctx != NULL;
854                              ifctx = ifctx->next) {
855                                 if (gctx->reply.xid != ifctx->call.xid)
856                                         continue;
857                                 
858                                 /* Same HW address size ? */
859                                 if (gctx->reply.hlen != ifctx->call.hlen)
860                                         continue;
861                                 
862                                 /* Correct HW address ? */
863                                 if (bcmp(gctx->reply.chaddr,
864                                          ifctx->call.chaddr,
865                                          ifctx->call.hlen) != 0)
866                                         continue;
867
868                                 break;
869                         }
870
871                         if (ifctx != NULL) {
872                                 s =  bootpc_tag(&gctx->tmptag,
873                                                 &gctx->reply,
874                                                 gctx->replylen,
875                                                 TAG_DHCP_MSGTYPE);
876                                 if (s != NULL) {
877                                         switch (*s) {
878                                         case DHCP_OFFER:
879                                                 s = "DHCP Offer";
880                                                 break;
881                                         case DHCP_ACK:
882                                                 s = "DHCP Ack";
883                                                 break;
884                                         default:
885                                                 s = "DHCP (unexpected)";
886                                                 break;
887                                         }
888                                 } else
889                                         s = "BOOTP Reply";
890
891                                 printf("Received %s packet"
892                                        " on %s from ",
893                                        s,
894                                        ifctx->ireq.ifr_name);
895                                 print_in_addr(gctx->reply.siaddr);
896                                 if (gctx->reply.giaddr.s_addr !=
897                                     htonl(INADDR_ANY)) {
898                                         printf(" via ");
899                                         print_in_addr(gctx->reply.giaddr);
900                                 }
901                                 if (bootpc_received(gctx, ifctx) != 0) {
902                                         printf(" (accepted)");
903                                         if (ifctx->outstanding) {
904                                                 ifctx->outstanding = 0;
905                                                 outstanding--;
906                                         }
907                                         /* Network settle delay */
908                                         if (outstanding == 0)
909                                                 atimo = time_second +
910                                                         BOOTP_SETTLE_DELAY;
911                                 } else
912                                         printf(" (ignored)");
913                                 if (ifctx->gotrootpath) {
914                                         gotrootpath = 1;
915                                         rtimo = time_second +
916                                                 BOOTP_SETTLE_DELAY;
917                                         printf(" (got root path)");
918                                 } else
919                                         printf(" (no root path)");
920                                 printf("\n");
921                         }
922                 } /* while secs */
923 #ifdef BOOTP_TIMEOUT
924                 if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
925                         break;
926 #endif
927                 /* Force a retry if halfway in DHCP negotiation */
928                 retry = 0;
929                 for (ifctx = gctx->interfaces; ifctx != NULL;
930                      ifctx = ifctx->next) {
931                         if (ifctx->state == IF_DHCP_OFFERED) {
932                                 if (ifctx->dhcpquerytype == DHCP_DISCOVER)
933                                         retry = 1;
934                                 else
935                                         ifctx->state = IF_DHCP_UNRESOLVED;
936                         }
937                 }
938                 
939                 if (retry != 0)
940                         continue;
941                 
942                 if (gotrootpath != 0) {
943                         gctx->gotrootpath = gotrootpath;
944                         if (rtimo != 0 && time_second >= rtimo)
945                                 break;
946                 }
947         } /* forever send/receive */
948         
949         /* 
950          * XXX: These are errors of varying seriousness being silently
951          * ignored
952          */
953
954         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
955                 if (bootpc_ifctx_isresolved(ifctx) == 0) {
956                         printf("%s timeout for interface %s\n",
957                                ifctx->dhcpquerytype != DHCP_NOMSG ?
958                                "DHCP" : "BOOTP",
959                                ifctx->ireq.ifr_name);
960                 }
961         }
962         if (gctx->gotrootpath != 0) {
963 #if 0
964                 printf("Got a root path, ignoring remaining timeout\n");
965 #endif
966                 error = 0;
967                 goto out;
968         }
969 #ifndef BOOTP_NFSROOT
970         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
971                 if (bootpc_ifctx_isresolved(ifctx) != 0) {
972                         error = 0;
973                         goto out;
974                 }
975         }
976 #endif
977         error = ETIMEDOUT;
978         goto out;
979         
980 gotreply:
981 out:
982         soclose(so);
983         return error;
984 }
985
986
987 static int
988 bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
989                         struct bootpc_globalcontext *gctx,
990                         struct thread *td)
991 {
992         struct sockaddr_in *sin;
993         int error;
994         
995         struct ifreq *ireq;
996         struct socket *so;
997         struct ifaddr *ifa;
998         struct sockaddr_dl *sdl;
999
1000         error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0, td);
1001         if (error != 0)
1002                 panic("nfs_boot: socreate, error=%d", error);
1003         
1004         ireq = &ifctx->ireq;
1005         so = ifctx->so;
1006
1007         /*
1008          * Bring up the interface.
1009          *
1010          * Get the old interface flags and or IFF_UP into them; if
1011          * IFF_UP set blindly, interface selection can be clobbered.
1012          */
1013         error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td);
1014         if (error != 0)
1015                 panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error);
1016         ireq->ifr_flags |= IFF_UP;
1017         error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td);
1018         if (error != 0)
1019                 panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error);
1020         
1021         /*
1022          * Do enough of ifconfig(8) so that the chosen interface
1023          * can talk to the servers.  (just set the address)
1024          */
1025         
1026         /* addr is 0.0.0.0 */
1027         
1028         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1029         clear_sinaddr(sin);
1030         error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td);
1031         if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
1032                 panic("bootpc_fakeup_interface: "
1033                       "set if addr, error=%d", error);
1034         
1035         /* netmask is 255.0.0.0 */
1036         
1037         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1038         clear_sinaddr(sin);
1039         sin->sin_addr.s_addr = htonl(0xff000000u);
1040         error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, td);
1041         if (error != 0)
1042                 panic("bootpc_fakeup_interface: set if netmask, error=%d",
1043                       error);
1044         
1045         /* Broadcast is 255.255.255.255 */
1046         
1047         sin = (struct sockaddr_in *)&ireq->ifr_addr;
1048         clear_sinaddr(sin);
1049         clear_sinaddr(&ifctx->broadcast);
1050         sin->sin_addr.s_addr = htonl(INADDR_BROADCAST);
1051         ifctx->broadcast.sin_addr.s_addr = sin->sin_addr.s_addr;
1052         
1053         error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, td);
1054         if (error != 0 && error != EADDRNOTAVAIL)
1055                 panic("bootpc_fakeup_interface: "
1056                       "set if broadcast addr, error=%d",
1057                       error);
1058         error = 0;
1059         
1060         /* Get HW address */
1061         
1062         sdl = NULL;
1063         for (ifa = TAILQ_FIRST(&ifctx->ifp->if_addrhead);
1064              ifa != NULL;
1065              ifa = TAILQ_NEXT(ifa,ifa_link))
1066                 if (ifa->ifa_addr->sa_family == AF_LINK &&
1067                     (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) != NULL &&
1068                     sdl->sdl_type == IFT_ETHER)
1069                         break;
1070         
1071         if (sdl == NULL)
1072                 panic("bootpc: Unable to find HW address for %s",
1073                       ifctx->ireq.ifr_name);
1074         ifctx->sdl = sdl;
1075         
1076         return error;
1077 }
1078
1079
1080 static int
1081 bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
1082                         struct bootpc_globalcontext *gctx,
1083                         struct thread *td)
1084 {
1085         int error;
1086         struct sockaddr_in defdst;
1087         struct sockaddr_in defmask;
1088         struct sockaddr_in *sin;
1089         
1090         struct ifreq *ireq;
1091         struct socket *so;
1092         struct sockaddr_in *myaddr;
1093         struct sockaddr_in *netmask;
1094         struct sockaddr_in *gw;
1095
1096         ireq = &ifctx->ireq;
1097         so = ifctx->so;
1098         myaddr = &ifctx->myaddr;
1099         netmask = &ifctx->netmask;
1100         gw = &ifctx->gw;
1101
1102         if (bootpc_ifctx_isresolved(ifctx) == 0) {
1103
1104                 /* Shutdown interfaces where BOOTP failed */
1105                 
1106                 printf("Shutdown interface %s\n", ifctx->ireq.ifr_name);
1107                 error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td);
1108                 if (error != 0)
1109                         panic("bootpc_adjust_interface: "
1110                               "SIOCGIFFLAGS, error=%d", error);
1111                 ireq->ifr_flags &= ~IFF_UP;
1112                 error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td);
1113                 if (error != 0)
1114                         panic("bootpc_adjust_interface: "
1115                               "SIOCSIFFLAGS, error=%d", error);
1116                 
1117                 sin = (struct sockaddr_in *) &ireq->ifr_addr;
1118                 clear_sinaddr(sin);
1119                 error = ifioctl(so, SIOCDIFADDR, (caddr_t) ireq, td);
1120                 if (error != 0 && (error != EADDRNOTAVAIL ||
1121                                    ifctx == gctx->interfaces))
1122                         panic("bootpc_adjust_interface: "
1123                               "SIOCDIFADDR, error=%d", error);
1124                 
1125                 return 0;
1126         }
1127
1128         printf("Adjusted interface %s\n", ifctx->ireq.ifr_name);
1129         /*
1130          * Do enough of ifconfig(8) so that the chosen interface
1131          * can talk to the servers.  (just set the address)
1132          */
1133         bcopy(netmask, &ireq->ifr_addr, sizeof(*netmask));
1134         error = ifioctl(so, SIOCSIFNETMASK, (caddr_t) ireq, td);
1135         if (error != 0)
1136                 panic("bootpc_adjust_interface: "
1137                       "set if netmask, error=%d", error);
1138         
1139         /* Broadcast is with host part of IP address all 1's */
1140         
1141         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1142         clear_sinaddr(sin);
1143         sin->sin_addr.s_addr = myaddr->sin_addr.s_addr |
1144                 ~ netmask->sin_addr.s_addr;
1145         error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t) ireq, td);
1146         if (error != 0)
1147                 panic("bootpc_adjust_interface: "
1148                       "set if broadcast addr, error=%d", error);
1149         
1150         bcopy(myaddr, &ireq->ifr_addr, sizeof(*myaddr));
1151         error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td);
1152         if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
1153                 panic("bootpc_adjust_interface: "
1154                       "set if addr, error=%d", error);
1155         
1156         /* Add new default route */
1157
1158         if (ifctx->gotgw != 0 || gctx->gotgw == 0) {
1159                 clear_sinaddr(&defdst);
1160                 clear_sinaddr(&defmask);
1161                 error = rtrequest(RTM_ADD,
1162                                   (struct sockaddr *) &defdst,
1163                                   (struct sockaddr *) gw,
1164                                   (struct sockaddr *) &defmask,
1165                                   (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
1166                 if (error != 0) {
1167                         printf("bootpc_adjust_interface: "
1168                                "add net route, error=%d\n", error);
1169                         return error;
1170                 }
1171         }
1172         
1173         return 0;
1174 }
1175
1176
1177 static int
1178 setfs(struct sockaddr_in *addr, char *path, char *p)
1179 {
1180         unsigned int ip;
1181         int val;
1182         
1183         ip = 0;
1184         if (((val = getdec(&p)) < 0) || (val > 255))
1185                 return 0;
1186         ip = val << 24;
1187         if (*p != '.')
1188                 return 0;
1189         p++;
1190         if (((val = getdec(&p)) < 0) || (val > 255))
1191                 return 0;
1192         ip |= (val << 16);
1193         if (*p != '.')
1194                 return 0;
1195         p++;
1196         if (((val = getdec(&p)) < 0) || (val > 255))
1197                 return 0;
1198         ip |= (val << 8);
1199         if (*p != '.')
1200                 return 0;
1201         p++;
1202         if (((val = getdec(&p)) < 0) || (val > 255))
1203                 return 0;
1204         ip |= val;
1205         if (*p != ':')
1206                 return 0;
1207         p++;
1208         
1209         addr->sin_addr.s_addr = htonl(ip);
1210         addr->sin_len = sizeof(struct sockaddr_in);
1211         addr->sin_family = AF_INET;
1212         
1213         strncpy(path, p, MNAMELEN - 1);
1214         return 1;
1215 }
1216
1217
1218 static int
1219 getdec(char **ptr)
1220 {
1221         char *p;
1222         int ret;
1223
1224         p = *ptr;
1225         ret = 0;
1226         if ((*p < '0') || (*p > '9'))
1227                 return -1;
1228         while ((*p >= '0') && (*p <= '9')) {
1229                 ret = ret * 10 + (*p - '0');
1230                 p++;
1231         }
1232         *ptr = p;
1233         return ret;
1234 }
1235
1236
1237 static char *
1238 substr(char *a, char *b)
1239 {
1240         char *loc1;
1241         char *loc2;
1242         
1243         while (*a != '\0') {
1244                 loc1 = a;
1245                 loc2 = b;
1246                 while (*loc1 == *loc2++) {
1247                         if (*loc1 == '\0')
1248                                 return 0;
1249                         loc1++;
1250                         if (*loc2 == '\0')
1251                                 return loc1;
1252                 }
1253                 a++;
1254         }
1255         return 0;
1256 }
1257
1258
1259 static void
1260 mountopts(struct nfs_args *args, char *p)
1261 {
1262         char *tmp;
1263         
1264         args->version = NFS_ARGSVERSION;
1265         args->rsize = 8192;
1266         args->wsize = 8192;
1267         args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
1268         args->sotype = SOCK_DGRAM;
1269         if (p == NULL)
1270                 return;
1271         if ((tmp = (char *)substr(p, "rsize=")))
1272                 args->rsize = getdec(&tmp);
1273         if ((tmp = (char *)substr(p, "wsize=")))
1274                 args->wsize = getdec(&tmp);
1275         if ((tmp = (char *)substr(p, "intr")))
1276                 args->flags |= NFSMNT_INT;
1277         if ((tmp = (char *)substr(p, "soft")))
1278                 args->flags |= NFSMNT_SOFT;
1279         if ((tmp = (char *)substr(p, "noconn")))
1280                 args->flags |= NFSMNT_NOCONN;
1281         if ((tmp = (char *)substr(p, "tcp")))
1282                 args->sotype = SOCK_STREAM;
1283 }
1284
1285
1286 static int
1287 xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
1288 {
1289         struct mbuf *m;
1290         int alignedlen;
1291         
1292         m = *mptr;
1293         alignedlen = ( len + 3 ) & ~3;
1294         
1295         if (m->m_len < alignedlen) {
1296                 m = m_pullup(m, alignedlen);
1297                 if (m == NULL) {
1298                         *mptr = NULL;
1299                         return EBADRPC;
1300                 }
1301         }
1302         bcopy(mtod(m, u_char *), buf, len);
1303         m_adj(m, alignedlen);
1304         *mptr = m;
1305         return 0;
1306 }
1307
1308
1309 static int
1310 xdr_int_decode(struct mbuf **mptr, int *iptr)
1311 {
1312         u_int32_t i;
1313         if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
1314                 return EBADRPC;
1315         *iptr = fxdr_unsigned(u_int32_t, i);
1316         return 0;
1317 }
1318
1319
1320 static void
1321 print_sin_addr(struct sockaddr_in *sin)
1322 {
1323         print_in_addr(sin->sin_addr);
1324 }
1325
1326
1327 static void
1328 print_in_addr(struct in_addr addr)
1329 {
1330         unsigned int ip;
1331         
1332         ip = ntohl(addr.s_addr);
1333         printf("%d.%d.%d.%d",
1334                ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
1335 }
1336
1337 static void
1338 bootpc_compose_query(ifctx, gctx, td)
1339         struct bootpc_ifcontext *ifctx;
1340         struct bootpc_globalcontext *gctx;
1341         struct thread *td;
1342 {
1343         unsigned char *vendp;
1344         unsigned char vendor_client[64];
1345         uint32_t leasetime;
1346         uint8_t vendor_client_len;
1347
1348         ifctx->gotrootpath = 0;
1349
1350         bzero((caddr_t) &ifctx->call, sizeof(ifctx->call));
1351         
1352         /* bootpc part */
1353         ifctx->call.op = BOOTP_REQUEST;         /* BOOTREQUEST */
1354         ifctx->call.htype = 1;                  /* 10mb ethernet */
1355         ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */
1356         ifctx->call.hops = 0;
1357         if (bootpc_ifctx_isunresolved(ifctx) != 0)
1358                 ifctx->xid++;
1359         ifctx->call.xid = txdr_unsigned(ifctx->xid);
1360         bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen);
1361         
1362         vendp = ifctx->call.vend;
1363         *vendp++ = 99;          /* RFC1048 cookie */
1364         *vendp++ = 130;
1365         *vendp++ = 83;
1366         *vendp++ = 99;
1367         *vendp++ = TAG_MAXMSGSIZE;
1368         *vendp++ = 2;
1369         *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255;
1370         *vendp++ = sizeof(struct bootp_packet) & 255;
1371
1372         snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s",
1373                 ostype, MACHINE, osrelease);
1374         vendor_client_len = strlen(vendor_client);
1375         *vendp++ = TAG_VENDOR_INDENTIFIER;
1376         *vendp++ = vendor_client_len;
1377         memcpy(vendp, vendor_client, vendor_client_len);
1378         vendp += vendor_client_len;;
1379         ifctx->dhcpquerytype = DHCP_NOMSG;
1380         switch (ifctx->state) {
1381         case IF_DHCP_UNRESOLVED:
1382                 *vendp++ = TAG_DHCP_MSGTYPE;
1383                 *vendp++ = 1;
1384                 *vendp++ = DHCP_DISCOVER;
1385                 ifctx->dhcpquerytype = DHCP_DISCOVER;
1386                 ifctx->gotdhcpserver = 0;
1387                 break;
1388         case IF_DHCP_OFFERED:
1389                 *vendp++ = TAG_DHCP_MSGTYPE;
1390                 *vendp++ = 1;
1391                 *vendp++ = DHCP_REQUEST;
1392                 ifctx->dhcpquerytype = DHCP_REQUEST;
1393                 *vendp++ = TAG_DHCP_REQ_ADDR;
1394                 *vendp++ = 4;
1395                 memcpy(vendp, &ifctx->reply.yiaddr, 4);
1396                 vendp += 4;
1397                 if (ifctx->gotdhcpserver != 0) {
1398                         *vendp++ = TAG_DHCP_SERVERID;
1399                         *vendp++ = 4;
1400                         memcpy(vendp, &ifctx->dhcpserver, 4);
1401                         vendp += 4;
1402                 }
1403                 *vendp++ = TAG_DHCP_LEASETIME;
1404                 *vendp++ = 4;
1405                 leasetime = htonl(300);
1406                 memcpy(vendp, &leasetime, 4);
1407                 vendp += 4;
1408         default:
1409                 ;
1410         }
1411         *vendp = TAG_END;
1412         
1413         ifctx->call.secs = 0;
1414         ifctx->call.flags = htons(0x8000); /* We need an broadcast answer */
1415 }
1416
1417
1418 static int
1419 bootpc_hascookie(struct bootp_packet *bp)
1420 {
1421         return (bp->vend[0] == 99 && bp->vend[1] == 130 &&
1422                 bp->vend[2] == 83 && bp->vend[3] == 99);
1423 }
1424
1425
1426 static void
1427 bootpc_tag_helper(struct bootpc_tagcontext *tctx,
1428                   unsigned char *start,
1429                   int len,
1430                   int tag)
1431 {
1432         unsigned char *j;
1433         unsigned char *ej;
1434         unsigned char code;
1435
1436         if (tctx->badtag != 0 || tctx->badopt != 0)
1437                 return;
1438         
1439         j = start;
1440         ej = j + len;
1441         
1442         while (j < ej) {
1443                 code = *j++;
1444                 if (code == TAG_PAD)
1445                         continue;
1446                 if (code == TAG_END)
1447                         return;
1448                 if (j >= ej || j + *j + 1 > ej) {
1449                         tctx->badopt = 1;
1450                         return;
1451                 }
1452                 len = *j++;
1453                 if (code == tag) {
1454                         if (tctx->taglen + len > TAG_MAXLEN) {
1455                                 tctx->badtag = 1;
1456                                 return;
1457                         }
1458                         tctx->foundopt = 1;
1459                         if (len > 0)
1460                                 memcpy(tctx->buf + tctx->taglen,
1461                                        j, len);
1462                         tctx->taglen += len;
1463                 }
1464                 if (code == TAG_OVERLOAD)
1465                         tctx->overload = *j;
1466                 
1467                 j += len;
1468         }
1469 }
1470
1471
1472 static unsigned char *
1473 bootpc_tag(struct bootpc_tagcontext *tctx,
1474            struct bootp_packet *bp,
1475            int len,
1476            int tag)
1477 {
1478         unsigned char *j;
1479         unsigned char *ej;
1480
1481         tctx->overload = 0;
1482         tctx->badopt = 0;
1483         tctx->badtag = 0;
1484         tctx->foundopt = 0;
1485         tctx->taglen = 0;
1486
1487         if (bootpc_hascookie(bp) == 0)
1488                 return NULL;
1489         
1490         j = &bp->vend[4];
1491         ej = (unsigned char *) bp + len;
1492
1493         bootpc_tag_helper(tctx, &bp->vend[4],
1494                           (unsigned char *) bp + len - &bp->vend[4], tag);
1495         
1496         if ((tctx->overload & OVERLOAD_FILE) != 0)
1497                 bootpc_tag_helper(tctx,
1498                                   (unsigned char *) bp->file,
1499                                   sizeof(bp->file),
1500                                   tag);
1501         if ((tctx->overload & OVERLOAD_SNAME) != 0)
1502                 bootpc_tag_helper(tctx,
1503                                   (unsigned char *) bp->sname,
1504                                   sizeof(bp->sname),
1505                                   tag);
1506         
1507         if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0)
1508                 return NULL;
1509         tctx->buf[tctx->taglen] = '\0';
1510         return tctx->buf;
1511 }
1512
1513
1514 static void
1515 bootpc_decode_reply(nd, ifctx, gctx)
1516         struct nfsv3_diskless *nd;
1517         struct bootpc_ifcontext *ifctx;
1518         struct bootpc_globalcontext *gctx;
1519 {
1520         char *p;
1521         unsigned int ip;
1522
1523         ifctx->gotgw = 0;
1524         ifctx->gotnetmask = 0;
1525
1526         clear_sinaddr(&ifctx->myaddr);
1527         clear_sinaddr(&ifctx->netmask);
1528         clear_sinaddr(&ifctx->gw);
1529         
1530         ifctx->myaddr.sin_addr = ifctx->reply.yiaddr;
1531         
1532         ip = ntohl(ifctx->myaddr.sin_addr.s_addr);
1533         snprintf(gctx->lookup_path, sizeof(gctx->lookup_path),
1534                  "swap.%d.%d.%d.%d",
1535                  ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
1536         
1537         printf("%s at ", ifctx->ireq.ifr_name);
1538         print_sin_addr(&ifctx->myaddr);
1539         printf(" server ");
1540         print_in_addr(ifctx->reply.siaddr);
1541         
1542         ifctx->gw.sin_addr = ifctx->reply.giaddr;
1543         if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) {
1544                 printf(" via gateway ");
1545                 print_in_addr(ifctx->reply.giaddr);
1546         }
1547
1548         /* This call used for the side effect (overload flag) */
1549         (void) bootpc_tag(&gctx->tmptag,
1550                           &ifctx->reply, ifctx->replylen, TAG_END);
1551         
1552         if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0)
1553                 if (ifctx->reply.sname[0] != '\0')
1554                         printf(" server name %s", ifctx->reply.sname);
1555         if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0)
1556                 if (ifctx->reply.file[0] != '\0')
1557                         printf(" boot file %s", ifctx->reply.file);
1558         
1559         printf("\n");
1560
1561         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1562                        TAG_SUBNETMASK);
1563         if (p != NULL) {
1564                 if (gctx->tag.taglen != 4)
1565                         panic("bootpc: subnet mask len is %d",
1566                               gctx->tag.taglen);
1567                 bcopy(p, &ifctx->netmask.sin_addr, 4);
1568                 ifctx->gotnetmask = 1;
1569                 printf("subnet mask ");
1570                 print_sin_addr(&ifctx->netmask);
1571                 printf(" ");
1572         }
1573         
1574         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1575                        TAG_ROUTERS);
1576         if (p != NULL) {
1577                 /* Routers */
1578                 if (gctx->tag.taglen % 4)
1579                         panic("bootpc: Router Len is %d", gctx->tag.taglen);
1580                 if (gctx->tag.taglen > 0) {
1581                         bcopy(p, &ifctx->gw.sin_addr, 4);
1582                         printf("router ");
1583                         print_sin_addr(&ifctx->gw);
1584                         printf(" ");
1585                         ifctx->gotgw = 1;
1586                         gctx->gotgw = 1;
1587                 }
1588         }
1589         
1590         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1591                        TAG_ROOT);
1592         if (p != NULL) {
1593                 if (gctx->setrootfs != NULL) {
1594                         printf("rootfs %s (ignored) ", p);
1595                 } else  if (setfs(&nd->root_saddr,
1596                                   nd->root_hostnam, p)) {
1597                         printf("rootfs %s ",p);
1598                         gctx->gotrootpath = 1;
1599                         ifctx->gotrootpath = 1;
1600                         gctx->setrootfs = ifctx;
1601                         
1602                         p = bootpc_tag(&gctx->tag, &ifctx->reply,
1603                                        ifctx->replylen,
1604                                        TAG_ROOTOPTS);
1605                         if (p != NULL) {
1606                                 mountopts(&nd->root_args, p);
1607                                 printf("rootopts %s ", p);
1608                         }
1609                 } else
1610                         panic("Failed to set rootfs to %s",p);
1611         }
1612
1613         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1614                        TAG_SWAP);
1615         if (p != NULL) {
1616                 if (gctx->setswapfs != NULL) {
1617                         printf("swapfs %s (ignored) ", p);
1618                 } else  if (setfs(&nd->swap_saddr,
1619                                   nd->swap_hostnam, p)) {
1620                         gctx->gotswappath = 1;
1621                         gctx->setswapfs = ifctx;
1622                         printf("swapfs %s ", p);
1623
1624                         p = bootpc_tag(&gctx->tag, &ifctx->reply,
1625                                        ifctx->replylen,
1626                                        TAG_SWAPOPTS);
1627                         if (p != NULL) {
1628                                 /* swap mount options */
1629                                 mountopts(&nd->swap_args, p);
1630                                 printf("swapopts %s ", p);
1631                         }
1632                         
1633                         p = bootpc_tag(&gctx->tag, &ifctx->reply,
1634                                        ifctx->replylen,
1635                                        TAG_SWAPSIZE);
1636                         if (p != NULL) {
1637                                 int swaplen;
1638                                 if (gctx->tag.taglen != 4)
1639                                         panic("bootpc: "
1640                                               "Expected 4 bytes for swaplen, "
1641                                               "not %d bytes",
1642                                               gctx->tag.taglen);
1643                                 bcopy(p, &swaplen, 4);
1644                                 nd->swap_nblks = ntohl(swaplen);
1645                                 printf("swapsize %d KB ",
1646                                        nd->swap_nblks);
1647                         }
1648                 } else
1649                         panic("Failed to set swapfs to %s", p);
1650         }
1651
1652         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1653                        TAG_HOSTNAME);
1654         if (p != NULL) {
1655                 if (gctx->tag.taglen >= MAXHOSTNAMELEN)
1656                         panic("bootpc: hostname >= %d bytes",
1657                               MAXHOSTNAMELEN);
1658                 if (gctx->sethostname != NULL) {
1659                         printf("hostname %s (ignored) ", p);
1660                 } else {
1661                         strcpy(nd->my_hostnam, p);
1662                         strcpy(hostname, p);
1663                         printf("hostname %s ",hostname);
1664                         gctx->sethostname = ifctx;
1665                 }
1666         }
1667         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1668                        TAG_COOKIE);
1669         if (p != NULL) {        /* store in a sysctl variable */
1670                 int i, l = sizeof(bootp_cookie) - 1;
1671                 for (i = 0; i < l && p[i] != '\0'; i++)
1672                         bootp_cookie[i] = p[i];
1673                 p[i] = '\0';
1674         }
1675
1676         printf("\n");
1677         
1678         if (ifctx->gotnetmask == 0) {
1679                 if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr)))
1680                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1681                 else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr)))
1682                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1683                 else
1684                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1685         }
1686         if (ifctx->gotgw == 0) {
1687                 /* Use proxyarp */
1688                 ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr;
1689         }
1690 }
1691
1692 void
1693 bootpc_init(void)
1694 {
1695         struct bootpc_ifcontext *ifctx, *nctx;  /* Interface BOOTP contexts */
1696         struct bootpc_globalcontext *gctx;      /* Global BOOTP context */
1697         struct ifnet *ifp;
1698         int error;
1699         struct nfsv3_diskless *nd;
1700         struct thread *td;
1701
1702         nd = &nfsv3_diskless;
1703         td = curthread;
1704         
1705         /*
1706          * If already filled in, don't touch it here
1707          */
1708         if (nfs_diskless_valid != 0)
1709                 return;
1710
1711         /*
1712          * Wait until arp entries can be handled.
1713          */
1714         while (time_second == 0)
1715                 tsleep(&time_second, 0, "arpkludge", 10);
1716         
1717         gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK);
1718         if (gctx == NULL)
1719                 panic("Failed to allocate bootp global context structure");
1720         
1721         bzero(gctx, sizeof(*gctx));
1722         gctx->xid = ~0xFFFF;
1723         gctx->starttime = time_second;
1724         
1725         ifctx = allocifctx(gctx);
1726
1727         /*
1728          * Find a network interface.
1729          */
1730 #ifdef BOOTP_WIRED_TO
1731         printf("bootpc_init: wired to interface '%s'\n",
1732                __XSTRING(BOOTP_WIRED_TO));
1733 #endif
1734         bzero(&ifctx->ireq, sizeof(ifctx->ireq));
1735         for (ifp = TAILQ_FIRST(&ifnet);
1736              ifp != NULL;
1737              ifp = TAILQ_NEXT(ifp, if_link)) {
1738                 strlcpy(ifctx->ireq.ifr_name, ifp->if_xname,
1739                          sizeof(ifctx->ireq.ifr_name));
1740 #ifdef BOOTP_WIRED_TO
1741                 if (strcmp(ifctx->ireq.ifr_name,
1742                            __XSTRING(BOOTP_WIRED_TO)) != 0)
1743                         continue;
1744 #else
1745                 if ((ifp->if_flags &
1746                      (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
1747                     IFF_BROADCAST)
1748                         continue;
1749 #endif
1750                 if (gctx->interfaces != NULL)
1751                         gctx->lastinterface->next = ifctx;
1752                 else
1753                         gctx->interfaces = ifctx;
1754                 ifctx->ifp = ifp;
1755                 gctx->lastinterface = ifctx;
1756                 ifctx = allocifctx(gctx);
1757         }
1758         free(ifctx, M_TEMP);
1759         
1760         if (gctx->interfaces == NULL) {
1761 #ifdef BOOTP_WIRED_TO
1762                 panic("bootpc_init: Could not find interface specified "
1763                       "by BOOTP_WIRED_TO: "
1764                       __XSTRING(BOOTP_WIRED_TO));
1765 #else
1766                 panic("bootpc_init: no suitable interface");
1767 #endif
1768         }
1769                 
1770         gctx->gotrootpath = 0;
1771         gctx->gotswappath = 0;
1772         gctx->gotgw = 0;
1773         
1774         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1775                 bootpc_fakeup_interface(ifctx, gctx, td);
1776         
1777         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1778                 bootpc_compose_query(ifctx, gctx, td);
1779         
1780         ifctx = gctx->interfaces;
1781         error = bootpc_call(gctx, td);
1782         
1783         if (error != 0) {
1784 #ifdef BOOTP_NFSROOT
1785                 panic("BOOTP call failed");
1786 #else
1787                 printf("BOOTP call failed\n");
1788 #endif
1789         }
1790         
1791         mountopts(&nd->root_args, NULL);
1792         
1793         mountopts(&nd->swap_args, NULL);
1794
1795         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1796                 if (bootpc_ifctx_isresolved(ifctx) != 0)
1797                         bootpc_decode_reply(nd, ifctx, gctx);
1798         
1799         if (gctx->gotswappath == 0)
1800                 nd->swap_nblks = 0;
1801 #ifdef BOOTP_NFSROOT
1802         if (gctx->gotrootpath == 0)
1803                 panic("bootpc: No root path offered");
1804 #endif
1805         
1806         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
1807                 bootpc_adjust_interface(ifctx, gctx, td);
1808                 
1809                 soclose(ifctx->so);
1810         }
1811
1812         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1813                 if (ifctx->gotrootpath != 0)
1814                         break;
1815         if (ifctx == NULL) {
1816                 for (ifctx = gctx->interfaces;
1817                      ifctx != NULL;
1818                      ifctx = ifctx->next)
1819                         if (bootpc_ifctx_isresolved(ifctx) != 0)
1820                                 break;
1821         }
1822         if (ifctx == NULL)
1823                 goto out;
1824         
1825         if (gctx->gotrootpath != 0) {
1826                 
1827                 error = md_mount(&nd->root_saddr, nd->root_hostnam,
1828                                  nd->root_fh, &nd->root_fhsize,
1829                                  &nd->root_args, td);
1830                 if (error != 0)
1831                         panic("nfs_boot: mountd root, error=%d", error);
1832     
1833                 if (gctx->gotswappath != 0) {
1834                         
1835                         error = md_mount(&nd->swap_saddr,
1836                                          nd->swap_hostnam,
1837                                          nd->swap_fh, &nd->swap_fhsize,
1838                                          &nd->swap_args, td);
1839                         if (error != 0)
1840                                 panic("nfs_boot: mountd swap, error=%d",
1841                                       error);
1842                         
1843                         error = md_lookup_swap(&nd->swap_saddr,
1844                                                gctx->lookup_path,
1845                                                nd->swap_fh, &nd->swap_fhsize,
1846                                                &nd->swap_args, td);
1847                         if (error != 0)
1848                                 panic("nfs_boot: lookup swap, error=%d",
1849                                       error);
1850                 }
1851                 nfs_diskless_valid = 3;
1852         }
1853         
1854         strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name);
1855         bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr));
1856         bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr));
1857         ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
1858                 ifctx->myaddr.sin_addr.s_addr |
1859                 ~ ifctx->netmask.sin_addr.s_addr;
1860         bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask));
1861         
1862 out:
1863         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = nctx) {
1864                 nctx = ifctx->next;
1865                 free(ifctx, M_TEMP);
1866         }
1867         free(gctx, M_TEMP);
1868 }
1869
1870
1871 /*
1872  * RPC: mountd/mount
1873  * Given a server pathname, get an NFS file handle.
1874  * Also, sets sin->sin_port to the NFS service port.
1875  */
1876 static int
1877 md_mount(struct sockaddr_in *mdsin,             /* mountd server address */
1878          char *path,
1879          u_char *fhp,
1880          int *fhsizep,
1881          struct nfs_args *args,
1882          struct thread *td)
1883 {
1884         struct mbuf *m;
1885         int error;
1886         int authunixok;
1887         int authcount;
1888         int authver;
1889         
1890 #ifdef BOOTP_NFSV3
1891         /* First try NFS v3 */
1892         /* Get port number for MOUNTD. */
1893         error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1894                              &mdsin->sin_port, td);
1895         if (error == 0) {
1896                 m = xdr_string_encode(path, strlen(path));
1897                 
1898                 /* Do RPC to mountd. */
1899                 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1900                                   RPCMNT_MOUNT, &m, NULL, td);
1901         }
1902         if (error == 0) {
1903                 args->flags |= NFSMNT_NFSV3;
1904         } else {
1905 #endif
1906                 /* Fallback to NFS v2 */
1907                 
1908                 /* Get port number for MOUNTD. */
1909                 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1910                                      &mdsin->sin_port, td);
1911                 if (error != 0)
1912                         return error;
1913                 
1914                 m = xdr_string_encode(path, strlen(path));
1915                 
1916                 /* Do RPC to mountd. */
1917                 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1918                                   RPCMNT_MOUNT, &m, NULL, td);
1919                 if (error != 0)
1920                         return error;   /* message already freed */
1921                 
1922 #ifdef BOOTP_NFSV3
1923         }
1924 #endif
1925
1926         if (xdr_int_decode(&m, &error) != 0 || error != 0)
1927                 goto bad;
1928         
1929         if ((args->flags & NFSMNT_NFSV3) != 0) {
1930                 if (xdr_int_decode(&m, fhsizep) != 0 ||
1931                     *fhsizep > NFSX_V3FHMAX ||
1932                     *fhsizep <= 0)
1933                         goto bad;
1934         } else
1935                 *fhsizep = NFSX_V2FH;
1936
1937         if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
1938                 goto bad;
1939
1940         if (args->flags & NFSMNT_NFSV3) {
1941                 if (xdr_int_decode(&m, &authcount) != 0)
1942                         goto bad;
1943                 authunixok = 0;
1944                 if (authcount < 0 || authcount > 100)
1945                         goto bad;
1946                 while (authcount > 0) {
1947                         if (xdr_int_decode(&m, &authver) != 0)
1948                                 goto bad;
1949                         if (authver == RPCAUTH_UNIX)
1950                                 authunixok = 1;
1951                         authcount--;
1952                 }
1953                 if (authunixok == 0)
1954                         goto bad;
1955         }
1956           
1957         /* Set port number for NFS use. */
1958         error = krpc_portmap(mdsin, NFS_PROG,
1959                              (args->flags &
1960                               NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
1961                              &mdsin->sin_port, td);
1962         
1963         goto out;
1964         
1965 bad:
1966         error = EBADRPC;
1967         
1968 out:
1969         m_freem(m);
1970         return error;
1971 }
1972
1973
1974 static int
1975 md_lookup_swap(struct sockaddr_in *mdsin,       /* mountd server address */
1976                char *path,
1977                u_char *fhp,
1978                int *fhsizep,
1979                struct nfs_args *args,
1980                struct thread *td)
1981 {
1982         struct mbuf *m;
1983         int error;
1984         int size = -1;
1985         int attribs_present;
1986         int status;
1987         union {
1988                 u_int32_t v2[17];
1989                 u_int32_t v3[21];
1990         } fattribs;
1991         
1992         m = m_get(M_WAIT,MT_DATA);
1993         if (m == NULL)
1994                 return ENOBUFS;
1995         
1996         if ((args->flags & NFSMNT_NFSV3) != 0) {
1997                 *mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
1998                 bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
1999                 m->m_len = *fhsizep + sizeof(u_int32_t);
2000         } else {
2001                 bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
2002                 m->m_len = NFSX_V2FH;
2003         }
2004         
2005         m->m_next = xdr_string_encode(path, strlen(path));
2006         if (m->m_next == NULL) {
2007                 error = ENOBUFS;
2008                 goto out;
2009         }
2010
2011         /* Do RPC to nfsd. */
2012         if ((args->flags & NFSMNT_NFSV3) != 0)
2013                 error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
2014                                   NFSPROC_LOOKUP, &m, NULL, td);
2015         else
2016                 error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
2017                                   NFSV2PROC_LOOKUP, &m, NULL, td);
2018         if (error != 0)
2019                 return error;   /* message already freed */
2020
2021         if (xdr_int_decode(&m, &status) != 0)
2022                 goto bad;
2023         if (status != 0) {
2024                 error = ENOENT;
2025                 goto out;
2026         }
2027         
2028         if ((args->flags & NFSMNT_NFSV3) != 0) {
2029                 if (xdr_int_decode(&m, fhsizep) != 0 ||
2030                     *fhsizep > NFSX_V3FHMAX ||
2031                     *fhsizep <= 0)
2032                         goto bad;
2033         } else
2034                 *fhsizep = NFSX_V2FH;
2035         
2036         if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
2037                 goto bad;
2038         
2039         if ((args->flags & NFSMNT_NFSV3) != 0) {
2040                 if (xdr_int_decode(&m, &attribs_present) != 0)
2041                         goto bad;
2042                 if (attribs_present != 0) {
2043                         if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
2044                                               sizeof(u_int32_t) * 21) != 0)
2045                                 goto bad;
2046                         size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
2047                 }
2048         } else {
2049                 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
2050                                       sizeof(u_int32_t) * 17) != 0)
2051                         goto bad;
2052                 size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
2053         }
2054           
2055         if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
2056                 nfsv3_diskless.swap_nblks = size / 1024;
2057                 printf("md_lookup_swap: Swap size is %d KB\n",
2058                        nfsv3_diskless.swap_nblks);
2059         }
2060         
2061         goto out;
2062         
2063 bad:
2064         error = EBADRPC;
2065         
2066 out:
2067         m_freem(m);
2068         return error;
2069 }