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