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