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