1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 2018, Joyent, Inc.
28 */
29
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/systm.h>
33 #include <sys/cred.h>
34 #include <sys/user.h>
35 #include <sys/file.h>
36 #include <sys/stream.h>
37 #include <sys/strsubr.h>
38 #include <sys/stropts.h>
39 #include <sys/strsun.h>
40 #include <sys/debug.h>
41 #include <sys/tiuser.h>
42 #include <sys/sockio.h>
43 #include <sys/socket.h>
44 #include <sys/t_kuser.h>
45 #include <sys/utsname.h>
46 #include <sys/systeminfo.h>
47 #include <sys/netconfig.h>
48 #include <sys/ethernet.h>
49 #include <sys/dlpi.h>
50 #include <sys/vfs.h>
51 #include <sys/sysmacros.h>
52 #include <sys/bootconf.h>
53 #include <sys/bootprops.h>
54 #include <sys/cmn_err.h>
55 #include <sys/promif.h>
56 #include <sys/mount.h>
57
58 #include <net/if.h>
59 #include <net/route.h>
60
61 #include <netinet/in.h>
62 #include <netinet/arp.h>
63 #include <netinet/dhcp.h>
64 #include <netinet/inetutil.h>
65 #include <dhcp_impl.h>
66 #include <sys/sunos_dhcp_class.h>
67
68 #include <rpc/types.h>
69 #include <rpc/rpc.h>
70 #include <rpc/xdr.h>
71 #include <rpc/auth.h>
72 #include <rpc/clnt.h>
73 #include <rpc/pmap_clnt.h>
74 #include <rpc/pmap_rmt.h>
75 #include <rpc/pmap_prot.h>
76 #include <rpc/bootparam.h>
77 #include <rpc/rpcb_prot.h>
78
79 #include <nfs/nfs.h>
80 #include <nfs/nfs4.h>
81 #include <nfs/nfs_clnt.h>
82 #include <nfs/mount.h>
83 #include <sys/mntent.h>
84
85 #include <sys/kstr.h>
86 #include <sys/sunddi.h>
87 #include <sys/sunldi.h>
88 #include <sys/esunddi.h>
89
90 #include <sys/errno.h>
91 #include <sys/modctl.h>
92
93 /*
94 * RPC timers and retries
95 */
96 #define PMAP_RETRIES 5
97 #define DEFAULT_RETRIES 3
98 #define GETFILE_RETRIES 2
99
100 #define DEFAULT_TIMEO 3
101 #define WHOAMI_TIMEO 20
102 #define REVARP_TIMEO 5
103 #define GETFILE_TIMEO 1
104
105 /*
106 * These are from the rpcgen'd version of mount.h XXX
107 */
108 #define MOUNTPROG 100005
109 #define MOUNTPROC_MNT 1
110 #define MOUNTVERS 1
111 #define MOUNTVERS_POSIX 2
112 #define MOUNTVERS3 3
113
114 struct fhstatus {
115 int fhs_status;
116 fhandle_t fhs_fh;
117 };
118
119 #define FHSIZE3 64
120
121 struct fhandle3 {
122 uint_t fhandle3_len;
123 char *fhandle3_val;
124 };
125
126 enum mountstat3 {
127 MNT_OK = 0,
128 MNT3ERR_PERM = 1,
129 MNT3ERR_NOENT = 2,
130 MNT3ERR_IO = 5,
131 MNT3ERR_ACCES = 13,
132 MNT3ERR_NOTDIR = 20,
133 MNT3ERR_INVAL = 22,
134 MNT3ERR_NAMETOOLONG = 63,
135 MNT3ERR_NOTSUPP = 10004,
136 MNT3ERR_SERVERFAULT = 10006
137 };
138
139 struct mountres3_ok {
140 struct fhandle3 fhandle;
141 struct {
142 uint_t auth_flavors_len;
143 int *auth_flavors_val;
144 } auth_flavors;
145 };
146
147 struct mountres3 {
148 enum mountstat3 fhs_status;
149 union {
150 struct mountres3_ok mountinfo;
151 } mountres3_u;
152 };
153
154 /*
155 * DLPI address format.
156 */
157 struct dladdr {
158 uchar_t dl_phys[6];
159 ushort_t dl_sap;
160 };
161
162 static struct modlmisc modlmisc = {
163 &mod_miscops, "Boot diskless"
164 };
165
166 static struct modlinkage modlinkage = {
167 MODREV_1, (void *)&modlmisc, NULL
168 };
169
170 static int dldebug;
171
172 int
_init(void)173 _init(void)
174 {
175 return (mod_install(&modlinkage));
176 }
177
178 int
_fini(void)179 _fini(void)
180 {
181 return (mod_remove(&modlinkage));
182 }
183
184 int
_info(struct modinfo * modinfop)185 _info(struct modinfo *modinfop)
186 {
187 return (mod_info(&modlinkage, modinfop));
188 }
189
190
191 static enum clnt_stat pmap_rmt_call(struct knetconfig *, struct netbuf *,
192 bool_t, rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
193 caddr_t, xdrproc_t, caddr_t, struct timeval,
194 struct netbuf *);
195 static bool_t myxdr_rmtcall_args(XDR *, struct rmtcallargs *);
196 static bool_t myxdr_rmtcallres(XDR *, struct rmtcallres *);
197 static bool_t myxdr_pmap(XDR *, struct pmap *);
198 static bool_t myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp);
199 static bool_t myxdr_fhandle(XDR *xdrs, fhandle_t *fh);
200 static bool_t myxdr_mountres3(XDR *xdrs, struct mountres3 *objp);
201 static bool_t myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp);
202 static bool_t myxdr_mountres3_ok(XDR *xdrs,
203 struct mountres3_ok *objp);
204 static bool_t myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp);
205 static enum clnt_stat pmap_kgetport(struct knetconfig *, struct netbuf *,
206 rpcprog_t, rpcvers_t, rpcprot_t);
207 static enum clnt_stat mycallrpc(struct knetconfig *, struct netbuf *,
208 rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
209 char *, xdrproc_t, char *, int, int);
210 static int ifioctl(TIUSER *, int, struct netbuf *);
211 static int getfile(char *, char *, struct netbuf *, char *);
212 static int ping_prog(struct netbuf *, uint_t prog, uint_t vers,
213 int proto, enum clnt_stat *);
214 static int mountnfs(struct netbuf *, char *, char *,
215 fhandle_t *, int *);
216 static int mountnfs3(struct netbuf *, char *, char *,
217 nfs_fh3 *, int *);
218 static int init_mountopts(struct nfs_args *, int,
219 struct knetconfig **, int *);
220 static int revarp_myaddr(TIUSER *);
221 static void revarp_start(ldi_handle_t, struct netbuf *);
222 static void revarpinput(ldi_handle_t, struct netbuf *);
223 static void init_netbuf(struct netbuf *);
224 static void free_netbuf(struct netbuf *);
225 static int rtioctl(TIUSER *, int, struct rtentry *);
226 static void init_config(void);
227
228 static void cacheinit(void);
229 static int cacheinfo(char *, int, struct netbuf *, char *, int);
230 static int dlifconfig(TIUSER *, struct in_addr *, struct in_addr *,
231 struct in_addr *, uint_t);
232 static int setifflags(TIUSER *, uint_t);
233
234 static char *inet_ntoa(struct in_addr);
235 static int inet_aton(char *, uchar_t *);
236 static int isdigit(int);
237
238 /*
239 * Should be in some common
240 * ethernet source file.
241 */
242 static struct ether_addr etherbroadcastaddr = {
243 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
244 };
245
246 static struct ether_addr myether;
247
248 /*
249 * "ifname" is the interface name/unit as read from the boot
250 * arguments.
251 * "ndev" is the major device number of the network interface
252 * used to boot from.
253 * "ifunit" it the physical point of attachment for the network
254 * interface used to boot from.
255 *
256 * Both of these are initialized in "init_config()".
257 */
258
259 static char ifname[IFNAMSIZ];
260 static char ndev_path[MAXPATHLEN];
261 static int ifunit;
262
263 /*
264 * XXX these should be shared
265 */
266 static struct knetconfig dl_udp_netconf = {
267 NC_TPI_CLTS, /* semantics */
268 NC_INET, /* family */
269 NC_UDP, /* protocol */
270 0, /* device */
271 };
272
273 static struct knetconfig dl_tcp_netconf = {
274 NC_TPI_COTS, /* semantics */
275 NC_INET, /* family */
276 NC_TCP, /* protocol */
277 0, /* device */
278 };
279
280 /* parameters from DHCP or bootparamd */
281 static PKT_LIST *pl = NULL;
282 static uchar_t server_ip[4];
283 static uchar_t dhcp_server_ip[4];
284 static char *server_name_c, *server_path_c;
285 static char rootopts[256];
286
287 /*
288 * XXX Until we get the nfsmapid deadlocks all fixed, don't allow
289 * XXX a v4 root mount.
290 */
291 int nfs4_no_diskless_root_support = 1;
292
293 int
mount_root(char * name,char * path,int version,struct nfs_args * args,int * vfsflags)294 mount_root(char *name, char *path, int version, struct nfs_args *args,
295 int *vfsflags)
296 {
297 int rc;
298 int proto;
299 struct knetconfig *dl_cf;
300 static int init_done = 0;
301 enum clnt_stat stat;
302
303 if (dldebug)
304 printf("mount_root: name=%s\n", name);
305
306 if (init_done == 0) {
307 init_config();
308 init_done = 1;
309 }
310
311 init_netbuf(args->addr);
312
313 do {
314 rc = getfile(name, args->hostname, args->addr, path);
315 } while (rc == ETIMEDOUT);
316
317 if (rc) {
318 free_netbuf(args->addr);
319 return (rc);
320 }
321
322 ASSERT(args->knconf->knc_protofmly != NULL);
323 ASSERT(args->knconf->knc_proto != NULL);
324
325 switch (version) {
326 case NFS_VERSION:
327 rc = mountnfs(args->addr, args->hostname, path,
328 (fhandle_t *)args->fh, &proto);
329 break;
330 case NFS_V3:
331 rc = mountnfs3(args->addr, args->hostname, path,
332 (nfs_fh3 *)args->fh, &proto);
333 break;
334 case NFS_V4:
335 ((struct sockaddr_in *)args->addr->buf)->sin_port =
336 htons(NFS_PORT);
337 if (ping_prog(args->addr, NFS_PROGRAM, NFS_V4, IPPROTO_TCP,
338 &stat)) {
339 proto = IPPROTO_TCP;
340 rc = 0;
341 } else {
342 switch (stat) {
343 case RPC_PROGVERSMISMATCH:
344 case RPC_XPRTFAILED:
345 /*
346 * Common failures if v4 unsupported or no TCP
347 */
348 rc = EPROTONOSUPPORT;
349 break;
350 default:
351 rc = ENXIO;
352 }
353 }
354 if (nfs4_no_diskless_root_support)
355 rc = EPROTONOSUPPORT;
356 break;
357 default:
358 rc = EPROTONOSUPPORT;
359 break;
360 }
361
362 if (rc)
363 goto errout;
364
365 switch (proto) {
366 case IPPROTO_TCP:
367 dl_cf = &dl_tcp_netconf;
368 break;
369 case IPPROTO_UDP:
370 default:
371 dl_cf = &dl_udp_netconf;
372 break;
373 }
374
375 rc = init_mountopts(args, version, &dl_cf, vfsflags);
376
377 /*
378 * Copy knetconfig information from the template, note that the
379 * rdev field has been set by init_config above.
380 */
381 args->knconf->knc_semantics = dl_cf->knc_semantics;
382 args->knconf->knc_rdev = dl_cf->knc_rdev;
383 (void) strcpy(args->knconf->knc_protofmly, dl_cf->knc_protofmly);
384 (void) strcpy(args->knconf->knc_proto, dl_cf->knc_proto);
385
386 errout:
387 if (dldebug) {
388 if (rc)
389 nfs_perror(rc, "mount_root: mount %s:%s failed: %m\n",
390 args->hostname, path);
391 else
392 printf("mount_root: leaving\n");
393 }
394
395 return (rc);
396 }
397
398 /*
399 * Call mount daemon on server `sa' to mount path.
400 * `port' is set to nfs port and fh is the fhandle
401 * returned from the server.
402 */
403 static int
mountnfs(struct netbuf * sa,char * server,char * path,fhandle_t * fh,int * proto)404 mountnfs(struct netbuf *sa, char *server,
405 char *path, fhandle_t *fh, int *proto)
406 {
407 struct fhstatus fhs;
408 enum clnt_stat stat;
409
410 if (dldebug)
411 printf("mountnfs: entered\n");
412
413 /*
414 * Get the port number for the mount program.
415 * pmap_kgetport first tries a SunOS portmapper
416 * and, if no reply is received, will try a
417 * SVR4 rpcbind. Either way, `sa' is set to
418 * the correct address.
419 */
420 do {
421 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
422 (rpcvers_t)MOUNTVERS, (rpcprot_t)IPPROTO_UDP);
423
424 if (stat == RPC_TIMEDOUT) {
425 cmn_err(CE_WARN,
426 "mountnfs: %s:%s portmap not responding",
427 server, path);
428 } else if (stat != RPC_SUCCESS) {
429 cmn_err(CE_WARN,
430 "mountnfs: pmap_kgetport RPC error %d (%s).",
431 stat, clnt_sperrno(stat));
432 return (ENXIO); /* XXX */
433 }
434 } while (stat == RPC_TIMEDOUT);
435
436 /*
437 * The correct port number has been
438 * put into `sa' by pmap_kgetport().
439 */
440 do {
441 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
442 (rpcvers_t)MOUNTVERS, (rpcproc_t)MOUNTPROC_MNT,
443 xdr_bp_path_t, (char *)&path,
444 myxdr_fhstatus, (char *)&fhs,
445 DEFAULT_TIMEO, DEFAULT_RETRIES);
446 if (stat == RPC_TIMEDOUT) {
447 cmn_err(CE_WARN,
448 "mountnfs: %s:%s mount server not responding",
449 server, path);
450 }
451 } while (stat == RPC_TIMEDOUT);
452
453 if (stat != RPC_SUCCESS) {
454 cmn_err(CE_WARN, "mountnfs: RPC failed: error %d (%s).",
455 stat, clnt_sperrno(stat));
456 return (ENXIO); /* XXX */
457 }
458
459 ((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT);
460
461 *fh = fhs.fhs_fh;
462 if (fhs.fhs_status != 0) {
463 if (dldebug)
464 printf("mountnfs: fhs_status %d\n", fhs.fhs_status);
465 return (ENXIO); /* XXX */
466 }
467
468 *proto = IPPROTO_UDP;
469
470 if (ping_prog(sa, NFS_PROGRAM, NFS_VERSION, IPPROTO_TCP, NULL))
471 *proto = IPPROTO_TCP;
472
473 if (dldebug)
474 printf("mountnfs: leaving\n");
475 return (0);
476 }
477
478 /*
479 * Call mount daemon on server `sa' to mount path.
480 * `port' is set to nfs port and fh is the fhandle
481 * returned from the server.
482 */
483 static int
mountnfs3(struct netbuf * sa,char * server,char * path,nfs_fh3 * fh,int * proto)484 mountnfs3(struct netbuf *sa, char *server,
485 char *path, nfs_fh3 *fh, int *proto)
486 {
487 struct mountres3 mountres3;
488 enum clnt_stat stat;
489 int ret = 0;
490
491 if (dldebug)
492 printf("mountnfs3: entered\n");
493
494 /*
495 * Get the port number for the mount program.
496 * pmap_kgetport first tries a SunOS portmapper
497 * and, if no reply is received, will try a
498 * SVR4 rpcbind. Either way, `sa' is set to
499 * the correct address.
500 */
501 do {
502 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
503 (rpcvers_t)MOUNTVERS3, (rpcprot_t)IPPROTO_UDP);
504
505 if (stat == RPC_PROGVERSMISMATCH) {
506 if (dldebug)
507 printf("mountnfs3: program/version mismatch\n");
508 return (EPROTONOSUPPORT); /* XXX */
509 } else if (stat == RPC_TIMEDOUT) {
510 cmn_err(CE_WARN,
511 "mountnfs3: %s:%s portmap not responding",
512 server, path);
513 } else if (stat != RPC_SUCCESS) {
514 cmn_err(CE_WARN,
515 "mountnfs3: pmap_kgetport RPC error %d (%s).",
516 stat, clnt_sperrno(stat));
517 return (ENXIO); /* XXX */
518 }
519 } while (stat == RPC_TIMEDOUT);
520
521 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = NULL;
522 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = NULL;
523
524 /*
525 * The correct port number has been
526 * put into `sa' by pmap_kgetport().
527 */
528 do {
529 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
530 (rpcvers_t)MOUNTVERS3, (rpcproc_t)MOUNTPROC_MNT,
531 xdr_bp_path_t, (char *)&path,
532 myxdr_mountres3, (char *)&mountres3,
533 DEFAULT_TIMEO, DEFAULT_RETRIES);
534 if (stat == RPC_TIMEDOUT) {
535 cmn_err(CE_WARN,
536 "mountnfs3: %s:%s mount server not responding",
537 server, path);
538 }
539 } while (stat == RPC_TIMEDOUT);
540
541 if (stat == RPC_PROGVERSMISMATCH) {
542 if (dldebug)
543 printf("mountnfs3: program/version mismatch\n");
544 ret = EPROTONOSUPPORT;
545 goto out;
546 }
547 if (stat != RPC_SUCCESS) {
548 cmn_err(CE_WARN, "mountnfs3: RPC failed: error %d (%s).",
549 stat, clnt_sperrno(stat));
550 ret = ENXIO; /* XXX */
551 goto out;
552 }
553
554 if (mountres3.fhs_status != MNT_OK) {
555 if (dldebug)
556 printf("mountnfs3: fhs_status %d\n",
557 mountres3.fhs_status);
558 ret = ENXIO; /* XXX */
559 goto out;
560 }
561
562 ((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT);
563
564 *proto = IPPROTO_UDP;
565
566 if (ping_prog(sa, NFS_PROGRAM, NFS_V3, IPPROTO_TCP, NULL)) {
567 *proto = IPPROTO_TCP;
568 }
569
570 fh->fh3_length = mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
571 bcopy(mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
572 fh->fh3_u.data, fh->fh3_length);
573
574 out:
575 xdr_free(myxdr_mountres3, (caddr_t)&mountres3);
576
577 if (dldebug)
578 printf("mountnfs3: leaving\n");
579 return (ret);
580 }
581
582 static int
ping_prog(struct netbuf * call_addr,uint_t prog,uint_t vers,int proto,enum clnt_stat * statp)583 ping_prog(struct netbuf *call_addr, uint_t prog, uint_t vers, int proto,
584 enum clnt_stat *statp)
585 {
586 struct knetconfig *knconf;
587 enum clnt_stat stat;
588 int retries = DEFAULT_RETRIES;
589
590 switch (proto) {
591 case IPPROTO_TCP:
592 knconf = &dl_tcp_netconf;
593 break;
594 case IPPROTO_UDP:
595 knconf = &dl_udp_netconf;
596 break;
597 default:
598 return (0);
599 }
600
601 do {
602 stat = mycallrpc(knconf, call_addr, prog, vers, NULLPROC,
603 xdr_void, NULL, xdr_void, NULL,
604 DEFAULT_TIMEO, DEFAULT_RETRIES);
605
606 if (dldebug)
607 printf("ping_prog: %d return %d (%s)\n", proto, stat,
608 clnt_sperrno(stat));
609 /*
610 * Special case for TCP, it may "timeout" because it failed
611 * to establish an initial connection but it doesn't
612 * actually retry, so we do the retry.
613 * Persistence pays in diskless.
614 */
615 } while (stat == RPC_TIMEDOUT && proto == IPPROTO_TCP && retries--);
616
617 if (statp != NULL)
618 *statp = stat;
619
620 if (stat != RPC_SUCCESS)
621 return (0);
622 return (1);
623 }
624
625 static struct netbuf bootparam_addr;
626
627 /*
628 * Returns after filling in the following global variables:
629 * bootparam_addr,
630 * utsname.nodename,
631 * srpc_domain.
632 */
633 static int
whoami(void)634 whoami(void)
635 {
636 TIUSER *tiptr;
637 struct netbuf sa;
638 struct netbuf req;
639 struct bp_whoami_arg arg;
640 struct bp_whoami_res res;
641 struct timeval tv;
642 enum clnt_stat stat;
643 int rc;
644 size_t namelen;
645 int printed_waiting_msg;
646
647 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
648 FREAD|FWRITE, &tiptr, CRED())) != 0) {
649 nfs_perror(rc, "whoami: t_kopen udp failed: %m.\n");
650 }
651
652 /*
653 * Find out our local (IP) address.
654 */
655 if (rc = revarp_myaddr(tiptr)) {
656 nfs_perror(rc, "whoami: revarp_myaddr failed: %m.\n");
657 (void) t_kclose(tiptr, 0);
658 return (rc);
659 }
660
661 /* explicitly use the limited broadcast address */
662 init_netbuf(&sa);
663 ((struct sockaddr_in *)sa.buf)->sin_family = AF_INET;
664 ((struct sockaddr_in *)sa.buf)->sin_addr.s_addr =
665 htonl(INADDR_BROADCAST);
666 sa.len = sizeof (struct sockaddr_in);
667
668 /*
669 * Pick up our local (IP) address.
670 */
671 init_netbuf(&req);
672 if (rc = ifioctl(tiptr, SIOCGIFADDR, &req)) {
673 nfs_perror(rc,
674 "whoami: couldn't get my IP address: %m.\n");
675 free_netbuf(&sa);
676 free_netbuf(&req);
677 (void) t_kclose(tiptr, 0);
678 return (rc);
679 }
680
681 /*
682 * Set up the arguments expected by bootparamd.
683 */
684 arg.client_address.address_type = IP_ADDR_TYPE;
685 bcopy(&((struct sockaddr_in *)req.buf)->sin_addr,
686 &arg.client_address.bp_address.ip_addr, sizeof (struct in_addr));
687
688 free_netbuf(&req);
689
690 init_netbuf(&bootparam_addr);
691
692 /*
693 * Initial retransmission interval
694 */
695 tv.tv_sec = DEFAULT_TIMEO;
696 tv.tv_usec = 0;
697 res.client_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
698 res.domain_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
699
700 /*
701 * Do a broadcast call to find a bootparam daemon that
702 * will tell us our hostname, domainname and any
703 * router that we have to use to talk to our NFS server.
704 */
705 printed_waiting_msg = 0;
706 do {
707 /*
708 * pmap_rmt_call will first try the SunOS portmapper
709 * and if no reply is received will then try the SVR4
710 * rpcbind.
711 * Either way, `bootparam_addr' will be set to the
712 * correct address for the bootparamd that responds.
713 */
714 stat = pmap_rmt_call(&dl_udp_netconf, &sa, TRUE, BOOTPARAMPROG,
715 BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI,
716 xdr_bp_whoami_arg, (caddr_t)&arg,
717 xdr_bp_whoami_res, (caddr_t)&res,
718 tv, &bootparam_addr);
719 if (stat == RPC_TIMEDOUT && !printed_waiting_msg) {
720 cmn_err(CE_WARN,
721 "No bootparam server responding; still trying");
722 printed_waiting_msg = 1;
723 }
724 /*
725 * Retransmission interval for second and subsequent tries.
726 * We expect first pmap_rmt_call to retransmit and backoff to
727 * at least this value.
728 */
729 tv.tv_sec = WHOAMI_TIMEO;
730 tv.tv_usec = 0;
731 } while (stat == RPC_TIMEDOUT);
732
733 if (printed_waiting_msg)
734 printf("Bootparam response received\n");
735
736 if (stat != RPC_SUCCESS) {
737 /* XXX should get real error here */
738 rc = ENXIO;
739 cmn_err(CE_WARN,
740 "whoami: bootparam RPC failed: error %d (%s).",
741 stat, clnt_sperrno(stat));
742 goto done;
743 }
744
745 namelen = strlen(res.client_name);
746 if (namelen > sizeof (utsname.nodename)) {
747 printf("whoami: hostname too long");
748 rc = ENAMETOOLONG;
749 goto done;
750 }
751 if (namelen != 0) {
752 bcopy(res.client_name, &utsname.nodename, namelen);
753 cmn_err(CE_CONT, "?hostname: %s\n", utsname.nodename);
754 } else {
755 printf("whoami: no host name\n");
756 rc = ENXIO;
757 goto done;
758 }
759
760 namelen = strlen(res.domain_name);
761 if (namelen != 0) {
762 if (namelen > SYS_NMLN) {
763 printf("whoami: domainname too long");
764 rc = ENAMETOOLONG;
765 goto done;
766 }
767 bcopy(res.domain_name, &srpc_domain, namelen);
768 cmn_err(CE_CONT, "?domainname: %s\n", srpc_domain);
769 } else {
770 printf("whoami: no domain name\n");
771 }
772
773 if (res.router_address.address_type == IP_ADDR_TYPE) {
774 struct rtentry rtentry;
775 struct sockaddr_in *sin;
776 struct in_addr ipaddr;
777
778 bcopy(&res.router_address.bp_address.ip_addr, &ipaddr,
779 sizeof (struct in_addr));
780
781 if (ipaddr.s_addr != (uint32_t)0) {
782 sin = (struct sockaddr_in *)&rtentry.rt_dst;
783 bzero(sin, sizeof (*sin));
784 sin->sin_family = AF_INET;
785
786 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
787 bzero(sin, sizeof (*sin));
788 sin->sin_family = AF_INET;
789 sin->sin_addr.s_addr = ipaddr.s_addr;
790
791 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
792
793 if (rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) {
794 nfs_perror(rc,
795 "whoami: couldn't add route: %m.\n");
796 goto done;
797 }
798 }
799 } else {
800 printf("whoami: unknown gateway addr family %d\n",
801 res.router_address.address_type);
802 }
803 done:
804 kmem_free(res.client_name, MAX_MACHINE_NAME + 1);
805 kmem_free(res.domain_name, MAX_MACHINE_NAME + 1);
806 free_netbuf(&sa);
807 (void) t_kclose(tiptr, 0);
808 return (rc);
809 }
810
811 /*
812 * Returns:
813 * 1) The ascii form of our root servers name in `server_name'.
814 * 2) Actual network address of our root server in `server_address'.
815 * 3) Whatever BOOTPARAMPROC_GETFILE returns for the fileid key, in
816 * `server_path'. If fileid is "root", it is the pathname of our
817 * root on the server.
818 */
819 static int
getfile(char * fileid,char * server_name,struct netbuf * server_address,char * server_path)820 getfile(char *fileid,
821 char *server_name, struct netbuf *server_address, char *server_path)
822 {
823 struct bp_getfile_arg arg;
824 struct bp_getfile_res res;
825 enum clnt_stat stat;
826 int root = FALSE;
827 static int using_cache = FALSE;
828 struct in_addr ipaddr;
829 int timeo = DEFAULT_TIMEO;
830 int retries = DEFAULT_RETRIES;
831
832 if (dldebug)
833 printf("getfile: entered\n");
834
835 /*
836 * Call cacheinfo() to see whether we can satisfy this request by using
837 * the information cached in memory by the boot program's DHCP
838 * implementation or boot properties rather than consult BOOTPARAMS,
839 * but while preserving the semantics of getfile(). We know that
840 * the server name is SYS_NMLN in length, and server_path is
841 * MAXPATHLEN (pn_alloc).
842 */
843 if (strcmp(fileid, "root") == 0) {
844 if (cacheinfo(server_name, SYS_NMLN, server_address,
845 server_path, MAXPATHLEN) == 0) {
846 using_cache = TRUE;
847 return (0);
848 }
849 root = TRUE;
850 }
851
852 /*
853 * If using cache, rootopts is already available.
854 */
855 if (strcmp(fileid, "rootopts") == 0 && using_cache == TRUE) {
856 return (rootopts[0] != 0 ? 0 : ENXIO);
857 }
858
859 if (bootparam_addr.len == 0) {
860 return (ENXIO);
861 }
862 arg.client_name = (caddr_t)&utsname.nodename;
863 arg.file_id = fileid;
864
865 bzero(&res, sizeof (res));
866 res.server_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
867 res.server_path = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
868
869 /*
870 * If we are not looking up the root file, we are looking
871 * up a non-critical option that should timeout quickly.
872 */
873 if (!root) {
874 timeo = GETFILE_TIMEO;
875 retries = GETFILE_RETRIES;
876 }
877
878 /*
879 * bootparam_addr was filled in by the call to
880 * whoami(), so now send an rpc message to the
881 * bootparam daemon requesting our server information.
882 * Use UDP to talk to bootparms.
883 */
884 stat = mycallrpc(&dl_udp_netconf, &bootparam_addr,
885 (rpcprog_t)BOOTPARAMPROG, (rpcvers_t)BOOTPARAMVERS,
886 (rpcproc_t)BOOTPARAMPROC_GETFILE,
887 xdr_bp_getfile_arg, (caddr_t)&arg,
888 xdr_bp_getfile_res, (caddr_t)&res,
889 timeo, retries);
890
891 if (stat == RPC_SUCCESS) {
892 (void) strcpy(server_name, res.server_name);
893 (void) strcpy(server_path, res.server_path);
894 }
895
896 kmem_free(res.server_name, MAX_MACHINE_NAME + 1);
897 kmem_free(res.server_path, MAX_MACHINE_NAME + 1);
898
899 if (stat != RPC_SUCCESS) {
900 if (root)
901 cmn_err(CE_WARN, "getfile: RPC failed: error %d (%s).",
902 stat, clnt_sperrno(stat));
903 return ((stat == RPC_TIMEDOUT) ? ETIMEDOUT : ENXIO); /* XXX */
904 }
905
906 if (*server_path == '\0')
907 return (EINVAL);
908
909 /*
910 * If the fileid is "root", we must get back a server name, for
911 * other parameters a server name is not required
912 */
913 if (!root) {
914 if (dldebug)
915 printf("getfile: leaving: non-root\n");
916 return (0);
917 }
918
919 if (*server_name == '\0')
920 return (EINVAL);
921
922 switch (res.server_address.address_type) {
923 case IP_ADDR_TYPE:
924 /*
925 * server_address is where we will get our root
926 * from.
927 */
928 ((struct sockaddr_in *)server_address->buf)->sin_family =
929 AF_INET;
930 bcopy(&res.server_address.bp_address.ip_addr,
931 &ipaddr, sizeof (ipaddr));
932 if (ipaddr.s_addr == 0)
933 return (EINVAL);
934
935 ((struct sockaddr_in *)server_address->buf)->sin_addr.s_addr =
936 ipaddr.s_addr;
937 server_address->len = sizeof (struct sockaddr_in);
938 break;
939
940 default:
941 printf("getfile: unknown address type %d\n",
942 res.server_address.address_type);
943 return (EPROTONOSUPPORT);
944 }
945 if (dldebug)
946 printf("getfile: leaving\n");
947 return (0);
948 }
949
950 /*
951 * If the boot property "bootp-response" exists, then OBP performed a
952 * successful DHCP lease acquisition for us and left the resultant ACK packet
953 * encoded at that location.
954 *
955 * If no such property exists (or the information is incomplete or garbled),
956 * the function returns -1.
957 */
958 int
dhcpinit(void)959 dhcpinit(void)
960 {
961 int rc, i;
962 char *p;
963 struct in_addr braddr;
964 struct in_addr subnet;
965 DHCP_OPT *doptp;
966 TIUSER *tiptr;
967 struct sockaddr_in *sin;
968 static int once_only = 0;
969
970 if (once_only == 1) {
971 return (0);
972 }
973 once_only = 1;
974
975 if (dhcack == NULL) {
976 return (-1);
977 }
978
979 if (dldebug) {
980 printf("dhcp: dhcack %p, len %d\n", (void *)dhcack,
981 dhcacklen);
982 }
983
984 pl = kmem_alloc(sizeof (PKT_LIST), KM_SLEEP);
985 pl->len = dhcacklen;
986 pl->pkt = kmem_alloc(pl->len, KM_SLEEP);
987 bcopy(dhcack, pl->pkt, dhcacklen);
988
989 /*
990 * For x86, ifname is not initialized
991 * in the netinstall case and dhcack interface name is
992 * set in strplumb(). So we only copy the name if ifname
993 * is set properly.
994 */
995 if (ifname[0])
996 (void) strlcpy(dhcifname, ifname, sizeof (dhcifname));
997
998 /* remember the server_ip in dhcack */
999 bcopy((uchar_t *)pl->pkt + 20, dhcp_server_ip, 4);
1000 bzero(pl->opts, (DHCP_LAST_OPT + 1) * sizeof (DHCP_OPT *));
1001 bzero(pl->vs, (VS_OPTION_END - VS_OPTION_START + 1) *
1002 sizeof (DHCP_OPT *));
1003
1004 if (dhcp_options_scan(pl, B_TRUE) != 0) {
1005 /* garbled packet */
1006 cmn_err(CE_WARN, "dhcp: DHCP packet parsing failed");
1007 kmem_free(pl->pkt, pl->len);
1008 kmem_free(pl, sizeof (PKT_LIST));
1009 pl = NULL;
1010 return (-1);
1011 }
1012
1013 /* set node name */
1014 if (pl->opts[CD_HOSTNAME] != NULL) {
1015 doptp = pl->opts[CD_HOSTNAME];
1016 i = doptp->len;
1017 if (i >= SYS_NMLN) {
1018 cmn_err(CE_WARN, "dhcp: Hostname is too long");
1019 } else {
1020 bcopy(doptp->value, utsname.nodename, i);
1021 utsname.nodename[i] = '\0';
1022 if (dldebug) {
1023 printf("hostname is %s\n",
1024 utsname.nodename);
1025 }
1026 }
1027 }
1028
1029 /* Set NIS domain name. */
1030 p = NULL;
1031 if (pl->opts[CD_NIS_DOMAIN] != NULL) {
1032 doptp = pl->opts[CD_NIS_DOMAIN];
1033 i = doptp->len;
1034 p = (caddr_t)doptp->value;
1035 }
1036 if (p != NULL) {
1037 if (i > SYS_NMLN) {
1038 cmn_err(CE_WARN,
1039 "dhcp: NIS domainname too long.");
1040 } else {
1041 bcopy(p, srpc_domain, i);
1042 srpc_domain[i] = '\0';
1043 if (dldebug)
1044 printf("dhcp: NIS domain name is %s\n",
1045 srpc_domain);
1046 }
1047 }
1048
1049 /* fetch netmask */
1050 if (pl->opts[CD_SUBNETMASK] != NULL) {
1051 doptp = pl->opts[CD_SUBNETMASK];
1052 if (doptp->len != sizeof (struct in_addr)) {
1053 pl->opts[CD_SUBNETMASK] = NULL;
1054 cmn_err(CE_WARN, "dhcp: netmask option malformed");
1055 } else {
1056 bcopy(doptp->value, &subnet, sizeof (struct in_addr));
1057 if (dldebug)
1058 printf("dhcp: setting netmask to: %s\n",
1059 inet_ntoa(subnet));
1060 }
1061 } else {
1062 struct in_addr myIPaddr;
1063
1064 myIPaddr.s_addr = pl->pkt->yiaddr.s_addr;
1065 cmn_err(CE_WARN, "dhcp: no subnet mask supplied - inferring");
1066 if (IN_CLASSA(ntohl(myIPaddr.s_addr)))
1067 subnet.s_addr = htonl(IN_CLASSA_NET);
1068 else if (IN_CLASSB(ntohl(myIPaddr.s_addr)))
1069 subnet.s_addr = htonl(IN_CLASSB_NET);
1070 else if (IN_CLASSC(ntohl(myIPaddr.s_addr)))
1071 subnet.s_addr = htonl(IN_CLASSC_NET);
1072 else if (IN_CLASSD(ntohl(myIPaddr.s_addr)))
1073 cmn_err(CE_WARN, "dhcp: bad IP address (%s)",
1074 inet_ntoa(myIPaddr));
1075 else
1076 subnet.s_addr = htonl(IN_CLASSE_NET);
1077 }
1078 /* and broadcast address */
1079 if (pl->opts[CD_BROADCASTADDR] != NULL) {
1080 doptp = pl->opts[CD_BROADCASTADDR];
1081 if (doptp->len != sizeof (struct in_addr)) {
1082 pl->opts[CD_BROADCASTADDR] = NULL;
1083 if (dldebug)
1084 printf("dhcp: broadcast address len %d\n",
1085 doptp->len);
1086 } else {
1087 bcopy(doptp->value, &braddr, sizeof (struct in_addr));
1088 if (dldebug)
1089 printf("dhcp: setting broadcast addr to: %s\n",
1090 inet_ntoa(braddr));
1091 }
1092 } else {
1093 if (dldebug)
1094 printf("dhcp: no broadcast address supplied\n");
1095 braddr.s_addr = htonl(INADDR_BROADCAST);
1096 }
1097 /* and plumb and initialize interface */
1098 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
1099 FREAD|FWRITE, &tiptr, CRED())) == 0) {
1100 if (rc = dlifconfig(tiptr, &pl->pkt->yiaddr, &subnet,
1101 &braddr, IFF_DHCPRUNNING)) {
1102 nfs_perror(rc, "dhcp: dlifconfig failed: %m\n");
1103 kmem_free(pl->pkt, pl->len);
1104 kmem_free(pl, sizeof (PKT_LIST));
1105 pl = NULL;
1106 (void) t_kclose(tiptr, 0);
1107 return (-1);
1108 }
1109
1110 /* add routes */
1111 if (pl->opts[CD_ROUTER] != NULL) {
1112 doptp = pl->opts[CD_ROUTER];
1113 if ((doptp->len % sizeof (struct in_addr)) != 0) {
1114 pl->opts[CD_ROUTER] = NULL;
1115 } else {
1116 int nrouters;
1117 uchar_t *tp;
1118
1119 nrouters = doptp->len / sizeof (struct in_addr);
1120 for (tp = doptp->value, i = 0; i < nrouters;
1121 i++) {
1122 struct in_addr defr;
1123 struct rtentry rtentry;
1124
1125 bcopy(tp, &defr,
1126 sizeof (struct in_addr));
1127 if (defr.s_addr == 0)
1128 continue;
1129
1130 sin = (struct
1131 sockaddr_in *)&rtentry.rt_dst;
1132
1133 bzero(sin, sizeof (*sin));
1134 sin->sin_family = AF_INET;
1135
1136 sin = (struct
1137 sockaddr_in *)&rtentry.rt_gateway;
1138 bzero(sin, sizeof (*sin));
1139 sin->sin_family = AF_INET;
1140 sin->sin_addr = defr;
1141
1142 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
1143
1144 if (rc = rtioctl(tiptr, SIOCADDRT,
1145 &rtentry)) {
1146 nfs_perror(rc,
1147 "dhcp: couldn't add route "
1148 "to %s: %m.\n",
1149 inet_ntoa(defr));
1150 continue;
1151 }
1152 if (dldebug) {
1153 printf("dhcp: added route %s\n",
1154 inet_ntoa(defr));
1155 }
1156 tp += sizeof (struct in_addr);
1157 }
1158 }
1159 }
1160
1161 (void) t_kclose(tiptr, 0);
1162 }
1163
1164 if (dldebug)
1165 printf("dhcpinit: leaving\n");
1166
1167 return (0);
1168 }
1169
1170 /*
1171 * Initialize nfs mount info from properties and dhcp response.
1172 */
1173 static void
cacheinit(void)1174 cacheinit(void)
1175 {
1176 char *str;
1177 DHCP_OPT *doptp;
1178
1179 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1180 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c);
1181 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1182 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c);
1183 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1184 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) {
1185 (void) strncpy(rootopts, str, 255);
1186 ddi_prop_free(str);
1187 }
1188 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1189 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) {
1190 if (inet_aton(str, server_ip) != 0)
1191 cmn_err(CE_NOTE, "server_ipaddr %s is invalid",
1192 str);
1193 ddi_prop_free(str);
1194 if (dldebug)
1195 printf("server ip is %s\n",
1196 inet_ntoa(*(struct in_addr *)server_ip));
1197 }
1198
1199 if (pl == NULL)
1200 return;
1201
1202 /* extract root path in server_path */
1203 if (server_path_c == NULL) {
1204 doptp = pl->vs[VS_NFSMNT_ROOTPATH];
1205 if (doptp == NULL)
1206 doptp = pl->opts[CD_ROOT_PATH];
1207 if (doptp != NULL) {
1208 int len, size;
1209 uint8_t c, *source;
1210
1211 str = NULL;
1212 source = doptp->value;
1213 size = doptp->len;
1214 c = ':';
1215
1216 /*
1217 * We have to consider three cases for root path:
1218 * "nfs://server_ip/path"
1219 * "server_ip:/path"
1220 * "/path"
1221 */
1222 if (bcmp(source, "nfs://", 6) == 0) {
1223 source += 6;
1224 size -= 6;
1225 c = '/';
1226 }
1227 /*
1228 * Search for next char after ':' or first '/'.
1229 * Note, the '/' is part of the path, but we do
1230 * not need to preserve the ':'.
1231 */
1232 for (len = 0; len < size; len++) {
1233 if (source[len] == c) {
1234 if (c == ':') {
1235 str = (char *)(&source[++len]);
1236 } else {
1237 str = (char *)(&source[len++]);
1238 size++;
1239 }
1240 break;
1241 }
1242 }
1243 if (str != NULL) {
1244 /* Do not override server_ip from property. */
1245 if ((*(uint_t *)server_ip) == 0) {
1246 char *ip = kmem_alloc(len, KM_SLEEP);
1247 bcopy(source, ip, len);
1248 ip[len - 1] = '\0';
1249 if (inet_aton((ip), server_ip) != 0) {
1250 cmn_err(CE_NOTE,
1251 "server_ipaddr %s is "
1252 "invalid", ip);
1253 }
1254 kmem_free(ip, len);
1255 if (dldebug) {
1256 printf("server ip is %s\n",
1257 inet_ntoa(
1258 *(struct in_addr *)
1259 server_ip));
1260 }
1261 }
1262 len = size - len;
1263 } else {
1264 str = (char *)doptp->value;
1265 len = doptp->len;
1266 }
1267 server_path_c = kmem_alloc(len + 1, KM_SLEEP);
1268 bcopy(str, server_path_c, len);
1269 server_path_c[len] = '\0';
1270 if (dldebug)
1271 printf("dhcp: root path %s\n", server_path_c);
1272 } else {
1273 cmn_err(CE_WARN, "dhcp: root server path missing");
1274 }
1275 }
1276
1277 /* set server_name */
1278 if (server_name_c == NULL) {
1279 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_NAME];
1280 if (doptp != NULL) {
1281 server_name_c = kmem_alloc(doptp->len + 1, KM_SLEEP);
1282 bcopy(doptp->value, server_name_c, doptp->len);
1283 server_name_c[doptp->len] = '\0';
1284 if (dldebug)
1285 printf("dhcp: root server name %s\n",
1286 server_name_c);
1287 } else {
1288 cmn_err(CE_WARN, "dhcp: root server name missing");
1289 }
1290 }
1291
1292 /* set root server_address */
1293 if ((*(uint_t *)server_ip) == 0) {
1294 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_IP];
1295 if (doptp) {
1296 bcopy(doptp->value, server_ip, sizeof (server_ip));
1297 if (dldebug) {
1298 printf("dhcp: root server IP address %s\n",
1299 inet_ntoa(*(struct in_addr *)server_ip));
1300 }
1301 } else {
1302 if (dldebug)
1303 cmn_err(CE_CONT,
1304 "dhcp: file server ip address missing,"
1305 " fallback to dhcp server as file server");
1306 bcopy(dhcp_server_ip, server_ip, sizeof (server_ip));
1307 }
1308 }
1309
1310 /* set root file system mount options */
1311 if (rootopts[0] == 0) {
1312 doptp = pl->vs[VS_NFSMNT_ROOTOPTS];
1313 if (doptp != NULL && doptp->len < 255) {
1314 bcopy(doptp->value, rootopts, doptp->len);
1315 rootopts[doptp->len] = '\0';
1316 if (dldebug)
1317 printf("dhcp: rootopts %s\n", rootopts);
1318 } else if (dldebug) {
1319 printf("dhcp: no rootopts or too long\n");
1320 /* not an error */
1321 }
1322 }
1323
1324 /* now we are done with pl, just free it */
1325 kmem_free(pl->pkt, pl->len);
1326 kmem_free(pl, sizeof (PKT_LIST));
1327 pl = NULL;
1328 }
1329
1330 static int
cacheinfo(char * name,int namelen,struct netbuf * server_address,char * rootpath,int pathlen)1331 cacheinfo(char *name, int namelen,
1332 struct netbuf *server_address, char *rootpath, int pathlen)
1333 {
1334 static int init_done = 0;
1335 struct sockaddr_in *sin;
1336
1337 if (init_done == 0) {
1338 cacheinit();
1339 init_done = 1;
1340 }
1341
1342 /* server_path is a reliable indicator of cache availability */
1343 if (server_path_c == NULL)
1344 return (-1);
1345
1346 (void) strncpy(rootpath, server_path_c, pathlen);
1347 if (server_name_c) {
1348 (void) strncpy(name, server_name_c, namelen);
1349 } else {
1350 (void) strncpy(name, "unknown", namelen);
1351 }
1352
1353 sin = (struct sockaddr_in *)server_address->buf;
1354 sin->sin_family = AF_INET;
1355 server_address->len = sizeof (struct sockaddr_in);
1356 bcopy(server_ip, &sin->sin_addr, sizeof (struct in_addr));
1357 return (0);
1358 }
1359
1360 /*
1361 * Set this interface's IP address and netmask, and bring it up.
1362 */
1363 static int
dlifconfig(TIUSER * tiptr,struct in_addr * myIPaddr,struct in_addr * mymask,struct in_addr * mybraddr,uint_t flags)1364 dlifconfig(TIUSER *tiptr, struct in_addr *myIPaddr, struct in_addr *mymask,
1365 struct in_addr *mybraddr, uint_t flags)
1366 {
1367 int rc;
1368 struct netbuf sbuf;
1369 struct sockaddr_in sin;
1370
1371 if (dldebug) {
1372 printf("dlifconfig: entered\n");
1373 printf("dlifconfig: addr %s\n", inet_ntoa(*myIPaddr));
1374 printf("dlifconfig: mask %s\n", inet_ntoa(*mymask));
1375 printf("dlifconfig: broadcast %s\n", inet_ntoa(*mybraddr));
1376 }
1377
1378 bcopy(myIPaddr, &sin.sin_addr, sizeof (struct in_addr));
1379 sin.sin_family = AF_INET;
1380 sbuf.buf = (caddr_t)&sin;
1381 sbuf.maxlen = sbuf.len = sizeof (sin);
1382 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1383 nfs_perror(rc,
1384 "dlifconfig: couldn't set interface net address: %m\n");
1385 return (rc);
1386 }
1387
1388 if (mybraddr->s_addr != INADDR_BROADCAST) {
1389 bcopy(mybraddr, &sin.sin_addr, sizeof (struct in_addr));
1390 sin.sin_family = AF_INET;
1391 sbuf.buf = (caddr_t)&sin;
1392 sbuf.maxlen = sbuf.len = sizeof (sin);
1393 if (rc = ifioctl(tiptr, SIOCSIFBRDADDR, &sbuf)) {
1394 nfs_perror(rc,
1395 "dlifconfig: couldn't set interface broadcast addr: %m\n");
1396 return (rc);
1397 }
1398 }
1399
1400 bcopy(mymask, &sin.sin_addr, sizeof (struct in_addr));
1401 sin.sin_family = AF_INET;
1402 sbuf.buf = (caddr_t)&sin;
1403 sbuf.maxlen = sbuf.len = sizeof (sin);
1404 if (rc = ifioctl(tiptr, SIOCSIFNETMASK, &sbuf)) {
1405 nfs_perror(rc,
1406 "dlifconfig: couldn't set interface net address: %m\n");
1407 return (rc);
1408 }
1409
1410 /*
1411 * Now turn on the interface.
1412 */
1413 if (rc = setifflags(tiptr, IFF_UP | flags)) {
1414 nfs_perror(rc,
1415 "dlifconfig: couldn't enable network interface: %m\n");
1416 return (rc);
1417 }
1418
1419 if (dldebug)
1420 printf("dlifconfig: returned\n");
1421 return (0);
1422 }
1423
1424 static char *
inet_ntoa(struct in_addr in)1425 inet_ntoa(struct in_addr in)
1426 {
1427 static char b[18];
1428 unsigned char *p;
1429
1430 p = (unsigned char *)∈
1431 (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1432 return (b);
1433 }
1434
1435 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1436 static int
inet_aton(char * ipstr,uchar_t * ip)1437 inet_aton(char *ipstr, uchar_t *ip)
1438 {
1439 int i = 0;
1440 uchar_t val[4] = {0};
1441 char c = *ipstr;
1442
1443 for (;;) {
1444 if (!isdigit(c))
1445 return (-1);
1446 for (;;) {
1447 if (!isdigit(c))
1448 break;
1449 val[i] = val[i] * 10 + (c - '0');
1450 c = *++ipstr;
1451 }
1452 i++;
1453 if (i == 4)
1454 break;
1455 if (c != '.')
1456 return (-1);
1457 c = *++ipstr;
1458 }
1459 if (c != 0)
1460 return (-1);
1461 bcopy(val, ip, 4);
1462 return (0);
1463 }
1464
1465 #define MAX_ADDR_SIZE 128
1466
1467 /*
1468 * Initialize a netbuf suitable for
1469 * describing an address for the
1470 * transport defined by `tiptr'.
1471 */
1472 static void
init_netbuf(struct netbuf * nbuf)1473 init_netbuf(struct netbuf *nbuf)
1474 {
1475 nbuf->buf = kmem_zalloc(MAX_ADDR_SIZE, KM_SLEEP);
1476 nbuf->maxlen = MAX_ADDR_SIZE;
1477 nbuf->len = 0;
1478 }
1479
1480 static void
free_netbuf(struct netbuf * nbuf)1481 free_netbuf(struct netbuf *nbuf)
1482 {
1483 kmem_free(nbuf->buf, nbuf->maxlen);
1484 nbuf->buf = NULL;
1485 nbuf->maxlen = 0;
1486 nbuf->len = 0;
1487 }
1488
1489 static int
rtioctl(TIUSER * tiptr,int cmd,struct rtentry * rtentry)1490 rtioctl(TIUSER *tiptr, int cmd, struct rtentry *rtentry)
1491 {
1492 struct strioctl iocb;
1493 int rc;
1494 vnode_t *vp;
1495
1496 iocb.ic_cmd = cmd;
1497 iocb.ic_timout = 0;
1498 iocb.ic_len = sizeof (struct rtentry);
1499 iocb.ic_dp = (caddr_t)rtentry;
1500
1501 vp = tiptr->fp->f_vnode;
1502 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1503 if (rc)
1504 nfs_perror(rc, "rtioctl: kstr_ioctl failed: %m\n");
1505 return (rc);
1506 }
1507
1508 /*
1509 * Send an ioctl down the stream defined
1510 * by `tiptr'.
1511 *
1512 * We isolate the ifreq dependencies in here. The
1513 * ioctl really ought to take a netbuf and be of
1514 * type TRANSPARENT - one day.
1515 */
1516 static int
ifioctl(TIUSER * tiptr,int cmd,struct netbuf * nbuf)1517 ifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf)
1518 {
1519 struct strioctl iocb;
1520 int rc;
1521 vnode_t *vp;
1522 struct ifreq ifr;
1523
1524 /*
1525 * Now do the one requested.
1526 */
1527 if (nbuf->len)
1528 ifr.ifr_addr = *(struct sockaddr *)nbuf->buf;
1529 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1530 iocb.ic_cmd = cmd;
1531 iocb.ic_timout = 0;
1532 iocb.ic_len = sizeof (ifr);
1533 iocb.ic_dp = (caddr_t)𝔦
1534
1535 vp = tiptr->fp->f_vnode;
1536 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1537 if (rc) {
1538 nfs_perror(rc, "ifioctl: kstr_ioctl failed: %m\n");
1539 return (rc);
1540 }
1541
1542 /*
1543 * Set reply length.
1544 */
1545 if (nbuf->len == 0) {
1546 /*
1547 * GET type.
1548 */
1549 nbuf->len = sizeof (struct sockaddr);
1550 *(struct sockaddr *)nbuf->buf = ifr.ifr_addr;
1551 }
1552
1553 return (0);
1554 }
1555
1556 static int
setifflags(TIUSER * tiptr,uint_t value)1557 setifflags(TIUSER *tiptr, uint_t value)
1558 {
1559 struct ifreq ifr;
1560 int rc;
1561 struct strioctl iocb;
1562
1563 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1564 iocb.ic_cmd = SIOCGIFFLAGS;
1565 iocb.ic_timout = 0;
1566 iocb.ic_len = sizeof (ifr);
1567 iocb.ic_dp = (caddr_t)𝔦
1568 if (rc = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb))
1569 return (rc);
1570
1571 ifr.ifr_flags |= value;
1572 iocb.ic_cmd = SIOCSIFFLAGS;
1573 return (kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb));
1574 }
1575
1576 /*
1577 * REVerse Address Resolution Protocol (revarp)
1578 * is used by a diskless client to find out its
1579 * IP address when all it knows is its Ethernet address.
1580 *
1581 * Open the ethernet driver, attach and bind
1582 * (DL_BIND_REQ) it, and then format a broadcast RARP
1583 * message for it to send. We pick up the reply and
1584 * let the caller set the interface address using SIOCSIFADDR.
1585 */
1586 static int
revarp_myaddr(TIUSER * tiptr)1587 revarp_myaddr(TIUSER *tiptr)
1588 {
1589 int rc;
1590 dl_info_ack_t info;
1591 struct sockaddr_in sin;
1592 struct netbuf sbuf;
1593 ldi_handle_t lh;
1594 ldi_ident_t li;
1595 struct netbuf myaddr = {0, 0, NULL};
1596
1597 if (dldebug)
1598 printf("revarp_myaddr: entered\n");
1599
1600 if (rc = ldi_ident_from_mod(&modlinkage, &li)) {
1601 nfs_perror(rc,
1602 "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1603 return (rc);
1604 }
1605
1606 rc = ldi_open_by_name(ndev_path, FREAD|FWRITE, CRED(), &lh, li);
1607 ldi_ident_release(li);
1608 if (rc) {
1609 nfs_perror(rc,
1610 "revarp_myaddr: ldi_open_by_name failed: %m\n");
1611 return (rc);
1612 }
1613
1614 if (rc = dl_attach(lh, ifunit, NULL)) {
1615 nfs_perror(rc, "revarp_myaddr: dl_attach failed: %m\n");
1616 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1617 return (rc);
1618 }
1619
1620 if (rc = dl_bind(lh, ETHERTYPE_REVARP, NULL)) {
1621 nfs_perror(rc, "revarp_myaddr: dl_bind failed: %m\n");
1622 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1623 return (rc);
1624 }
1625
1626 if (rc = dl_info(lh, &info, NULL, NULL, NULL)) {
1627 nfs_perror(rc, "revarp_myaddr: dl_info failed: %m\n");
1628 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1629 return (rc);
1630 }
1631
1632 /* Initialize myaddr */
1633 myaddr.maxlen = info.dl_addr_length;
1634 myaddr.buf = kmem_alloc(myaddr.maxlen, KM_SLEEP);
1635
1636 revarp_start(lh, &myaddr);
1637
1638 bcopy(myaddr.buf, &sin.sin_addr, myaddr.len);
1639 sin.sin_family = AF_INET;
1640
1641 sbuf.buf = (caddr_t)&sin;
1642 sbuf.maxlen = sbuf.len = sizeof (sin);
1643 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1644 nfs_perror(rc,
1645 "revarp_myaddr: couldn't set interface net address: %m\n");
1646 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1647 kmem_free(myaddr.buf, myaddr.maxlen);
1648 return (rc);
1649 }
1650
1651 /* Now turn on the interface */
1652 if (rc = setifflags(tiptr, IFF_UP)) {
1653 nfs_perror(rc,
1654 "revarp_myaddr: couldn't enable network interface: %m\n");
1655 }
1656
1657 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1658 kmem_free(myaddr.buf, myaddr.maxlen);
1659 return (rc);
1660 }
1661
1662 static void
revarp_start(ldi_handle_t lh,struct netbuf * myaddr)1663 revarp_start(ldi_handle_t lh, struct netbuf *myaddr)
1664 {
1665 struct ether_arp *ea;
1666 int rc;
1667 dl_unitdata_req_t *dl_udata;
1668 mblk_t *bp;
1669 mblk_t *mp;
1670 struct dladdr *dlsap;
1671 static int done = 0;
1672 size_t addrlen = ETHERADDRL;
1673
1674 if (dl_phys_addr(lh, (uchar_t *)&myether, &addrlen, NULL) != 0 ||
1675 addrlen != ETHERADDRL) {
1676 /* Fallback using per-node address */
1677 (void) localetheraddr((struct ether_addr *)NULL, &myether);
1678 cmn_err(CE_CONT, "?DLPI failed to get Ethernet address. Using "
1679 "system wide Ethernet address %s\n",
1680 ether_sprintf(&myether));
1681 }
1682
1683 getreply:
1684 if (myaddr->len != 0) {
1685 cmn_err(CE_CONT, "?Found my IP address: %x (%d.%d.%d.%d)\n",
1686 *(int *)myaddr->buf,
1687 (uchar_t)myaddr->buf[0], (uchar_t)myaddr->buf[1],
1688 (uchar_t)myaddr->buf[2], (uchar_t)myaddr->buf[3]);
1689 return;
1690 }
1691
1692 if (done++ == 0)
1693 cmn_err(CE_CONT, "?Requesting Internet address for %s\n",
1694 ether_sprintf(&myether));
1695
1696 /*
1697 * Send another RARP request.
1698 */
1699 if ((mp = allocb(sizeof (dl_unitdata_req_t) + sizeof (*dlsap),
1700 BPRI_HI)) == NULL) {
1701 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1702 return;
1703 }
1704 if ((bp = allocb(sizeof (struct ether_arp), BPRI_HI)) == NULL) {
1705 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1706 return;
1707 }
1708
1709 /*
1710 * Format the transmit request part.
1711 */
1712 mp->b_datap->db_type = M_PROTO;
1713 dl_udata = (dl_unitdata_req_t *)mp->b_wptr;
1714 mp->b_wptr += sizeof (dl_unitdata_req_t) + sizeof (*dlsap);
1715 dl_udata->dl_primitive = DL_UNITDATA_REQ;
1716 dl_udata->dl_dest_addr_length = sizeof (*dlsap);
1717 dl_udata->dl_dest_addr_offset = sizeof (*dl_udata);
1718 dl_udata->dl_priority.dl_min = 0;
1719 dl_udata->dl_priority.dl_max = 0;
1720
1721 dlsap = (struct dladdr *)(mp->b_rptr + sizeof (*dl_udata));
1722 bcopy(ðerbroadcastaddr, &dlsap->dl_phys,
1723 sizeof (etherbroadcastaddr));
1724 dlsap->dl_sap = ETHERTYPE_REVARP;
1725
1726 /*
1727 * Format the actual REVARP request.
1728 */
1729 bzero(bp->b_wptr, sizeof (struct ether_arp));
1730 ea = (struct ether_arp *)bp->b_wptr;
1731 bp->b_wptr += sizeof (struct ether_arp);
1732 ea->arp_hrd = htons(ARPHRD_ETHER);
1733 ea->arp_pro = htons(ETHERTYPE_IP);
1734 ea->arp_hln = sizeof (ea->arp_sha); /* hardware address length */
1735 ea->arp_pln = sizeof (ea->arp_spa); /* protocol address length */
1736 ea->arp_op = htons(REVARP_REQUEST);
1737 ether_copy(&myether, &ea->arp_sha);
1738 ether_copy(&myether, &ea->arp_tha);
1739
1740 mp->b_cont = bp;
1741
1742 if ((rc = ldi_putmsg(lh, mp)) != 0) {
1743 nfs_perror(rc, "revarp_start: ldi_putmsg failed: %m\n");
1744 return;
1745 }
1746 revarpinput(lh, myaddr);
1747
1748 goto getreply;
1749 }
1750
1751 /*
1752 * Client side Reverse-ARP input
1753 * Server side is handled by user level server
1754 */
1755 static void
revarpinput(ldi_handle_t lh,struct netbuf * myaddr)1756 revarpinput(ldi_handle_t lh, struct netbuf *myaddr)
1757 {
1758 struct ether_arp *ea;
1759 mblk_t *bp;
1760 mblk_t *mp;
1761 int rc;
1762 timestruc_t tv, give_up, now;
1763
1764 /*
1765 * Choose the time at which we will give up, and resend our
1766 * request.
1767 */
1768 gethrestime(&give_up);
1769 give_up.tv_sec += REVARP_TIMEO;
1770 wait:
1771 /*
1772 * Compute new timeout value.
1773 */
1774 tv = give_up;
1775 gethrestime(&now);
1776 timespecsub(&tv, &now);
1777 /*
1778 * If we don't have at least one full second remaining, give up.
1779 * This means we might wait only just over 4.0 seconds, but that's
1780 * okay.
1781 */
1782 if (tv.tv_sec <= 0)
1783 return;
1784 rc = ldi_getmsg(lh, &mp, &tv);
1785 if (rc == ETIME) {
1786 goto out;
1787 } else if (rc != 0) {
1788 nfs_perror(rc, "revarpinput: ldi_getmsg failed: %m\n");
1789 return;
1790 }
1791
1792 if (mp->b_cont == NULL) {
1793 printf("revarpinput: b_cont == NULL\n");
1794 goto out;
1795 }
1796
1797 if (mp->b_datap->db_type != M_PROTO) {
1798 printf("revarpinput: bad header type %d\n",
1799 mp->b_datap->db_type);
1800 goto out;
1801 }
1802
1803 bp = mp->b_cont;
1804
1805 if (bp->b_wptr - bp->b_rptr < sizeof (*ea)) {
1806 printf("revarpinput: bad data len %d, expect %d\n",
1807 (int)(bp->b_wptr - bp->b_rptr), (int)sizeof (*ea));
1808 goto out;
1809 }
1810
1811 ea = (struct ether_arp *)bp->b_rptr;
1812
1813 if ((ushort_t)ntohs(ea->arp_pro) != ETHERTYPE_IP) {
1814 /* We could have received another broadcast arp packet. */
1815 if (dldebug)
1816 printf("revarpinput: bad type %x\n",
1817 (ushort_t)ntohs(ea->arp_pro));
1818 freemsg(mp);
1819 goto wait;
1820 }
1821 if ((ushort_t)ntohs(ea->arp_op) != REVARP_REPLY) {
1822 /* We could have received a broadcast arp request. */
1823 if (dldebug)
1824 printf("revarpinput: bad op %x\n",
1825 (ushort_t)ntohs(ea->arp_op));
1826 freemsg(mp);
1827 goto wait;
1828 }
1829
1830 if (!ether_cmp(&ea->arp_tha, &myether)) {
1831 bcopy(&ea->arp_tpa, myaddr->buf, sizeof (ea->arp_tpa));
1832 myaddr->len = sizeof (ea->arp_tpa);
1833 } else {
1834 /* We could have gotten a broadcast arp response. */
1835 if (dldebug)
1836 printf("revarpinput: got reply, but not my address\n");
1837 freemsg(mp);
1838 goto wait;
1839 }
1840 out:
1841 freemsg(mp);
1842 }
1843
1844 /*
1845 * From rpcsvc/mountxdr.c in SunOS. We can't
1846 * put this into the rpc directory because
1847 * it calls xdr_fhandle() which is in a
1848 * loadable module.
1849 */
1850 static bool_t
myxdr_fhstatus(XDR * xdrs,struct fhstatus * fhsp)1851 myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp)
1852 {
1853
1854 if (!xdr_int(xdrs, &fhsp->fhs_status))
1855 return (FALSE);
1856 if (fhsp->fhs_status == 0) {
1857 if (!myxdr_fhandle(xdrs, &fhsp->fhs_fh))
1858 return (FALSE);
1859 }
1860 return (TRUE);
1861 }
1862
1863 /*
1864 * From nfs_xdr.c.
1865 *
1866 * File access handle
1867 * The fhandle struct is treated a opaque data on the wire
1868 */
1869 static bool_t
myxdr_fhandle(XDR * xdrs,fhandle_t * fh)1870 myxdr_fhandle(XDR *xdrs, fhandle_t *fh)
1871 {
1872 return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
1873 }
1874
1875 static bool_t
myxdr_mountres3(XDR * xdrs,struct mountres3 * objp)1876 myxdr_mountres3(XDR *xdrs, struct mountres3 *objp)
1877 {
1878 if (!myxdr_mountstat3(xdrs, &objp->fhs_status))
1879 return (FALSE);
1880 switch (objp->fhs_status) {
1881 case MNT_OK:
1882 if (!myxdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
1883 return (FALSE);
1884 break;
1885 default:
1886 break;
1887 }
1888 return (TRUE);
1889 }
1890
1891 static bool_t
myxdr_mountstat3(XDR * xdrs,enum mountstat3 * objp)1892 myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp)
1893 {
1894 return (xdr_enum(xdrs, (enum_t *)objp));
1895 }
1896
1897 static bool_t
myxdr_mountres3_ok(XDR * xdrs,struct mountres3_ok * objp)1898 myxdr_mountres3_ok(XDR *xdrs, struct mountres3_ok *objp)
1899 {
1900 if (!myxdr_fhandle3(xdrs, &objp->fhandle))
1901 return (FALSE);
1902 if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val,
1903 (uint_t *)&objp->auth_flavors.auth_flavors_len, ~0,
1904 sizeof (int), (xdrproc_t)xdr_int))
1905 return (FALSE);
1906 return (TRUE);
1907 }
1908
1909 static bool_t
myxdr_fhandle3(XDR * xdrs,struct fhandle3 * objp)1910 myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp)
1911 {
1912 return (xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
1913 (uint_t *)&objp->fhandle3_len, FHSIZE3));
1914 }
1915
1916 /*
1917 * From SunOS pmap_clnt.c
1918 *
1919 * Port mapper routines:
1920 * pmap_kgetport() - get port number.
1921 * pmap_rmt_call() - indirect call via port mapper.
1922 *
1923 */
1924 static enum clnt_stat
pmap_kgetport(struct knetconfig * knconf,struct netbuf * call_addr,rpcprog_t prog,rpcvers_t vers,rpcprot_t prot)1925 pmap_kgetport(struct knetconfig *knconf, struct netbuf *call_addr,
1926 rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
1927 {
1928 ushort_t port;
1929 int tries;
1930 enum clnt_stat stat;
1931 struct pmap pmap_parms;
1932 RPCB rpcb_parms;
1933 char *ua = NULL;
1934
1935 port = 0;
1936
1937 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
1938
1939 pmap_parms.pm_prog = prog;
1940 pmap_parms.pm_vers = vers;
1941 pmap_parms.pm_prot = prot;
1942 pmap_parms.pm_port = 0;
1943 for (tries = 0; tries < 5; tries++) {
1944 stat = mycallrpc(knconf, call_addr,
1945 PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
1946 myxdr_pmap, (char *)&pmap_parms,
1947 xdr_u_short, (char *)&port,
1948 DEFAULT_TIMEO, DEFAULT_RETRIES);
1949
1950 if (stat != RPC_TIMEDOUT)
1951 break;
1952 cmn_err(CE_WARN,
1953 "pmap_kgetport: Portmapper not responding; still trying");
1954 }
1955
1956 if (stat == RPC_PROGUNAVAIL) {
1957 cmn_err(CE_WARN,
1958 "pmap_kgetport: Portmapper failed - trying rpcbind");
1959
1960 rpcb_parms.r_prog = prog;
1961 rpcb_parms.r_vers = vers;
1962 rpcb_parms.r_netid = knconf->knc_proto;
1963 rpcb_parms.r_addr = rpcb_parms.r_owner = "";
1964
1965 for (tries = 0; tries < 5; tries++) {
1966 stat = mycallrpc(knconf, call_addr,
1967 RPCBPROG, RPCBVERS, RPCBPROC_GETADDR,
1968 xdr_rpcb, (char *)&rpcb_parms,
1969 xdr_wrapstring, (char *)&ua,
1970 DEFAULT_TIMEO, DEFAULT_RETRIES);
1971
1972 if (stat != RPC_TIMEDOUT)
1973 break;
1974 cmn_err(CE_WARN,
1975 "pmap_kgetport: rpcbind not responding; still trying");
1976 }
1977
1978 if (stat == RPC_SUCCESS) {
1979 if ((ua != NULL) && (ua[0] != '\0')) {
1980 port = rpc_uaddr2port(AF_INET, ua);
1981 } else {
1982 /* Address unknown */
1983 stat = RPC_PROGUNAVAIL;
1984 }
1985 }
1986 }
1987
1988 if (stat == RPC_SUCCESS)
1989 ((struct sockaddr_in *)call_addr->buf)->sin_port = ntohs(port);
1990
1991 return (stat);
1992 }
1993
1994 /*
1995 * pmapper remote-call-service interface.
1996 * This routine is used to call the pmapper remote call service
1997 * which will look up a service program in the port maps, and then
1998 * remotely call that routine with the given parameters. This allows
1999 * programs to do a lookup and call in one step. In addition to the call_addr,
2000 * the caller provides a boolean hint about the destination address (TRUE if
2001 * address is a broadcast address, FALSE otherwise).
2002 *
2003 * On return, `call addr' contains the port number for the
2004 * service requested, and `resp_addr' contains its IP address.
2005 */
2006 static enum clnt_stat
pmap_rmt_call(struct knetconfig * knconf,struct netbuf * call_addr,bool_t bcast,rpcprog_t progn,rpcvers_t versn,rpcproc_t procn,xdrproc_t xdrargs,caddr_t argsp,xdrproc_t xdrres,caddr_t resp,struct timeval tout,struct netbuf * resp_addr)2007 pmap_rmt_call(struct knetconfig *knconf, struct netbuf *call_addr,
2008 bool_t bcast, rpcprog_t progn, rpcvers_t versn, rpcproc_t procn,
2009 xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
2010 struct timeval tout, struct netbuf *resp_addr)
2011 {
2012 CLIENT *cl;
2013 enum clnt_stat stat;
2014 rpcport_t port;
2015 int rc;
2016 struct rmtcallargs pmap_args;
2017 struct rmtcallres pmap_res;
2018 struct rpcb_rmtcallargs rpcb_args;
2019 struct rpcb_rmtcallres rpcb_res;
2020 char ua[100]; /* XXX */
2021
2022 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
2023
2024 rc = clnt_tli_kcreate(knconf, call_addr, PMAPPROG, PMAPVERS,
2025 0, PMAP_RETRIES, CRED(), &cl);
2026 if (rc != 0) {
2027 nfs_perror(rc,
2028 "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2029 return (RPC_SYSTEMERROR); /* XXX */
2030 }
2031 if (cl == (CLIENT *)NULL) {
2032 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2033 /* NOTREACHED */
2034 }
2035
2036 (void) CLNT_CONTROL(cl, CLSET_BCAST, (char *)&bcast);
2037
2038 pmap_args.prog = progn;
2039 pmap_args.vers = versn;
2040 pmap_args.proc = procn;
2041 pmap_args.args_ptr = argsp;
2042 pmap_args.xdr_args = xdrargs;
2043 pmap_res.port_ptr = &port;
2044 pmap_res.results_ptr = resp;
2045 pmap_res.xdr_results = xdrres;
2046 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
2047 myxdr_rmtcall_args, (caddr_t)&pmap_args,
2048 myxdr_rmtcallres, (caddr_t)&pmap_res,
2049 tout, resp_addr);
2050
2051 if (stat == RPC_SUCCESS) {
2052 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2053 htons((ushort_t)port);
2054 }
2055 CLNT_DESTROY(cl);
2056
2057 if (stat != RPC_PROGUNAVAIL)
2058 return (stat);
2059
2060 cmn_err(CE_WARN, "pmap_rmt_call: Portmapper failed - trying rpcbind");
2061
2062 rc = clnt_tli_kcreate(knconf, call_addr, RPCBPROG, RPCBVERS,
2063 0, PMAP_RETRIES, CRED(), &cl);
2064 if (rc != 0) {
2065 nfs_perror(rc, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2066 return (RPC_SYSTEMERROR); /* XXX */
2067 }
2068
2069 if (cl == NULL) {
2070 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2071 /* NOTREACHED */
2072 }
2073
2074 rpcb_args.prog = progn;
2075 rpcb_args.vers = versn;
2076 rpcb_args.proc = procn;
2077 rpcb_args.args_ptr = argsp;
2078 rpcb_args.xdr_args = xdrargs;
2079 rpcb_res.addr_ptr = ua;
2080 rpcb_res.results_ptr = resp;
2081 rpcb_res.xdr_results = xdrres;
2082 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
2083 xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_args,
2084 xdr_rpcb_rmtcallres, (caddr_t)&rpcb_res,
2085 tout, resp_addr);
2086
2087 if (stat == RPC_SUCCESS)
2088 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2089 rpc_uaddr2port(AF_INET, ua);
2090 CLNT_DESTROY(cl);
2091
2092 return (stat);
2093 }
2094
2095 /*
2096 * XDR remote call arguments
2097 * written for XDR_ENCODE direction only
2098 */
2099 static bool_t
myxdr_rmtcall_args(XDR * xdrs,struct rmtcallargs * cap)2100 myxdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
2101 {
2102 uint_t lenposition;
2103 uint_t argposition;
2104 uint_t position;
2105
2106 if (xdr_rpcprog(xdrs, &(cap->prog)) &&
2107 xdr_rpcvers(xdrs, &(cap->vers)) &&
2108 xdr_rpcproc(xdrs, &(cap->proc))) {
2109 lenposition = XDR_GETPOS(xdrs);
2110 if (!xdr_u_int(xdrs, &cap->arglen))
2111 return (FALSE);
2112 argposition = XDR_GETPOS(xdrs);
2113 if (!(*(cap->xdr_args))(xdrs, cap->args_ptr))
2114 return (FALSE);
2115 position = XDR_GETPOS(xdrs);
2116 cap->arglen = (uint_t)position - (uint_t)argposition;
2117 XDR_SETPOS(xdrs, lenposition);
2118 if (!xdr_u_int(xdrs, &cap->arglen))
2119 return (FALSE);
2120 XDR_SETPOS(xdrs, position);
2121 return (TRUE);
2122 }
2123 return (FALSE);
2124 }
2125
2126 /*
2127 * XDR remote call results
2128 * written for XDR_DECODE direction only
2129 */
2130 static bool_t
myxdr_rmtcallres(XDR * xdrs,struct rmtcallres * crp)2131 myxdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
2132 {
2133 caddr_t port_ptr;
2134
2135 port_ptr = (caddr_t)crp->port_ptr;
2136 if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) &&
2137 xdr_u_int(xdrs, &crp->resultslen)) {
2138 crp->port_ptr = (rpcport_t *)port_ptr;
2139 return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
2140 }
2141 return (FALSE);
2142 }
2143
2144 static bool_t
myxdr_pmap(XDR * xdrs,struct pmap * regs)2145 myxdr_pmap(XDR *xdrs, struct pmap *regs)
2146 {
2147 if (xdr_rpcprog(xdrs, ®s->pm_prog) &&
2148 xdr_rpcvers(xdrs, ®s->pm_vers) &&
2149 xdr_rpcprot(xdrs, ®s->pm_prot))
2150 return (xdr_rpcport(xdrs, ®s->pm_port));
2151
2152 return (FALSE);
2153 }
2154
2155 /*
2156 * From SunOS callrpc.c
2157 */
2158 static enum clnt_stat
mycallrpc(struct knetconfig * knconf,struct netbuf * call_addr,rpcprog_t prognum,rpcvers_t versnum,rpcproc_t procnum,xdrproc_t inproc,char * in,xdrproc_t outproc,char * out,int timeo,int retries)2159 mycallrpc(struct knetconfig *knconf, struct netbuf *call_addr,
2160 rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
2161 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out,
2162 int timeo, int retries)
2163 {
2164 CLIENT *cl;
2165 struct timeval tv;
2166 enum clnt_stat cl_stat;
2167 int rc;
2168
2169 rc = clnt_tli_kcreate(knconf, call_addr, prognum, versnum,
2170 0, retries, CRED(), &cl);
2171 if (rc) {
2172 nfs_perror(rc, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2173 return (RPC_SYSTEMERROR); /* XXX */
2174 }
2175 tv.tv_sec = timeo;
2176 tv.tv_usec = 0;
2177 cl_stat = CLNT_CALL(cl, procnum, inproc, in, outproc, out, tv);
2178 AUTH_DESTROY(cl->cl_auth);
2179 CLNT_DESTROY(cl);
2180 return (cl_stat);
2181 }
2182
2183 /*
2184 * Configure the 'default' interface based on existing boot properties.
2185 */
2186 static int
bp_netconfig(void)2187 bp_netconfig(void)
2188 {
2189 char *str;
2190 struct in_addr my_ip, my_netmask, my_router, my_broadcast;
2191 struct sockaddr_in *sin;
2192 TIUSER *tiptr;
2193 int rc;
2194 struct rtentry rtentry;
2195
2196 my_ip.s_addr = my_netmask.s_addr = my_router.s_addr = 0;
2197
2198 /*
2199 * No way of getting this right now. Collude with dlifconfig()
2200 * to let the protocol stack choose.
2201 */
2202 my_broadcast.s_addr = INADDR_BROADCAST;
2203
2204 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2205 DDI_PROP_DONTPASS, BP_HOST_IP, &str) == DDI_SUCCESS) {
2206 if (inet_aton(str, (uchar_t *)&my_ip) != 0)
2207 cmn_err(CE_NOTE, "host-ip %s is invalid\n",
2208 str);
2209 ddi_prop_free(str);
2210 if (dldebug)
2211 printf("host ip is %s\n",
2212 inet_ntoa(my_ip));
2213 }
2214 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2215 DDI_PROP_DONTPASS, BP_SUBNET_MASK, &str) == DDI_SUCCESS) {
2216 if (inet_aton(str, (uchar_t *)&my_netmask) != 0)
2217 cmn_err(CE_NOTE, "subnet-mask %s is invalid\n",
2218 str);
2219 ddi_prop_free(str);
2220 if (dldebug)
2221 printf("subnet mask is %s\n",
2222 inet_ntoa(my_netmask));
2223 }
2224 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2225 DDI_PROP_DONTPASS, BP_ROUTER_IP, &str) == DDI_SUCCESS) {
2226 if (inet_aton(str, (uchar_t *)&my_router) != 0)
2227 cmn_err(CE_NOTE, "router-ip %s is invalid\n",
2228 str);
2229 ddi_prop_free(str);
2230 if (dldebug)
2231 printf("router ip is %s\n",
2232 inet_ntoa(my_router));
2233 }
2234 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2235 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c);
2236 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2237 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c);
2238 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2239 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) {
2240 (void) strlcpy(rootopts, str, sizeof (rootopts));
2241 ddi_prop_free(str);
2242 }
2243 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2244 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) {
2245 if (inet_aton(str, server_ip) != 0)
2246 cmn_err(CE_NOTE, "server-ip %s is invalid\n",
2247 str);
2248 ddi_prop_free(str);
2249 if (dldebug)
2250 printf("server ip is %s\n",
2251 inet_ntoa(*(struct in_addr *)server_ip));
2252 }
2253
2254 /*
2255 * We need all of these to configure based on properties.
2256 */
2257 if ((my_ip.s_addr == 0) ||
2258 (my_netmask.s_addr == 0) ||
2259 (server_path_c == NULL) ||
2260 (server_name_c == NULL) ||
2261 (*(uint_t *)server_ip == 0))
2262 return (-1);
2263
2264 cmn_err(CE_CONT, "?IP address: %s\n", inet_ntoa(my_ip));
2265 cmn_err(CE_CONT, "?IP netmask: %s\n", inet_ntoa(my_netmask));
2266 if (my_router.s_addr != 0)
2267 cmn_err(CE_CONT, "?IP router: %s\n", inet_ntoa(my_router));
2268 cmn_err(CE_CONT, "?NFS server: %s (%s)\n", server_name_c,
2269 inet_ntoa(*(struct in_addr *)server_ip));
2270 cmn_err(CE_CONT, "?NFS path: %s\n", server_path_c);
2271
2272 /*
2273 * Configure the interface.
2274 */
2275 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
2276 FREAD|FWRITE, &tiptr, CRED())) != 0) {
2277 nfs_perror(rc, "bp_netconfig: t_kopen udp failed: %m.\n");
2278 return (rc);
2279 }
2280
2281 if ((rc = dlifconfig(tiptr, &my_ip, &my_netmask, &my_broadcast,
2282 0)) < 0) {
2283 nfs_perror(rc, "bp_netconfig: dlifconfig failed: %m.\n");
2284 (void) t_kclose(tiptr, 0);
2285 return (rc);
2286 }
2287
2288 if (my_router.s_addr != 0) {
2289 /*
2290 * Add a default route.
2291 */
2292 sin = (struct sockaddr_in *)&rtentry.rt_dst;
2293 bzero(sin, sizeof (*sin));
2294 sin->sin_family = AF_INET;
2295
2296 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
2297 bzero(sin, sizeof (*sin));
2298 sin->sin_family = AF_INET;
2299 sin->sin_addr = my_router;
2300
2301 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
2302
2303 if ((rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) != 0) {
2304 nfs_perror(rc,
2305 "bp_netconfig: couldn't add route: %m.\n");
2306 (void) t_kclose(tiptr, 0);
2307 return (rc);
2308 }
2309 }
2310
2311 (void) t_kclose(tiptr, 0);
2312
2313 return (0);
2314 }
2315
2316 /*
2317 * The network device we will use to boot from is plumbed. Extract the details
2318 * from rootfs.
2319 */
2320 static void
init_config(void)2321 init_config(void)
2322 {
2323 (void) strlcpy(ndev_path, rootfs.bo_devname, sizeof (ndev_path));
2324 (void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname));
2325 ifunit = rootfs.bo_ppa;
2326
2327 /*
2328 * Assumes only one linkage array element.
2329 */
2330 dl_udp_netconf.knc_rdev =
2331 makedevice(clone_major, ddi_name_to_major("udp"));
2332 dl_tcp_netconf.knc_rdev =
2333 makedevice(clone_major, ddi_name_to_major("tcp"));
2334
2335 /*
2336 * Now we bringup the interface.
2337 * Try cached dhcp response first. If it fails, do rarp.
2338 */
2339 if ((bp_netconfig() != 0) &&
2340 (dhcpinit() != 0) &&
2341 (whoami() != 0))
2342 cmn_err(CE_WARN,
2343 "%s: no response from interface", ifname);
2344 else if (dldebug)
2345 printf("init_config: ifname %s is up\n", ifname);
2346 }
2347
2348 /*
2349 * These options are duplicated in cmd/fs.d/nfs/mount/mount.c
2350 * Changes must be made to both lists.
2351 */
2352 static char *optlist[] = {
2353 #define OPT_RO 0
2354 MNTOPT_RO,
2355 #define OPT_RW 1
2356 MNTOPT_RW,
2357 #define OPT_QUOTA 2
2358 MNTOPT_QUOTA,
2359 #define OPT_NOQUOTA 3
2360 MNTOPT_NOQUOTA,
2361 #define OPT_SOFT 4
2362 MNTOPT_SOFT,
2363 #define OPT_HARD 5
2364 MNTOPT_HARD,
2365 #define OPT_SUID 6
2366 MNTOPT_SUID,
2367 #define OPT_NOSUID 7
2368 MNTOPT_NOSUID,
2369 #define OPT_GRPID 8
2370 MNTOPT_GRPID,
2371 #define OPT_REMOUNT 9
2372 MNTOPT_REMOUNT,
2373 #define OPT_NOSUB 10
2374 MNTOPT_NOSUB,
2375 #define OPT_INTR 11
2376 MNTOPT_INTR,
2377 #define OPT_NOINTR 12
2378 MNTOPT_NOINTR,
2379 #define OPT_PORT 13
2380 MNTOPT_PORT,
2381 #define OPT_SECURE 14
2382 MNTOPT_SECURE,
2383 #define OPT_RSIZE 15
2384 MNTOPT_RSIZE,
2385 #define OPT_WSIZE 16
2386 MNTOPT_WSIZE,
2387 #define OPT_TIMEO 17
2388 MNTOPT_TIMEO,
2389 #define OPT_RETRANS 18
2390 MNTOPT_RETRANS,
2391 #define OPT_ACTIMEO 19
2392 MNTOPT_ACTIMEO,
2393 #define OPT_ACREGMIN 20
2394 MNTOPT_ACREGMIN,
2395 #define OPT_ACREGMAX 21
2396 MNTOPT_ACREGMAX,
2397 #define OPT_ACDIRMIN 22
2398 MNTOPT_ACDIRMIN,
2399 #define OPT_ACDIRMAX 23
2400 MNTOPT_ACDIRMAX,
2401 #define OPT_BG 24
2402 MNTOPT_BG,
2403 #define OPT_FG 25
2404 MNTOPT_FG,
2405 #define OPT_RETRY 26
2406 MNTOPT_RETRY,
2407 #define OPT_NOAC 27
2408 MNTOPT_NOAC,
2409 #define OPT_NOCTO 28
2410 MNTOPT_NOCTO,
2411 #define OPT_LLOCK 29
2412 MNTOPT_LLOCK,
2413 #define OPT_POSIX 30
2414 MNTOPT_POSIX,
2415 #define OPT_VERS 31
2416 MNTOPT_VERS,
2417 #define OPT_PROTO 32
2418 MNTOPT_PROTO,
2419 #define OPT_SEMISOFT 33
2420 MNTOPT_SEMISOFT,
2421 #define OPT_NOPRINT 34
2422 MNTOPT_NOPRINT,
2423 #define OPT_SEC 35
2424 MNTOPT_SEC,
2425 #define OPT_LARGEFILES 36
2426 MNTOPT_LARGEFILES,
2427 #define OPT_NOLARGEFILES 37
2428 MNTOPT_NOLARGEFILES,
2429 #define OPT_PUBLIC 38
2430 MNTOPT_PUBLIC,
2431 #define OPT_DIRECTIO 39
2432 MNTOPT_FORCEDIRECTIO,
2433 #define OPT_NODIRECTIO 40
2434 MNTOPT_NOFORCEDIRECTIO,
2435 #define OPT_XATTR 41
2436 MNTOPT_XATTR,
2437 #define OPT_NOXATTR 42
2438 MNTOPT_NOXATTR,
2439 #define OPT_DEVICES 43
2440 MNTOPT_DEVICES,
2441 #define OPT_NODEVICES 44
2442 MNTOPT_NODEVICES,
2443 #define OPT_SETUID 45
2444 MNTOPT_SETUID,
2445 #define OPT_NOSETUID 46
2446 MNTOPT_NOSETUID,
2447 #define OPT_EXEC 47
2448 MNTOPT_EXEC,
2449 #define OPT_NOEXEC 48
2450 MNTOPT_NOEXEC,
2451 NULL
2452 };
2453
2454 static int
isdigit(int ch)2455 isdigit(int ch)
2456 {
2457 return (ch >= '0' && ch <= '9');
2458 }
2459
2460 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2461 #define bad(val) (val == NULL || !isdigit(*val))
2462
2463 static int
atoi(const char * p)2464 atoi(const char *p)
2465 {
2466 int n;
2467 int c, neg = 0;
2468
2469 if (!isdigit(c = *p)) {
2470 while (isspace(c))
2471 c = *++p;
2472 switch (c) {
2473 case '-':
2474 neg++;
2475 /* FALLTHROUGH */
2476 case '+':
2477 c = *++p;
2478 }
2479 if (!isdigit(c))
2480 return (0);
2481 }
2482 for (n = '0' - c; isdigit(c = *++p); ) {
2483 n *= 10; /* two steps to avoid unnecessary overflow */
2484 n += '0' - c; /* accum neg to avoid surprises at MAX */
2485 }
2486 return (neg ? n : -n);
2487 }
2488
2489 /*
2490 * Default root read tsize XXX
2491 */
2492 int nfs_root_rsize = 8 * 1024; /* conservative for dumb NICs */
2493 int nfs4_root_rsize = 32 * 1024; /* only runs on TCP be aggressive */
2494
2495 /*
2496 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2497 */
2498 int nfs_rootopts = NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT;
2499
2500 static int
init_mountopts(struct nfs_args * args,int version,struct knetconfig ** dl_cf,int * vfsflags)2501 init_mountopts(struct nfs_args *args, int version, struct knetconfig **dl_cf,
2502 int *vfsflags)
2503 {
2504 char servername[SYS_NMLN];
2505 static int first = 0;
2506 struct netbuf server_address;
2507 char *opts, *val;
2508 int vers;
2509 struct knetconfig *cf = *dl_cf;
2510 char rootoptsbuf[256];
2511
2512 /*
2513 * Set default mount options
2514 */
2515 args->flags = nfs_rootopts;
2516 args->rsize = 0;
2517 args->flags |= NFSMNT_ACREGMIN;
2518 args->acregmin = ACMINMAX;
2519 args->flags |= NFSMNT_ACREGMAX;
2520 args->acregmax = ACMAXMAX;
2521 args->flags |= NFSMNT_ACDIRMIN;
2522 args->acdirmin = ACMINMAX;
2523 args->flags |= NFSMNT_ACDIRMAX;
2524 args->acdirmax = ACMAXMAX;
2525
2526 *vfsflags = 0;
2527
2528 /*
2529 * Only look up the rootopts the first time, we store this in
2530 * a static buffer but we are guaranteed to be single threaded
2531 * and not reentrant.
2532 */
2533 if (first == 0) {
2534 first++;
2535
2536 init_netbuf(&server_address);
2537
2538 if (getfile("rootopts", servername, &server_address,
2539 rootopts)) {
2540 rootopts[0] = '\0';
2541 free_netbuf(&server_address);
2542 goto sanity;
2543 }
2544 free_netbuf(&server_address);
2545 }
2546
2547 if (dldebug)
2548 printf("rootopts = %s\n", rootopts);
2549
2550 /*
2551 * We have to preserve rootopts for second time.
2552 */
2553 (void) strncpy(rootoptsbuf, rootopts, sizeof (rootoptsbuf));
2554 rootoptsbuf[sizeof (rootoptsbuf) - 1] = '\0';
2555 opts = rootoptsbuf;
2556 while (*opts) {
2557 int opt;
2558
2559 switch (opt = getsubopt(&opts, optlist, &val)) {
2560 /*
2561 * Options that are defaults or meaningless so ignored
2562 */
2563 case OPT_QUOTA:
2564 case OPT_NOQUOTA:
2565 case OPT_SUID:
2566 case OPT_DEVICES:
2567 case OPT_SETUID:
2568 case OPT_BG:
2569 case OPT_FG:
2570 case OPT_RETRY:
2571 case OPT_POSIX:
2572 case OPT_LARGEFILES:
2573 case OPT_XATTR:
2574 case OPT_NOXATTR:
2575 case OPT_EXEC:
2576 break;
2577 case OPT_RO:
2578 *vfsflags |= MS_RDONLY;
2579 break;
2580 case OPT_RW:
2581 *vfsflags &= ~(MS_RDONLY);
2582 break;
2583 case OPT_SOFT:
2584 args->flags |= NFSMNT_SOFT;
2585 args->flags &= ~(NFSMNT_SEMISOFT);
2586 break;
2587 case OPT_SEMISOFT:
2588 args->flags |= NFSMNT_SOFT;
2589 args->flags |= NFSMNT_SEMISOFT;
2590 break;
2591 case OPT_HARD:
2592 args->flags &= ~(NFSMNT_SOFT);
2593 args->flags &= ~(NFSMNT_SEMISOFT);
2594 break;
2595 case OPT_NOSUID:
2596 case OPT_NODEVICES:
2597 case OPT_NOSETUID:
2598 case OPT_NOEXEC:
2599 cmn_err(CE_WARN,
2600 "nfs_dlboot: may not set root partition %s",
2601 optlist[opt]);
2602 break;
2603 case OPT_GRPID:
2604 args->flags |= NFSMNT_GRPID;
2605 break;
2606 case OPT_REMOUNT:
2607 cmn_err(CE_WARN,
2608 "nfs_dlboot: may not remount root partition");
2609 break;
2610 case OPT_INTR:
2611 args->flags |= NFSMNT_INT;
2612 break;
2613 case OPT_NOINTR:
2614 args->flags &= ~(NFSMNT_INT);
2615 break;
2616 case OPT_NOAC:
2617 args->flags |= NFSMNT_NOAC;
2618 break;
2619 case OPT_PORT:
2620 cmn_err(CE_WARN,
2621 "nfs_dlboot: may not change root port number");
2622 break;
2623 case OPT_SECURE:
2624 cmn_err(CE_WARN,
2625 "nfs_dlboot: root mounted auth_unix, secure ignored");
2626 break;
2627 case OPT_NOCTO:
2628 args->flags |= NFSMNT_NOCTO;
2629 break;
2630 case OPT_RSIZE:
2631 if (bad(val)) {
2632 cmn_err(CE_WARN,
2633 "nfs_dlboot: invalid option: rsize");
2634 break;
2635 }
2636 args->flags |= NFSMNT_RSIZE;
2637 args->rsize = atoi(val);
2638 break;
2639 case OPT_WSIZE:
2640 if (bad(val)) {
2641 cmn_err(CE_WARN,
2642 "nfs_dlboot: invalid option: wsize");
2643 break;
2644 }
2645 args->flags |= NFSMNT_WSIZE;
2646 args->wsize = atoi(val);
2647 break;
2648 case OPT_TIMEO:
2649 if (bad(val)) {
2650 cmn_err(CE_WARN,
2651 "nfs_dlboot: invalid option: timeo");
2652 break;
2653 }
2654 args->flags |= NFSMNT_TIMEO;
2655 args->timeo = atoi(val);
2656 break;
2657 case OPT_RETRANS:
2658 if (bad(val)) {
2659 cmn_err(CE_WARN,
2660 "nfs_dlboot: invalid option: retrans");
2661 break;
2662 }
2663 args->flags |= NFSMNT_RETRANS;
2664 args->retrans = atoi(val);
2665 break;
2666 case OPT_ACTIMEO:
2667 if (bad(val)) {
2668 cmn_err(CE_WARN,
2669 "nfs_dlboot: invalid option: actimeo");
2670 break;
2671 }
2672 args->flags |= NFSMNT_ACDIRMAX;
2673 args->flags |= NFSMNT_ACREGMAX;
2674 args->flags |= NFSMNT_ACDIRMIN;
2675 args->flags |= NFSMNT_ACREGMIN;
2676 args->acdirmin = args->acregmin = args->acdirmax =
2677 args->acregmax = atoi(val);
2678 break;
2679 case OPT_ACREGMIN:
2680 if (bad(val)) {
2681 cmn_err(CE_WARN,
2682 "nfs_dlboot: invalid option: acregmin");
2683 break;
2684 }
2685 args->flags |= NFSMNT_ACREGMIN;
2686 args->acregmin = atoi(val);
2687 break;
2688 case OPT_ACREGMAX:
2689 if (bad(val)) {
2690 cmn_err(CE_WARN,
2691 "nfs_dlboot: invalid option: acregmax");
2692 break;
2693 }
2694 args->flags |= NFSMNT_ACREGMAX;
2695 args->acregmax = atoi(val);
2696 break;
2697 case OPT_ACDIRMIN:
2698 if (bad(val)) {
2699 cmn_err(CE_WARN,
2700 "nfs_dlboot: invalid option: acdirmin");
2701 break;
2702 }
2703 args->flags |= NFSMNT_ACDIRMIN;
2704 args->acdirmin = atoi(val);
2705 break;
2706 case OPT_ACDIRMAX:
2707 if (bad(val)) {
2708 cmn_err(CE_WARN,
2709 "nfs_dlboot: invalid option: acdirmax");
2710 break;
2711 }
2712 args->flags |= NFSMNT_ACDIRMAX;
2713 args->acdirmax = atoi(val);
2714 break;
2715 case OPT_LLOCK:
2716 args->flags |= NFSMNT_LLOCK;
2717 break;
2718 case OPT_VERS:
2719 if (bad(val)) {
2720 cmn_err(CE_WARN,
2721 "nfs_dlboot: invalid option: vers");
2722 break;
2723 }
2724 vers = atoi(val);
2725 /*
2726 * If the requested version is less than what we
2727 * chose, pretend the chosen version doesn't exist
2728 */
2729 if (vers < version) {
2730 return (EPROTONOSUPPORT);
2731 }
2732 if (vers > version) {
2733 cmn_err(CE_WARN,
2734 "nfs_dlboot: version %d unavailable",
2735 vers);
2736 return (EINVAL);
2737 }
2738 break;
2739 case OPT_PROTO:
2740 /*
2741 * NFSv4 can only run over TCP, if they requested
2742 * UDP pretend v4 doesn't exist, they might not have
2743 * specified a version allowing a fallback to v2 or v3.
2744 */
2745 if (version == NFS_V4 && strcmp(val, NC_UDP) == 0)
2746 return (EPROTONOSUPPORT);
2747 /*
2748 * TCP is always chosen over UDP, so if the
2749 * requested is the same as the chosen either
2750 * they chose TCP when available or UDP on a UDP
2751 * only server.
2752 */
2753 if (strcmp(cf->knc_proto, val) == 0)
2754 break;
2755 /*
2756 * If we chose UDP, they must have requested TCP
2757 */
2758 if (strcmp(cf->knc_proto, NC_TCP) != 0) {
2759 cmn_err(CE_WARN,
2760 "nfs_dlboot: TCP protocol unavailable");
2761 return (EINVAL);
2762 }
2763 /*
2764 * They can only have requested UDP
2765 */
2766 if (strcmp(val, NC_UDP) != 0) {
2767 cmn_err(CE_WARN,
2768 "nfs_dlboot: unknown protocol");
2769 return (EINVAL);
2770 }
2771 *dl_cf = &dl_udp_netconf;
2772 break;
2773 case OPT_NOPRINT:
2774 args->flags |= NFSMNT_NOPRINT;
2775 break;
2776 case OPT_NOLARGEFILES:
2777 cmn_err(CE_WARN,
2778 "nfs_dlboot: NFS can't support nolargefiles");
2779 break;
2780 case OPT_SEC:
2781 cmn_err(CE_WARN,
2782 "nfs_dlboot: root mounted auth_unix, sec ignored");
2783 break;
2784
2785 case OPT_DIRECTIO:
2786 args->flags |= NFSMNT_DIRECTIO;
2787 break;
2788
2789 case OPT_NODIRECTIO:
2790 args->flags &= ~(NFSMNT_DIRECTIO);
2791 break;
2792
2793 default:
2794 cmn_err(CE_WARN,
2795 "nfs_dlboot: ignoring invalid option \"%s\"", val);
2796 break;
2797 }
2798 }
2799 sanity:
2800 /*
2801 * Set some sane limits on read size
2802 */
2803 if (!(args->flags & NFSMNT_RSIZE) || args->rsize == 0) {
2804 /*
2805 * Establish defaults
2806 */
2807 args->flags |= NFSMNT_RSIZE;
2808 if (version == NFS_V4)
2809 args->rsize = nfs4_root_rsize;
2810 else
2811 args->rsize = nfs_root_rsize;
2812 return (0);
2813 }
2814 /*
2815 * No less than 512 bytes, otherwise it will take forever to boot
2816 */
2817 if (args->rsize < 512)
2818 args->rsize = 512;
2819 /*
2820 * If we are running over UDP, we cannot exceed 64KB, trim
2821 * to 56KB to allow room for headers.
2822 */
2823 if (*dl_cf == &dl_udp_netconf && args->rsize > (56 * 1024))
2824 args->rsize = 56 * 1024;
2825 return (0);
2826 }
2827