blob: 34658b161f1395a1eeb4b7ec131f87531735d46b [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
johnlev843e1982007-09-18 15:46:43 -07005 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07007 *
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/*
yz147064d62bc4b2008-01-23 18:09:15 -080022 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070023 * Use is subject to license terms.
24 */
25
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070026#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
110struct fhstatus {
111 int fhs_status;
112 fhandle_t fhs_fh;
113};
114
115#define FHSIZE3 64
116
117struct fhandle3 {
118 uint_t fhandle3_len;
119 char *fhandle3_val;
120};
121
122enum 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
135struct mountres3_ok {
136 struct fhandle3 fhandle;
137 struct {
138 uint_t auth_flavors_len;
139 int *auth_flavors_val;
140 } auth_flavors;
141};
142
143struct mountres3 {
144 enum mountstat3 fhs_status;
145 union {
146 struct mountres3_ok mountinfo;
147 } mountres3_u;
148};
149
150/*
151 * DLPI address format.
152 */
153struct dladdr {
154 uchar_t dl_phys[6];
155 ushort_t dl_sap;
156};
157
158static struct modlmisc modlmisc = {
159 &mod_miscops, "Boot diskless"
160};
161
162static struct modlinkage modlinkage = {
163 MODREV_1, (void *)&modlmisc, NULL
164};
165
166static int dldebug;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700167
168int
169_init(void)
170{
171 return (mod_install(&modlinkage));
172}
173
174int
175_fini(void)
176{
177 return (mod_remove(&modlinkage));
178}
179
180int
181_info(struct modinfo *modinfop)
182{
183 return (mod_info(&modlinkage, modinfop));
184}
185
dduvallcc2b7f02005-10-11 15:55:16 -0700186
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700187static 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 *);
191static bool_t myxdr_rmtcall_args(XDR *, struct rmtcallargs *);
192static bool_t myxdr_rmtcallres(XDR *, struct rmtcallres *);
193static bool_t myxdr_pmap(XDR *, struct pmap *);
194static bool_t myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp);
195static bool_t myxdr_fhandle(XDR *xdrs, fhandle_t *fh);
196static bool_t myxdr_mountres3(XDR *xdrs, struct mountres3 *objp);
197static bool_t myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp);
198static bool_t myxdr_mountres3_ok(XDR *xdrs,
199 struct mountres3_ok *objp);
200static bool_t myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp);
201static enum clnt_stat pmap_kgetport(struct knetconfig *, struct netbuf *,
202 rpcprog_t, rpcvers_t, rpcprot_t);
203static enum clnt_stat mycallrpc(struct knetconfig *, struct netbuf *,
204 rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
205 char *, xdrproc_t, char *, int, int);
206static int ifioctl(TIUSER *, int, struct netbuf *);
207static int getfile(char *, char *, struct netbuf *, char *);
208static int ping_prog(struct netbuf *, uint_t prog, uint_t vers,
209 int proto, enum clnt_stat *);
210static int mountnfs(struct netbuf *, char *, char *,
211 fhandle_t *, int *);
212static int mountnfs3(struct netbuf *, char *, char *,
213 nfs_fh3 *, int *);
214static int init_mountopts(struct nfs_args *, int,
215 struct knetconfig **, int *);
216static int revarp_myaddr(TIUSER *);
217static void revarp_start(ldi_handle_t, struct netbuf *);
218static void revarpinput(ldi_handle_t, struct netbuf *);
219static void init_netbuf(struct netbuf *);
220static void free_netbuf(struct netbuf *);
221static int rtioctl(TIUSER *, int, struct rtentry *);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700222static void init_config(void);
223
224static void cacheinit(void);
225static int cacheinfo(char *, int, struct netbuf *, char *, int);
226static int dlifconfig(TIUSER *, struct in_addr *, struct in_addr *,
johnlev843e1982007-09-18 15:46:43 -0700227 struct in_addr *, uint_t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700228static int setifflags(TIUSER *, uint_t);
229
230static char *inet_ntoa(struct in_addr);
231static int inet_aton(char *, uchar_t *);
232static int isdigit(int);
233
234/*
235 * Should be in some common
236 * ethernet source file.
237 */
238static struct ether_addr etherbroadcastaddr = {
239 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
240};
241
242static 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
255static char ifname[IFNAMSIZ];
256static char ndev_path[MAXPATHLEN];
257static int ifunit;
258
259/*
260 * XXX these should be shared
261 */
262static struct knetconfig dl_udp_netconf = {
263 NC_TPI_CLTS, /* semantics */
264 NC_INET, /* family */
265 NC_UDP, /* protocol */
266 0, /* device */
267};
268
269static 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 */
277static PKT_LIST *pl = NULL;
278static uchar_t server_ip[4];
279static uchar_t dhcp_server_ip[4];
280static char *server_name_c, *server_path_c;
281static 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 */
287int nfs4_no_diskless_root_support = 1;
288
289int
290mount_root(char *name, char *path, int version, struct nfs_args *args,
Toomas Soomef3de0dd2016-12-18 00:37:43 +0200291 int *vfsflags)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700292{
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 =
johnlev843e1982007-09-18 15:46:43 -0700332 htons(NFS_PORT);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700333 if (ping_prog(args->addr, NFS_PROGRAM, NFS_V4, IPPROTO_TCP,
johnlev843e1982007-09-18 15:46:43 -0700334 &stat)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700335 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
382errout:
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 */
399static int
400mountnfs(struct netbuf *sa, char *server,
Toomas Soomef3de0dd2016-12-18 00:37:43 +0200401 char *path, fhandle_t *fh, int *proto)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700402{
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 */
479static int
480mountnfs3(struct netbuf *sa, char *server,
Toomas Soomef3de0dd2016-12-18 00:37:43 +0200481 char *path, nfs_fh3 *fh, int *proto)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700482{
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",
johnlev843e1982007-09-18 15:46:43 -0700553 mountres3.fhs_status);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700554 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
570out:
571 xdr_free(myxdr_mountres3, (caddr_t)&mountres3);
572
573 if (dldebug)
574 printf("mountnfs3: leaving\n");
575 return (ret);
576}
577
578static int
579ping_prog(struct netbuf *call_addr, uint_t prog, uint_t vers, int proto,
Toomas Soomef3de0dd2016-12-18 00:37:43 +0200580 enum clnt_stat *statp)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700581{
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
621static 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 */
629static int
630whoami(void)
631{
dduvallcc2b7f02005-10-11 15:55:16 -0700632 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;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700642
dduvallcc2b7f02005-10-11 15:55:16 -0700643 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
644 FREAD|FWRITE, &tiptr, CRED())) != 0) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700645 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 }
dduvallcc2b7f02005-10-11 15:55:16 -0700676
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700677 /*
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 }
dduvallcc2b7f02005-10-11 15:55:16 -0700740
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700741 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;
dduvallcc2b7f02005-10-11 15:55:16 -0700772 struct in_addr ipaddr;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700773
774 bcopy(&res.router_address.bp_address.ip_addr, &ipaddr,
dduvallcc2b7f02005-10-11 15:55:16 -0700775 sizeof (struct in_addr));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700776
dduvallcc2b7f02005-10-11 15:55:16 -0700777 if (ipaddr.s_addr != (uint32_t)0) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700778 sin = (struct sockaddr_in *)&rtentry.rt_dst;
779 bzero(sin, sizeof (*sin));
780 sin->sin_family = AF_INET;
dduvallcc2b7f02005-10-11 15:55:16 -0700781
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700782 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
783 bzero(sin, sizeof (*sin));
784 sin->sin_family = AF_INET;
dduvallcc2b7f02005-10-11 15:55:16 -0700785 sin->sin_addr.s_addr = ipaddr.s_addr;
786
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700787 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
dduvallcc2b7f02005-10-11 15:55:16 -0700788
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700789 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 }
799done:
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 */
815static int
816getfile(char *fileid,
Toomas Soomef3de0dd2016-12-18 00:37:43 +0200817 char *server_name, struct netbuf *server_address, char *server_path)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700818{
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;
dduvallcc2b7f02005-10-11 15:55:16 -0700824 struct in_addr ipaddr;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700825 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));
dduvallcc2b7f02005-10-11 15:55:16 -0700928 if (ipaddr.s_addr == 0)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700929 return (EINVAL);
930
931 ((struct sockaddr_in *)server_address->buf)->sin_addr.s_addr =
dduvallcc2b7f02005-10-11 15:55:16 -0700932 ipaddr.s_addr;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700933 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/*
setje986fd292007-12-07 16:04:33 -0800947 * If the boot property "bootp-response" exists, then OBP performed a
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700948 * 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 */
954int
955dhcpinit(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;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700964 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
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700975 if (dldebug) {
976 printf("dhcp: dhcack %p, len %d\n", (void *)dhcack,
setje986fd292007-12-07 16:04:33 -0800977 dhcacklen);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700978 }
979
980 pl = kmem_alloc(sizeof (PKT_LIST), KM_SLEEP);
setje986fd292007-12-07 16:04:33 -0800981 pl->len = dhcacklen;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700982 pl->pkt = kmem_alloc(pl->len, KM_SLEEP);
setje986fd292007-12-07 16:04:33 -0800983 bcopy(dhcack, pl->pkt, dhcacklen);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700984
985 /*
setje986fd292007-12-07 16:04:33 -0800986 * For x86, ifname is not initialized
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700987 * 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])
setje986fd292007-12-07 16:04:33 -0800992 (void) strlcpy(dhcifname, ifname, sizeof (dhcifname));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700993
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);
sangeeta2a9459b2007-12-03 10:10:44 -08001068 else if (IN_CLASSD(ntohl(myIPaddr.s_addr)))
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001069 cmn_err(CE_WARN, "dhcp: bad IP address (%s)",
1070 inet_ntoa(myIPaddr));
sangeeta2a9459b2007-12-03 10:10:44 -08001071 else
1072 subnet.s_addr = htonl(IN_CLASSE_NET);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001073 }
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,
johnlev843e1982007-09-18 15:46:43 -07001097 &braddr, IFF_DHCPRUNNING)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001098 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 */
1169static void
1170cacheinit(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)
Toomas Soomef3de0dd2016-12-18 00:37:43 +02001187 cmn_err(CE_NOTE, "server_ipaddr %s is invalid",
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001188 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];
Toomas Soomef3de0dd2016-12-18 00:37:43 +02001201 if (doptp == NULL)
1202 doptp = pl->opts[CD_ROOT_PATH];
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001203 if (doptp != NULL) {
Toomas Soome48373132018-09-13 20:05:48 +03001204 int len, size;
1205 uint8_t c, *source;
1206
Toomas Soomef3de0dd2016-12-18 00:37:43 +02001207 str = NULL;
Toomas Soome48373132018-09-13 20:05:48 +03001208 source = doptp->value;
1209 size = doptp->len;
1210 c = ':';
1211
1212 /*
1213 * We have to consider three cases for root path:
1214 * "nfs://server_ip/path"
1215 * "server_ip:/path"
1216 * "/path"
1217 */
1218 if (bcmp(source, "nfs://", 6) == 0) {
1219 source += 6;
1220 size -= 6;
1221 c = '/';
1222 }
1223 /*
1224 * Search for next char after ':' or first '/'.
1225 * Note, the '/' is part of the path, but we do
1226 * not need to preserve the ':'.
1227 */
1228 for (len = 0; len < size; len++) {
1229 if (source[len] == c) {
1230 if (c == ':') {
1231 str = (char *)(&source[++len]);
1232 } else {
1233 str = (char *)(&source[len++]);
1234 size++;
1235 }
Toomas Soomef3de0dd2016-12-18 00:37:43 +02001236 break;
1237 }
1238 }
1239 if (str != NULL) {
1240 /* Do not override server_ip from property. */
1241 if ((*(uint_t *)server_ip) == 0) {
1242 char *ip = kmem_alloc(len, KM_SLEEP);
Toomas Soome48373132018-09-13 20:05:48 +03001243 bcopy(source, ip, len);
Toomas Soomef3de0dd2016-12-18 00:37:43 +02001244 ip[len - 1] = '\0';
1245 if (inet_aton((ip), server_ip) != 0) {
1246 cmn_err(CE_NOTE,
1247 "server_ipaddr %s is "
1248 "invalid", ip);
1249 }
1250 kmem_free(ip, len);
1251 if (dldebug) {
1252 printf("server ip is %s\n",
1253 inet_ntoa(
1254 *(struct in_addr *)
1255 server_ip));
1256 }
1257 }
Toomas Soome48373132018-09-13 20:05:48 +03001258 len = size - len;
Toomas Soomef3de0dd2016-12-18 00:37:43 +02001259 } else {
1260 str = (char *)doptp->value;
1261 len = doptp->len;
1262 }
1263 server_path_c = kmem_alloc(len + 1, KM_SLEEP);
1264 bcopy(str, server_path_c, len);
1265 server_path_c[len] = '\0';
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001266 if (dldebug)
1267 printf("dhcp: root path %s\n", server_path_c);
1268 } else {
1269 cmn_err(CE_WARN, "dhcp: root server path missing");
1270 }
1271 }
1272
1273 /* set server_name */
1274 if (server_name_c == NULL) {
1275 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_NAME];
1276 if (doptp != NULL) {
1277 server_name_c = kmem_alloc(doptp->len + 1, KM_SLEEP);
1278 bcopy(doptp->value, server_name_c, doptp->len);
1279 server_name_c[doptp->len] = '\0';
1280 if (dldebug)
1281 printf("dhcp: root server name %s\n",
1282 server_name_c);
1283 } else {
1284 cmn_err(CE_WARN, "dhcp: root server name missing");
1285 }
1286 }
1287
1288 /* set root server_address */
1289 if ((*(uint_t *)server_ip) == 0) {
1290 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_IP];
1291 if (doptp) {
1292 bcopy(doptp->value, server_ip, sizeof (server_ip));
1293 if (dldebug) {
1294 printf("dhcp: root server IP address %s\n",
1295 inet_ntoa(*(struct in_addr *)server_ip));
1296 }
1297 } else {
1298 if (dldebug)
1299 cmn_err(CE_CONT,
1300 "dhcp: file server ip address missing,"
1301 " fallback to dhcp server as file server");
1302 bcopy(dhcp_server_ip, server_ip, sizeof (server_ip));
1303 }
1304 }
1305
1306 /* set root file system mount options */
1307 if (rootopts[0] == 0) {
1308 doptp = pl->vs[VS_NFSMNT_ROOTOPTS];
1309 if (doptp != NULL && doptp->len < 255) {
1310 bcopy(doptp->value, rootopts, doptp->len);
1311 rootopts[doptp->len] = '\0';
1312 if (dldebug)
1313 printf("dhcp: rootopts %s\n", rootopts);
1314 } else if (dldebug) {
1315 printf("dhcp: no rootopts or too long\n");
1316 /* not an error */
1317 }
1318 }
1319
1320 /* now we are done with pl, just free it */
1321 kmem_free(pl->pkt, pl->len);
1322 kmem_free(pl, sizeof (PKT_LIST));
1323 pl = NULL;
1324}
1325
1326static int
1327cacheinfo(char *name, int namelen,
1328 struct netbuf *server_address, char *rootpath, int pathlen)
1329{
1330 static int init_done = 0;
1331 struct sockaddr_in *sin;
1332
1333 if (init_done == 0) {
1334 cacheinit();
1335 init_done = 1;
1336 }
1337
1338 /* server_path is a reliable indicator of cache availability */
1339 if (server_path_c == NULL)
1340 return (-1);
1341
1342 (void) strncpy(rootpath, server_path_c, pathlen);
1343 if (server_name_c) {
1344 (void) strncpy(name, server_name_c, namelen);
1345 } else {
1346 (void) strncpy(name, "unknown", namelen);
1347 }
1348
1349 sin = (struct sockaddr_in *)server_address->buf;
1350 sin->sin_family = AF_INET;
1351 server_address->len = sizeof (struct sockaddr_in);
1352 bcopy(server_ip, &sin->sin_addr, sizeof (struct in_addr));
1353 return (0);
1354}
1355
1356/*
1357 * Set this interface's IP address and netmask, and bring it up.
1358 */
1359static int
1360dlifconfig(TIUSER *tiptr, struct in_addr *myIPaddr, struct in_addr *mymask,
johnlev843e1982007-09-18 15:46:43 -07001361 struct in_addr *mybraddr, uint_t flags)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001362{
1363 int rc;
1364 struct netbuf sbuf;
1365 struct sockaddr_in sin;
1366
1367 if (dldebug) {
1368 printf("dlifconfig: entered\n");
1369 printf("dlifconfig: addr %s\n", inet_ntoa(*myIPaddr));
1370 printf("dlifconfig: mask %s\n", inet_ntoa(*mymask));
1371 printf("dlifconfig: broadcast %s\n", inet_ntoa(*mybraddr));
1372 }
1373
1374 bcopy(myIPaddr, &sin.sin_addr, sizeof (struct in_addr));
1375 sin.sin_family = AF_INET;
1376 sbuf.buf = (caddr_t)&sin;
1377 sbuf.maxlen = sbuf.len = sizeof (sin);
1378 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1379 nfs_perror(rc,
1380 "dlifconfig: couldn't set interface net address: %m\n");
1381 return (rc);
1382 }
1383
1384 if (mybraddr->s_addr != INADDR_BROADCAST) {
1385 bcopy(mybraddr, &sin.sin_addr, sizeof (struct in_addr));
1386 sin.sin_family = AF_INET;
1387 sbuf.buf = (caddr_t)&sin;
1388 sbuf.maxlen = sbuf.len = sizeof (sin);
1389 if (rc = ifioctl(tiptr, SIOCSIFBRDADDR, &sbuf)) {
1390 nfs_perror(rc,
1391 "dlifconfig: couldn't set interface broadcast addr: %m\n");
1392 return (rc);
1393 }
1394 }
1395
1396 bcopy(mymask, &sin.sin_addr, sizeof (struct in_addr));
1397 sin.sin_family = AF_INET;
1398 sbuf.buf = (caddr_t)&sin;
1399 sbuf.maxlen = sbuf.len = sizeof (sin);
1400 if (rc = ifioctl(tiptr, SIOCSIFNETMASK, &sbuf)) {
1401 nfs_perror(rc,
1402 "dlifconfig: couldn't set interface net address: %m\n");
1403 return (rc);
1404 }
1405
1406 /*
1407 * Now turn on the interface.
1408 */
johnlev843e1982007-09-18 15:46:43 -07001409 if (rc = setifflags(tiptr, IFF_UP | flags)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001410 nfs_perror(rc,
1411 "dlifconfig: couldn't enable network interface: %m\n");
1412 return (rc);
1413 }
1414
1415 if (dldebug)
1416 printf("dlifconfig: returned\n");
1417 return (0);
1418}
1419
1420static char *
1421inet_ntoa(struct in_addr in)
1422{
1423 static char b[18];
1424 unsigned char *p;
1425
1426 p = (unsigned char *)&in;
1427 (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1428 return (b);
1429}
1430
1431/* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1432static int
1433inet_aton(char *ipstr, uchar_t *ip)
1434{
1435 int i = 0;
1436 uchar_t val[4] = {0};
1437 char c = *ipstr;
1438
1439 for (;;) {
1440 if (!isdigit(c))
1441 return (-1);
1442 for (;;) {
1443 if (!isdigit(c))
1444 break;
1445 val[i] = val[i] * 10 + (c - '0');
1446 c = *++ipstr;
1447 }
1448 i++;
1449 if (i == 4)
1450 break;
1451 if (c != '.')
1452 return (-1);
1453 c = *++ipstr;
1454 }
1455 if (c != 0)
1456 return (-1);
1457 bcopy(val, ip, 4);
1458 return (0);
1459}
1460
1461#define MAX_ADDR_SIZE 128
1462
1463/*
1464 * Initialize a netbuf suitable for
1465 * describing an address for the
1466 * transport defined by `tiptr'.
1467 */
1468static void
1469init_netbuf(struct netbuf *nbuf)
1470{
1471 nbuf->buf = kmem_zalloc(MAX_ADDR_SIZE, KM_SLEEP);
1472 nbuf->maxlen = MAX_ADDR_SIZE;
1473 nbuf->len = 0;
1474}
1475
1476static void
1477free_netbuf(struct netbuf *nbuf)
1478{
1479 kmem_free(nbuf->buf, nbuf->maxlen);
1480 nbuf->buf = NULL;
1481 nbuf->maxlen = 0;
1482 nbuf->len = 0;
1483}
1484
1485static int
1486rtioctl(TIUSER *tiptr, int cmd, struct rtentry *rtentry)
1487{
1488 struct strioctl iocb;
1489 int rc;
1490 vnode_t *vp;
1491
1492 iocb.ic_cmd = cmd;
1493 iocb.ic_timout = 0;
1494 iocb.ic_len = sizeof (struct rtentry);
1495 iocb.ic_dp = (caddr_t)rtentry;
1496
1497 vp = tiptr->fp->f_vnode;
1498 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1499 if (rc)
1500 nfs_perror(rc, "rtioctl: kstr_ioctl failed: %m\n");
1501 return (rc);
1502}
1503
1504/*
1505 * Send an ioctl down the stream defined
1506 * by `tiptr'.
1507 *
1508 * We isolate the ifreq dependencies in here. The
1509 * ioctl really ought to take a netbuf and be of
1510 * type TRANSPARENT - one day.
1511 */
1512static int
1513ifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf)
1514{
1515 struct strioctl iocb;
1516 int rc;
1517 vnode_t *vp;
1518 struct ifreq ifr;
1519
1520 /*
1521 * Now do the one requested.
1522 */
1523 if (nbuf->len)
1524 ifr.ifr_addr = *(struct sockaddr *)nbuf->buf;
1525 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1526 iocb.ic_cmd = cmd;
1527 iocb.ic_timout = 0;
1528 iocb.ic_len = sizeof (ifr);
1529 iocb.ic_dp = (caddr_t)&ifr;
1530
1531 vp = tiptr->fp->f_vnode;
1532 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1533 if (rc) {
1534 nfs_perror(rc, "ifioctl: kstr_ioctl failed: %m\n");
1535 return (rc);
1536 }
1537
1538 /*
1539 * Set reply length.
1540 */
1541 if (nbuf->len == 0) {
1542 /*
1543 * GET type.
1544 */
1545 nbuf->len = sizeof (struct sockaddr);
1546 *(struct sockaddr *)nbuf->buf = ifr.ifr_addr;
1547 }
1548
1549 return (0);
1550}
1551
1552static int
1553setifflags(TIUSER *tiptr, uint_t value)
1554{
1555 struct ifreq ifr;
1556 int rc;
1557 struct strioctl iocb;
1558
1559 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1560 iocb.ic_cmd = SIOCGIFFLAGS;
1561 iocb.ic_timout = 0;
1562 iocb.ic_len = sizeof (ifr);
1563 iocb.ic_dp = (caddr_t)&ifr;
1564 if (rc = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb))
1565 return (rc);
1566
1567 ifr.ifr_flags |= value;
1568 iocb.ic_cmd = SIOCSIFFLAGS;
1569 return (kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb));
1570}
1571
1572/*
1573 * REVerse Address Resolution Protocol (revarp)
1574 * is used by a diskless client to find out its
1575 * IP address when all it knows is its Ethernet address.
1576 *
1577 * Open the ethernet driver, attach and bind
1578 * (DL_BIND_REQ) it, and then format a broadcast RARP
1579 * message for it to send. We pick up the reply and
1580 * let the caller set the interface address using SIOCSIFADDR.
1581 */
1582static int
1583revarp_myaddr(TIUSER *tiptr)
1584{
1585 int rc;
1586 dl_info_ack_t info;
1587 struct sockaddr_in sin;
1588 struct netbuf sbuf;
1589 ldi_handle_t lh;
1590 ldi_ident_t li;
1591 struct netbuf myaddr = {0, 0, NULL};
1592
1593 if (dldebug)
1594 printf("revarp_myaddr: entered\n");
1595
1596 if (rc = ldi_ident_from_mod(&modlinkage, &li)) {
1597 nfs_perror(rc,
1598 "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1599 return (rc);
1600 }
1601
1602 rc = ldi_open_by_name(ndev_path, FREAD|FWRITE, CRED(), &lh, li);
1603 ldi_ident_release(li);
1604 if (rc) {
1605 nfs_perror(rc,
1606 "revarp_myaddr: ldi_open_by_name failed: %m\n");
1607 return (rc);
1608 }
1609
yz147064d62bc4b2008-01-23 18:09:15 -08001610 if (rc = dl_attach(lh, ifunit, NULL)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001611 nfs_perror(rc, "revarp_myaddr: dl_attach failed: %m\n");
1612 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1613 return (rc);
1614 }
1615
yz147064d62bc4b2008-01-23 18:09:15 -08001616 if (rc = dl_bind(lh, ETHERTYPE_REVARP, NULL)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001617 nfs_perror(rc, "revarp_myaddr: dl_bind failed: %m\n");
1618 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1619 return (rc);
1620 }
1621
yz147064d62bc4b2008-01-23 18:09:15 -08001622 if (rc = dl_info(lh, &info, NULL, NULL, NULL)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001623 nfs_perror(rc, "revarp_myaddr: dl_info failed: %m\n");
1624 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1625 return (rc);
1626 }
1627
1628 /* Initialize myaddr */
1629 myaddr.maxlen = info.dl_addr_length;
1630 myaddr.buf = kmem_alloc(myaddr.maxlen, KM_SLEEP);
1631
1632 revarp_start(lh, &myaddr);
1633
1634 bcopy(myaddr.buf, &sin.sin_addr, myaddr.len);
1635 sin.sin_family = AF_INET;
1636
1637 sbuf.buf = (caddr_t)&sin;
1638 sbuf.maxlen = sbuf.len = sizeof (sin);
1639 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1640 nfs_perror(rc,
1641 "revarp_myaddr: couldn't set interface net address: %m\n");
1642 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1643 kmem_free(myaddr.buf, myaddr.maxlen);
1644 return (rc);
1645 }
1646
1647 /* Now turn on the interface */
1648 if (rc = setifflags(tiptr, IFF_UP)) {
1649 nfs_perror(rc,
1650 "revarp_myaddr: couldn't enable network interface: %m\n");
1651 }
1652
1653 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1654 kmem_free(myaddr.buf, myaddr.maxlen);
1655 return (rc);
1656}
1657
1658static void
1659revarp_start(ldi_handle_t lh, struct netbuf *myaddr)
1660{
1661 struct ether_arp *ea;
1662 int rc;
1663 dl_unitdata_req_t *dl_udata;
1664 mblk_t *bp;
1665 mblk_t *mp;
1666 struct dladdr *dlsap;
1667 static int done = 0;
yz147064d62bc4b2008-01-23 18:09:15 -08001668 size_t addrlen = ETHERADDRL;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001669
yz147064d62bc4b2008-01-23 18:09:15 -08001670 if (dl_phys_addr(lh, (uchar_t *)&myether, &addrlen, NULL) != 0 ||
1671 addrlen != ETHERADDRL) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001672 /* Fallback using per-node address */
1673 (void) localetheraddr((struct ether_addr *)NULL, &myether);
1674 cmn_err(CE_CONT, "?DLPI failed to get Ethernet address. Using "
johnlev843e1982007-09-18 15:46:43 -07001675 "system wide Ethernet address %s\n",
1676 ether_sprintf(&myether));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001677 }
1678
1679getreply:
1680 if (myaddr->len != 0) {
1681 cmn_err(CE_CONT, "?Found my IP address: %x (%d.%d.%d.%d)\n",
1682 *(int *)myaddr->buf,
1683 (uchar_t)myaddr->buf[0], (uchar_t)myaddr->buf[1],
1684 (uchar_t)myaddr->buf[2], (uchar_t)myaddr->buf[3]);
1685 return;
1686 }
1687
1688 if (done++ == 0)
1689 cmn_err(CE_CONT, "?Requesting Internet address for %s\n",
1690 ether_sprintf(&myether));
1691
1692 /*
1693 * Send another RARP request.
1694 */
1695 if ((mp = allocb(sizeof (dl_unitdata_req_t) + sizeof (*dlsap),
1696 BPRI_HI)) == NULL) {
1697 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1698 return;
1699 }
1700 if ((bp = allocb(sizeof (struct ether_arp), BPRI_HI)) == NULL) {
1701 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1702 return;
1703 }
1704
1705 /*
1706 * Format the transmit request part.
1707 */
1708 mp->b_datap->db_type = M_PROTO;
1709 dl_udata = (dl_unitdata_req_t *)mp->b_wptr;
1710 mp->b_wptr += sizeof (dl_unitdata_req_t) + sizeof (*dlsap);
1711 dl_udata->dl_primitive = DL_UNITDATA_REQ;
1712 dl_udata->dl_dest_addr_length = sizeof (*dlsap);
1713 dl_udata->dl_dest_addr_offset = sizeof (*dl_udata);
1714 dl_udata->dl_priority.dl_min = 0;
1715 dl_udata->dl_priority.dl_max = 0;
1716
1717 dlsap = (struct dladdr *)(mp->b_rptr + sizeof (*dl_udata));
1718 bcopy(&etherbroadcastaddr, &dlsap->dl_phys,
1719 sizeof (etherbroadcastaddr));
1720 dlsap->dl_sap = ETHERTYPE_REVARP;
1721
1722 /*
1723 * Format the actual REVARP request.
1724 */
1725 bzero(bp->b_wptr, sizeof (struct ether_arp));
1726 ea = (struct ether_arp *)bp->b_wptr;
1727 bp->b_wptr += sizeof (struct ether_arp);
1728 ea->arp_hrd = htons(ARPHRD_ETHER);
1729 ea->arp_pro = htons(ETHERTYPE_IP);
1730 ea->arp_hln = sizeof (ea->arp_sha); /* hardware address length */
1731 ea->arp_pln = sizeof (ea->arp_spa); /* protocol address length */
1732 ea->arp_op = htons(REVARP_REQUEST);
1733 ether_copy(&myether, &ea->arp_sha);
1734 ether_copy(&myether, &ea->arp_tha);
1735
1736 mp->b_cont = bp;
1737
1738 if ((rc = ldi_putmsg(lh, mp)) != 0) {
1739 nfs_perror(rc, "revarp_start: ldi_putmsg failed: %m\n");
1740 return;
1741 }
1742 revarpinput(lh, myaddr);
1743
1744 goto getreply;
1745}
1746
1747/*
1748 * Client side Reverse-ARP input
1749 * Server side is handled by user level server
1750 */
1751static void
1752revarpinput(ldi_handle_t lh, struct netbuf *myaddr)
1753{
1754 struct ether_arp *ea;
1755 mblk_t *bp;
1756 mblk_t *mp;
1757 int rc;
1758 timestruc_t tv, give_up, now;
1759
1760 /*
1761 * Choose the time at which we will give up, and resend our
1762 * request.
1763 */
1764 gethrestime(&give_up);
1765 give_up.tv_sec += REVARP_TIMEO;
1766wait:
1767 /*
1768 * Compute new timeout value.
1769 */
1770 tv = give_up;
1771 gethrestime(&now);
1772 timespecsub(&tv, &now);
1773 /*
1774 * If we don't have at least one full second remaining, give up.
1775 * This means we might wait only just over 4.0 seconds, but that's
1776 * okay.
1777 */
1778 if (tv.tv_sec <= 0)
1779 return;
1780 rc = ldi_getmsg(lh, &mp, &tv);
1781 if (rc == ETIME) {
1782 goto out;
1783 } else if (rc != 0) {
1784 nfs_perror(rc, "revarpinput: ldi_getmsg failed: %m\n");
1785 return;
1786 }
1787
1788 if (mp->b_cont == NULL) {
1789 printf("revarpinput: b_cont == NULL\n");
1790 goto out;
1791 }
1792
1793 if (mp->b_datap->db_type != M_PROTO) {
1794 printf("revarpinput: bad header type %d\n",
1795 mp->b_datap->db_type);
1796 goto out;
1797 }
1798
1799 bp = mp->b_cont;
1800
1801 if (bp->b_wptr - bp->b_rptr < sizeof (*ea)) {
1802 printf("revarpinput: bad data len %d, expect %d\n",
1803 (int)(bp->b_wptr - bp->b_rptr), (int)sizeof (*ea));
1804 goto out;
1805 }
1806
1807 ea = (struct ether_arp *)bp->b_rptr;
1808
1809 if ((ushort_t)ntohs(ea->arp_pro) != ETHERTYPE_IP) {
1810 /* We could have received another broadcast arp packet. */
1811 if (dldebug)
1812 printf("revarpinput: bad type %x\n",
1813 (ushort_t)ntohs(ea->arp_pro));
1814 freemsg(mp);
1815 goto wait;
1816 }
1817 if ((ushort_t)ntohs(ea->arp_op) != REVARP_REPLY) {
1818 /* We could have received a broadcast arp request. */
1819 if (dldebug)
1820 printf("revarpinput: bad op %x\n",
1821 (ushort_t)ntohs(ea->arp_op));
1822 freemsg(mp);
1823 goto wait;
1824 }
1825
1826 if (!ether_cmp(&ea->arp_tha, &myether)) {
1827 bcopy(&ea->arp_tpa, myaddr->buf, sizeof (ea->arp_tpa));
1828 myaddr->len = sizeof (ea->arp_tpa);
1829 } else {
1830 /* We could have gotten a broadcast arp response. */
1831 if (dldebug)
1832 printf("revarpinput: got reply, but not my address\n");
1833 freemsg(mp);
1834 goto wait;
1835 }
1836out:
1837 freemsg(mp);
1838}
1839
1840/*
1841 * From rpcsvc/mountxdr.c in SunOS. We can't
1842 * put this into the rpc directory because
1843 * it calls xdr_fhandle() which is in a
1844 * loadable module.
1845 */
1846static bool_t
1847myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp)
1848{
1849
1850 if (!xdr_int(xdrs, &fhsp->fhs_status))
1851 return (FALSE);
1852 if (fhsp->fhs_status == 0) {
1853 if (!myxdr_fhandle(xdrs, &fhsp->fhs_fh))
1854 return (FALSE);
1855 }
1856 return (TRUE);
1857}
1858
1859/*
1860 * From nfs_xdr.c.
1861 *
1862 * File access handle
1863 * The fhandle struct is treated a opaque data on the wire
1864 */
1865static bool_t
1866myxdr_fhandle(XDR *xdrs, fhandle_t *fh)
1867{
1868 return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
1869}
1870
1871static bool_t
1872myxdr_mountres3(XDR *xdrs, struct mountres3 *objp)
1873{
1874 if (!myxdr_mountstat3(xdrs, &objp->fhs_status))
1875 return (FALSE);
1876 switch (objp->fhs_status) {
1877 case MNT_OK:
1878 if (!myxdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
1879 return (FALSE);
1880 break;
1881 default:
1882 break;
1883 }
1884 return (TRUE);
1885}
1886
1887static bool_t
1888myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp)
1889{
1890 return (xdr_enum(xdrs, (enum_t *)objp));
1891}
1892
1893static bool_t
1894myxdr_mountres3_ok(XDR *xdrs, struct mountres3_ok *objp)
1895{
1896 if (!myxdr_fhandle3(xdrs, &objp->fhandle))
1897 return (FALSE);
1898 if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val,
johnlev843e1982007-09-18 15:46:43 -07001899 (uint_t *)&objp->auth_flavors.auth_flavors_len, ~0,
1900 sizeof (int), (xdrproc_t)xdr_int))
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001901 return (FALSE);
1902 return (TRUE);
1903}
1904
1905static bool_t
1906myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp)
1907{
1908 return (xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
1909 (uint_t *)&objp->fhandle3_len, FHSIZE3));
1910}
1911
1912/*
1913 * From SunOS pmap_clnt.c
1914 *
1915 * Port mapper routines:
1916 * pmap_kgetport() - get port number.
1917 * pmap_rmt_call() - indirect call via port mapper.
1918 *
1919 */
1920static enum clnt_stat
1921pmap_kgetport(struct knetconfig *knconf, struct netbuf *call_addr,
Toomas Soomef3de0dd2016-12-18 00:37:43 +02001922 rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001923{
1924 ushort_t port;
1925 int tries;
1926 enum clnt_stat stat;
1927 struct pmap pmap_parms;
1928 RPCB rpcb_parms;
1929 char *ua = NULL;
1930
1931 port = 0;
1932
1933 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
1934
1935 pmap_parms.pm_prog = prog;
1936 pmap_parms.pm_vers = vers;
1937 pmap_parms.pm_prot = prot;
1938 pmap_parms.pm_port = 0;
1939 for (tries = 0; tries < 5; tries++) {
1940 stat = mycallrpc(knconf, call_addr,
1941 PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
1942 myxdr_pmap, (char *)&pmap_parms,
1943 xdr_u_short, (char *)&port,
1944 DEFAULT_TIMEO, DEFAULT_RETRIES);
1945
1946 if (stat != RPC_TIMEDOUT)
1947 break;
1948 cmn_err(CE_WARN,
1949 "pmap_kgetport: Portmapper not responding; still trying");
1950 }
1951
1952 if (stat == RPC_PROGUNAVAIL) {
1953 cmn_err(CE_WARN,
1954 "pmap_kgetport: Portmapper failed - trying rpcbind");
1955
1956 rpcb_parms.r_prog = prog;
1957 rpcb_parms.r_vers = vers;
1958 rpcb_parms.r_netid = knconf->knc_proto;
1959 rpcb_parms.r_addr = rpcb_parms.r_owner = "";
1960
1961 for (tries = 0; tries < 5; tries++) {
1962 stat = mycallrpc(knconf, call_addr,
1963 RPCBPROG, RPCBVERS, RPCBPROC_GETADDR,
1964 xdr_rpcb, (char *)&rpcb_parms,
1965 xdr_wrapstring, (char *)&ua,
1966 DEFAULT_TIMEO, DEFAULT_RETRIES);
1967
1968 if (stat != RPC_TIMEDOUT)
1969 break;
1970 cmn_err(CE_WARN,
1971 "pmap_kgetport: rpcbind not responding; still trying");
1972 }
1973
1974 if (stat == RPC_SUCCESS) {
1975 if ((ua != NULL) && (ua[0] != NULL)) {
1976 port = rpc_uaddr2port(AF_INET, ua);
1977 } else {
1978 /* Address unknown */
1979 stat = RPC_PROGUNAVAIL;
1980 }
1981 }
1982 }
1983
1984 if (stat == RPC_SUCCESS)
1985 ((struct sockaddr_in *)call_addr->buf)->sin_port = ntohs(port);
1986
1987 return (stat);
1988}
1989
1990/*
1991 * pmapper remote-call-service interface.
1992 * This routine is used to call the pmapper remote call service
1993 * which will look up a service program in the port maps, and then
1994 * remotely call that routine with the given parameters. This allows
1995 * programs to do a lookup and call in one step. In addition to the call_addr,
1996 * the caller provides a boolean hint about the destination address (TRUE if
1997 * address is a broadcast address, FALSE otherwise).
1998 *
1999 * On return, `call addr' contains the port number for the
2000 * service requested, and `resp_addr' contains its IP address.
2001 */
2002static enum clnt_stat
2003pmap_rmt_call(struct knetconfig *knconf, struct netbuf *call_addr,
Toomas Soomef3de0dd2016-12-18 00:37:43 +02002004 bool_t bcast, rpcprog_t progn, rpcvers_t versn, rpcproc_t procn,
2005 xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
2006 struct timeval tout, struct netbuf *resp_addr)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002007{
2008 CLIENT *cl;
2009 enum clnt_stat stat;
2010 rpcport_t port;
2011 int rc;
2012 struct rmtcallargs pmap_args;
2013 struct rmtcallres pmap_res;
2014 struct rpcb_rmtcallargs rpcb_args;
2015 struct rpcb_rmtcallres rpcb_res;
2016 char ua[100]; /* XXX */
2017
2018 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
2019
2020 rc = clnt_tli_kcreate(knconf, call_addr, PMAPPROG, PMAPVERS,
2021 0, PMAP_RETRIES, CRED(), &cl);
2022 if (rc != 0) {
2023 nfs_perror(rc,
2024 "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2025 return (RPC_SYSTEMERROR); /* XXX */
2026 }
2027 if (cl == (CLIENT *)NULL) {
2028 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2029 /* NOTREACHED */
2030 }
2031
2032 (void) CLNT_CONTROL(cl, CLSET_BCAST, (char *)&bcast);
2033
2034 pmap_args.prog = progn;
2035 pmap_args.vers = versn;
2036 pmap_args.proc = procn;
2037 pmap_args.args_ptr = argsp;
2038 pmap_args.xdr_args = xdrargs;
2039 pmap_res.port_ptr = &port;
2040 pmap_res.results_ptr = resp;
2041 pmap_res.xdr_results = xdrres;
2042 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
2043 myxdr_rmtcall_args, (caddr_t)&pmap_args,
2044 myxdr_rmtcallres, (caddr_t)&pmap_res,
2045 tout, resp_addr);
2046
2047 if (stat == RPC_SUCCESS) {
2048 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2049 htons((ushort_t)port);
2050 }
2051 CLNT_DESTROY(cl);
2052
2053 if (stat != RPC_PROGUNAVAIL)
2054 return (stat);
2055
2056 cmn_err(CE_WARN, "pmap_rmt_call: Portmapper failed - trying rpcbind");
2057
2058 rc = clnt_tli_kcreate(knconf, call_addr, RPCBPROG, RPCBVERS,
2059 0, PMAP_RETRIES, CRED(), &cl);
2060 if (rc != 0) {
2061 nfs_perror(rc, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2062 return (RPC_SYSTEMERROR); /* XXX */
2063 }
2064
2065 if (cl == NULL) {
2066 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2067 /* NOTREACHED */
2068 }
2069
2070 rpcb_args.prog = progn;
2071 rpcb_args.vers = versn;
2072 rpcb_args.proc = procn;
2073 rpcb_args.args_ptr = argsp;
2074 rpcb_args.xdr_args = xdrargs;
2075 rpcb_res.addr_ptr = ua;
2076 rpcb_res.results_ptr = resp;
2077 rpcb_res.xdr_results = xdrres;
2078 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
2079 xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_args,
2080 xdr_rpcb_rmtcallres, (caddr_t)&rpcb_res,
2081 tout, resp_addr);
2082
2083 if (stat == RPC_SUCCESS)
2084 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2085 rpc_uaddr2port(AF_INET, ua);
2086 CLNT_DESTROY(cl);
2087
2088 return (stat);
2089}
2090
2091/*
2092 * XDR remote call arguments
2093 * written for XDR_ENCODE direction only
2094 */
2095static bool_t
2096myxdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
2097{
2098 uint_t lenposition;
2099 uint_t argposition;
2100 uint_t position;
2101
2102 if (xdr_rpcprog(xdrs, &(cap->prog)) &&
2103 xdr_rpcvers(xdrs, &(cap->vers)) &&
2104 xdr_rpcproc(xdrs, &(cap->proc))) {
2105 lenposition = XDR_GETPOS(xdrs);
2106 if (!xdr_u_int(xdrs, &cap->arglen))
2107 return (FALSE);
2108 argposition = XDR_GETPOS(xdrs);
2109 if (!(*(cap->xdr_args))(xdrs, cap->args_ptr))
2110 return (FALSE);
2111 position = XDR_GETPOS(xdrs);
2112 cap->arglen = (uint_t)position - (uint_t)argposition;
2113 XDR_SETPOS(xdrs, lenposition);
2114 if (!xdr_u_int(xdrs, &cap->arglen))
2115 return (FALSE);
2116 XDR_SETPOS(xdrs, position);
2117 return (TRUE);
2118 }
2119 return (FALSE);
2120}
2121
2122/*
2123 * XDR remote call results
2124 * written for XDR_DECODE direction only
2125 */
2126static bool_t
2127myxdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
2128{
2129 caddr_t port_ptr;
2130
2131 port_ptr = (caddr_t)crp->port_ptr;
2132 if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) &&
2133 xdr_u_int(xdrs, &crp->resultslen)) {
2134 crp->port_ptr = (rpcport_t *)port_ptr;
2135 return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
2136 }
2137 return (FALSE);
2138}
2139
2140static bool_t
2141myxdr_pmap(XDR *xdrs, struct pmap *regs)
2142{
2143 if (xdr_rpcprog(xdrs, &regs->pm_prog) &&
2144 xdr_rpcvers(xdrs, &regs->pm_vers) &&
2145 xdr_rpcprot(xdrs, &regs->pm_prot))
2146 return (xdr_rpcport(xdrs, &regs->pm_port));
2147
2148 return (FALSE);
2149}
2150
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002151/*
2152 * From SunOS callrpc.c
2153 */
2154static enum clnt_stat
2155mycallrpc(struct knetconfig *knconf, struct netbuf *call_addr,
Toomas Soomef3de0dd2016-12-18 00:37:43 +02002156 rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
2157 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out,
2158 int timeo, int retries)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002159{
2160 CLIENT *cl;
2161 struct timeval tv;
2162 enum clnt_stat cl_stat;
2163 int rc;
2164
2165 rc = clnt_tli_kcreate(knconf, call_addr, prognum, versnum,
2166 0, retries, CRED(), &cl);
2167 if (rc) {
2168 nfs_perror(rc, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2169 return (RPC_SYSTEMERROR); /* XXX */
2170 }
2171 tv.tv_sec = timeo;
2172 tv.tv_usec = 0;
2173 cl_stat = CLNT_CALL(cl, procnum, inproc, in, outproc, out, tv);
2174 AUTH_DESTROY(cl->cl_auth);
2175 CLNT_DESTROY(cl);
2176 return (cl_stat);
2177}
2178
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002179/*
johnlev843e1982007-09-18 15:46:43 -07002180 * Configure the 'default' interface based on existing boot properties.
2181 */
2182static int
2183bp_netconfig(void)
2184{
2185 char *str;
2186 struct in_addr my_ip, my_netmask, my_router, my_broadcast;
2187 struct sockaddr_in *sin;
2188 TIUSER *tiptr;
2189 int rc;
2190 struct rtentry rtentry;
2191
2192 my_ip.s_addr = my_netmask.s_addr = my_router.s_addr = 0;
2193
2194 /*
2195 * No way of getting this right now. Collude with dlifconfig()
2196 * to let the protocol stack choose.
2197 */
2198 my_broadcast.s_addr = INADDR_BROADCAST;
2199
2200 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2201 DDI_PROP_DONTPASS, BP_HOST_IP, &str) == DDI_SUCCESS) {
2202 if (inet_aton(str, (uchar_t *)&my_ip) != 0)
2203 cmn_err(CE_NOTE, "host-ip %s is invalid\n",
2204 str);
2205 ddi_prop_free(str);
2206 if (dldebug)
2207 printf("host ip is %s\n",
2208 inet_ntoa(my_ip));
2209 }
2210 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2211 DDI_PROP_DONTPASS, BP_SUBNET_MASK, &str) == DDI_SUCCESS) {
2212 if (inet_aton(str, (uchar_t *)&my_netmask) != 0)
2213 cmn_err(CE_NOTE, "subnet-mask %s is invalid\n",
2214 str);
2215 ddi_prop_free(str);
2216 if (dldebug)
2217 printf("subnet mask is %s\n",
2218 inet_ntoa(my_netmask));
2219 }
2220 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2221 DDI_PROP_DONTPASS, BP_ROUTER_IP, &str) == DDI_SUCCESS) {
2222 if (inet_aton(str, (uchar_t *)&my_router) != 0)
2223 cmn_err(CE_NOTE, "router-ip %s is invalid\n",
2224 str);
2225 ddi_prop_free(str);
2226 if (dldebug)
2227 printf("router ip is %s\n",
2228 inet_ntoa(my_router));
2229 }
2230 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2231 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c);
2232 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2233 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c);
2234 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2235 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) {
2236 (void) strlcpy(rootopts, str, sizeof (rootopts));
2237 ddi_prop_free(str);
2238 }
2239 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2240 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) {
2241 if (inet_aton(str, server_ip) != 0)
2242 cmn_err(CE_NOTE, "server-ip %s is invalid\n",
2243 str);
2244 ddi_prop_free(str);
2245 if (dldebug)
2246 printf("server ip is %s\n",
2247 inet_ntoa(*(struct in_addr *)server_ip));
2248 }
2249
2250 /*
2251 * We need all of these to configure based on properties.
2252 */
2253 if ((my_ip.s_addr == 0) ||
2254 (my_netmask.s_addr == 0) ||
2255 (server_path_c == NULL) ||
2256 (server_name_c == NULL) ||
2257 (*(uint_t *)server_ip == 0))
2258 return (-1);
2259
2260 cmn_err(CE_CONT, "?IP address: %s\n", inet_ntoa(my_ip));
2261 cmn_err(CE_CONT, "?IP netmask: %s\n", inet_ntoa(my_netmask));
2262 if (my_router.s_addr != 0)
2263 cmn_err(CE_CONT, "?IP router: %s\n", inet_ntoa(my_router));
2264 cmn_err(CE_CONT, "?NFS server: %s (%s)\n", server_name_c,
2265 inet_ntoa(*(struct in_addr *)server_ip));
2266 cmn_err(CE_CONT, "?NFS path: %s\n", server_path_c);
2267
2268 /*
2269 * Configure the interface.
2270 */
2271 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
2272 FREAD|FWRITE, &tiptr, CRED())) != 0) {
2273 nfs_perror(rc, "bp_netconfig: t_kopen udp failed: %m.\n");
2274 return (rc);
2275 }
2276
2277 if ((rc = dlifconfig(tiptr, &my_ip, &my_netmask, &my_broadcast,
2278 0)) < 0) {
2279 nfs_perror(rc, "bp_netconfig: dlifconfig failed: %m.\n");
2280 (void) t_kclose(tiptr, 0);
2281 return (rc);
2282 }
2283
2284 if (my_router.s_addr != 0) {
2285 /*
2286 * Add a default route.
2287 */
2288 sin = (struct sockaddr_in *)&rtentry.rt_dst;
2289 bzero(sin, sizeof (*sin));
2290 sin->sin_family = AF_INET;
2291
2292 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
2293 bzero(sin, sizeof (*sin));
2294 sin->sin_family = AF_INET;
2295 sin->sin_addr = my_router;
2296
2297 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
2298
2299 if ((rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) != 0) {
2300 nfs_perror(rc,
2301 "bp_netconfig: couldn't add route: %m.\n");
2302 (void) t_kclose(tiptr, 0);
2303 return (rc);
2304 }
2305 }
2306
2307 (void) t_kclose(tiptr, 0);
2308
2309 return (0);
2310}
2311
2312/*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002313 * The network device we will use to boot from is plumbed. Extract the details
2314 * from rootfs.
2315 */
2316static void
2317init_config(void)
2318{
2319 (void) strlcpy(ndev_path, rootfs.bo_devname, sizeof (ndev_path));
2320 (void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname));
2321 ifunit = rootfs.bo_ppa;
2322
2323 /*
2324 * Assumes only one linkage array element.
2325 */
2326 dl_udp_netconf.knc_rdev =
2327 makedevice(clone_major, ddi_name_to_major("udp"));
2328 dl_tcp_netconf.knc_rdev =
2329 makedevice(clone_major, ddi_name_to_major("tcp"));
2330
2331 /*
2332 * Now we bringup the interface.
2333 * Try cached dhcp response first. If it fails, do rarp.
2334 */
johnlev843e1982007-09-18 15:46:43 -07002335 if ((bp_netconfig() != 0) &&
2336 (dhcpinit() != 0) &&
2337 (whoami() != 0))
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002338 cmn_err(CE_WARN,
2339 "%s: no response from interface", ifname);
2340 else if (dldebug)
2341 printf("init_config: ifname %s is up\n", ifname);
2342}
2343
2344/*
2345 * These options are duplicated in cmd/fs.d/nfs/mount/mount.c
2346 * Changes must be made to both lists.
2347 */
2348static char *optlist[] = {
2349#define OPT_RO 0
2350 MNTOPT_RO,
2351#define OPT_RW 1
2352 MNTOPT_RW,
2353#define OPT_QUOTA 2
2354 MNTOPT_QUOTA,
2355#define OPT_NOQUOTA 3
2356 MNTOPT_NOQUOTA,
2357#define OPT_SOFT 4
2358 MNTOPT_SOFT,
2359#define OPT_HARD 5
2360 MNTOPT_HARD,
2361#define OPT_SUID 6
2362 MNTOPT_SUID,
2363#define OPT_NOSUID 7
2364 MNTOPT_NOSUID,
2365#define OPT_GRPID 8
2366 MNTOPT_GRPID,
2367#define OPT_REMOUNT 9
2368 MNTOPT_REMOUNT,
2369#define OPT_NOSUB 10
2370 MNTOPT_NOSUB,
2371#define OPT_INTR 11
2372 MNTOPT_INTR,
2373#define OPT_NOINTR 12
2374 MNTOPT_NOINTR,
2375#define OPT_PORT 13
2376 MNTOPT_PORT,
2377#define OPT_SECURE 14
2378 MNTOPT_SECURE,
2379#define OPT_RSIZE 15
2380 MNTOPT_RSIZE,
2381#define OPT_WSIZE 16
2382 MNTOPT_WSIZE,
2383#define OPT_TIMEO 17
2384 MNTOPT_TIMEO,
2385#define OPT_RETRANS 18
2386 MNTOPT_RETRANS,
2387#define OPT_ACTIMEO 19
2388 MNTOPT_ACTIMEO,
2389#define OPT_ACREGMIN 20
2390 MNTOPT_ACREGMIN,
2391#define OPT_ACREGMAX 21
2392 MNTOPT_ACREGMAX,
2393#define OPT_ACDIRMIN 22
2394 MNTOPT_ACDIRMIN,
2395#define OPT_ACDIRMAX 23
2396 MNTOPT_ACDIRMAX,
2397#define OPT_BG 24
2398 MNTOPT_BG,
2399#define OPT_FG 25
2400 MNTOPT_FG,
2401#define OPT_RETRY 26
2402 MNTOPT_RETRY,
2403#define OPT_NOAC 27
2404 MNTOPT_NOAC,
2405#define OPT_NOCTO 28
2406 MNTOPT_NOCTO,
2407#define OPT_LLOCK 29
2408 MNTOPT_LLOCK,
2409#define OPT_POSIX 30
2410 MNTOPT_POSIX,
2411#define OPT_VERS 31
2412 MNTOPT_VERS,
2413#define OPT_PROTO 32
2414 MNTOPT_PROTO,
2415#define OPT_SEMISOFT 33
2416 MNTOPT_SEMISOFT,
2417#define OPT_NOPRINT 34
2418 MNTOPT_NOPRINT,
2419#define OPT_SEC 35
2420 MNTOPT_SEC,
2421#define OPT_LARGEFILES 36
2422 MNTOPT_LARGEFILES,
2423#define OPT_NOLARGEFILES 37
2424 MNTOPT_NOLARGEFILES,
2425#define OPT_PUBLIC 38
2426 MNTOPT_PUBLIC,
2427#define OPT_DIRECTIO 39
2428 MNTOPT_FORCEDIRECTIO,
2429#define OPT_NODIRECTIO 40
2430 MNTOPT_NOFORCEDIRECTIO,
2431#define OPT_XATTR 41
2432 MNTOPT_XATTR,
2433#define OPT_NOXATTR 42
2434 MNTOPT_NOXATTR,
2435#define OPT_DEVICES 43
2436 MNTOPT_DEVICES,
2437#define OPT_NODEVICES 44
2438 MNTOPT_NODEVICES,
2439#define OPT_SETUID 45
2440 MNTOPT_SETUID,
2441#define OPT_NOSETUID 46
2442 MNTOPT_NOSETUID,
2443#define OPT_EXEC 47
2444 MNTOPT_EXEC,
2445#define OPT_NOEXEC 48
2446 MNTOPT_NOEXEC,
2447 NULL
2448};
2449
2450static int
2451isdigit(int ch)
2452{
2453 return (ch >= '0' && ch <= '9');
2454}
2455
2456#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2457#define bad(val) (val == NULL || !isdigit(*val))
2458
2459static int
2460atoi(const char *p)
2461{
2462 int n;
2463 int c, neg = 0;
2464
2465 if (!isdigit(c = *p)) {
2466 while (isspace(c))
2467 c = *++p;
2468 switch (c) {
2469 case '-':
2470 neg++;
2471 /* FALLTHROUGH */
2472 case '+':
2473 c = *++p;
2474 }
2475 if (!isdigit(c))
2476 return (0);
2477 }
2478 for (n = '0' - c; isdigit(c = *++p); ) {
2479 n *= 10; /* two steps to avoid unnecessary overflow */
2480 n += '0' - c; /* accum neg to avoid surprises at MAX */
2481 }
2482 return (neg ? n : -n);
2483}
2484
2485/*
2486 * Default root read tsize XXX
2487 */
2488int nfs_root_rsize = 8 * 1024; /* conservative for dumb NICs */
2489int nfs4_root_rsize = 32 * 1024; /* only runs on TCP be aggressive */
2490
2491/*
2492 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2493 */
2494int nfs_rootopts = NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT;
2495
2496static int
2497init_mountopts(struct nfs_args *args, int version, struct knetconfig **dl_cf,
Toomas Soomef3de0dd2016-12-18 00:37:43 +02002498 int *vfsflags)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002499{
2500 char servername[SYS_NMLN];
2501 static int first = 0;
2502 struct netbuf server_address;
2503 char *opts, *val;
2504 int vers;
2505 struct knetconfig *cf = *dl_cf;
2506 char rootoptsbuf[256];
2507
2508 /*
2509 * Set default mount options
2510 */
2511 args->flags = nfs_rootopts;
2512 args->rsize = 0;
2513 args->flags |= NFSMNT_ACREGMIN;
2514 args->acregmin = ACMINMAX;
2515 args->flags |= NFSMNT_ACREGMAX;
2516 args->acregmax = ACMAXMAX;
2517 args->flags |= NFSMNT_ACDIRMIN;
2518 args->acdirmin = ACMINMAX;
2519 args->flags |= NFSMNT_ACDIRMAX;
2520 args->acdirmax = ACMAXMAX;
2521
2522 *vfsflags = 0;
2523
2524 /*
2525 * Only look up the rootopts the first time, we store this in
2526 * a static buffer but we are guaranteed to be single threaded
2527 * and not reentrant.
2528 */
2529 if (first == 0) {
2530 first++;
2531
2532 init_netbuf(&server_address);
2533
2534 if (getfile("rootopts", servername, &server_address,
2535 rootopts)) {
2536 rootopts[0] = '\0';
2537 free_netbuf(&server_address);
2538 goto sanity;
2539 }
2540 free_netbuf(&server_address);
2541 }
2542
2543 if (dldebug)
2544 printf("rootopts = %s\n", rootopts);
2545
2546 /*
2547 * We have to preserve rootopts for second time.
2548 */
2549 (void) strncpy(rootoptsbuf, rootopts, sizeof (rootoptsbuf));
2550 rootoptsbuf[sizeof (rootoptsbuf) - 1] = '\0';
2551 opts = rootoptsbuf;
2552 while (*opts) {
2553 int opt;
2554
2555 switch (opt = getsubopt(&opts, optlist, &val)) {
2556 /*
2557 * Options that are defaults or meaningless so ignored
2558 */
2559 case OPT_QUOTA:
2560 case OPT_NOQUOTA:
2561 case OPT_SUID:
2562 case OPT_DEVICES:
2563 case OPT_SETUID:
2564 case OPT_BG:
2565 case OPT_FG:
2566 case OPT_RETRY:
2567 case OPT_POSIX:
2568 case OPT_LARGEFILES:
2569 case OPT_XATTR:
2570 case OPT_NOXATTR:
2571 case OPT_EXEC:
2572 break;
2573 case OPT_RO:
2574 *vfsflags |= MS_RDONLY;
2575 break;
2576 case OPT_RW:
2577 *vfsflags &= ~(MS_RDONLY);
2578 break;
2579 case OPT_SOFT:
2580 args->flags |= NFSMNT_SOFT;
2581 args->flags &= ~(NFSMNT_SEMISOFT);
2582 break;
2583 case OPT_SEMISOFT:
2584 args->flags |= NFSMNT_SOFT;
2585 args->flags |= NFSMNT_SEMISOFT;
2586 break;
2587 case OPT_HARD:
2588 args->flags &= ~(NFSMNT_SOFT);
2589 args->flags &= ~(NFSMNT_SEMISOFT);
2590 break;
2591 case OPT_NOSUID:
2592 case OPT_NODEVICES:
2593 case OPT_NOSETUID:
2594 case OPT_NOEXEC:
2595 cmn_err(CE_WARN,
2596 "nfs_dlboot: may not set root partition %s",
2597 optlist[opt]);
2598 break;
2599 case OPT_GRPID:
2600 args->flags |= NFSMNT_GRPID;
2601 break;
2602 case OPT_REMOUNT:
2603 cmn_err(CE_WARN,
2604 "nfs_dlboot: may not remount root partition");
2605 break;
2606 case OPT_INTR:
2607 args->flags |= NFSMNT_INT;
2608 break;
2609 case OPT_NOINTR:
2610 args->flags &= ~(NFSMNT_INT);
2611 break;
2612 case OPT_NOAC:
2613 args->flags |= NFSMNT_NOAC;
2614 break;
2615 case OPT_PORT:
2616 cmn_err(CE_WARN,
2617 "nfs_dlboot: may not change root port number");
2618 break;
2619 case OPT_SECURE:
2620 cmn_err(CE_WARN,
2621 "nfs_dlboot: root mounted auth_unix, secure ignored");
2622 break;
2623 case OPT_NOCTO:
2624 args->flags |= NFSMNT_NOCTO;
2625 break;
2626 case OPT_RSIZE:
2627 if (bad(val)) {
2628 cmn_err(CE_WARN,
2629 "nfs_dlboot: invalid option: rsize");
2630 break;
2631 }
2632 args->flags |= NFSMNT_RSIZE;
2633 args->rsize = atoi(val);
2634 break;
2635 case OPT_WSIZE:
2636 if (bad(val)) {
2637 cmn_err(CE_WARN,
2638 "nfs_dlboot: invalid option: wsize");
2639 break;
2640 }
2641 args->flags |= NFSMNT_WSIZE;
2642 args->wsize = atoi(val);