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