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