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