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