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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright (c) 2018, Joyent, Inc.
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/systm.h>
36 #include <sys/stream.h>
37 #include <sys/strsubr.h>
38 #include <sys/stropts.h>
39 #include <sys/strsun.h>
40 #include <sys/debug.h>
41 #include <sys/tiuser.h>
42 #include <sys/sockio.h>
43 #include <sys/socket.h>
44 #include <sys/t_kuser.h>
45 #include <sys/utsname.h>
46 #include <sys/systeminfo.h>
47 #include <sys/netconfig.h>
48 #include <sys/ethernet.h>
51 #include <sys/sysmacros.h>
52 #include <sys/bootconf.h>
53 #include <sys/bootprops.h>
54 #include <sys/cmn_err.h>
55 #include <sys/promif.h>
56 #include <sys/mount.h>
59 #include <net/route.h>
61 #include <netinet/in.h>
62 #include <netinet/arp.h>
63 #include <netinet/dhcp.h>
64 #include <netinet/inetutil.h>
65 #include <dhcp_impl.h>
66 #include <sys/sunos_dhcp_class.h>
68 #include <rpc/types.h>
73 #include <rpc/pmap_clnt.h>
74 #include <rpc/pmap_rmt.h>
75 #include <rpc/pmap_prot.h>
76 #include <rpc/bootparam.h>
77 #include <rpc/rpcb_prot.h>
81 #include <nfs/nfs_clnt.h>
82 #include <nfs/mount.h>
83 #include <sys/mntent.h>
86 #include <sys/sunddi.h>
87 #include <sys/sunldi.h>
88 #include <sys/esunddi.h>
90 #include <sys/errno.h>
91 #include <sys/modctl.h>
94 * RPC timers and retries
96 #define PMAP_RETRIES 5
97 #define DEFAULT_RETRIES 3
98 #define GETFILE_RETRIES 2
100 #define DEFAULT_TIMEO 3
101 #define WHOAMI_TIMEO 20
102 #define REVARP_TIMEO 5
103 #define GETFILE_TIMEO 1
106 * These are from the rpcgen'd version of mount.h XXX
108 #define MOUNTPROG 100005
109 #define MOUNTPROC_MNT 1
111 #define MOUNTVERS_POSIX 2
134 MNT3ERR_NAMETOOLONG
= 63,
135 MNT3ERR_NOTSUPP
= 10004,
136 MNT3ERR_SERVERFAULT
= 10006
139 struct mountres3_ok
{
140 struct fhandle3 fhandle
;
142 uint_t auth_flavors_len
;
143 int *auth_flavors_val
;
148 enum mountstat3 fhs_status
;
150 struct mountres3_ok mountinfo
;
155 * DLPI address format.
162 static struct modlmisc modlmisc
= {
163 &mod_miscops
, "Boot diskless"
166 static struct modlinkage modlinkage
= {
167 MODREV_1
, (void *)&modlmisc
, NULL
175 return (mod_install(&modlinkage
));
181 return (mod_remove(&modlinkage
));
185 _info(struct modinfo
*modinfop
)
187 return (mod_info(&modlinkage
, modinfop
));
191 static enum clnt_stat
pmap_rmt_call(struct knetconfig
*, struct netbuf
*,
192 bool_t
, rpcprog_t
, rpcvers_t
, rpcproc_t
, xdrproc_t
,
193 caddr_t
, xdrproc_t
, caddr_t
, struct timeval
,
195 static bool_t
myxdr_rmtcall_args(XDR
*, struct rmtcallargs
*);
196 static bool_t
myxdr_rmtcallres(XDR
*, struct rmtcallres
*);
197 static bool_t
myxdr_pmap(XDR
*, struct pmap
*);
198 static bool_t
myxdr_fhstatus(XDR
*xdrs
, struct fhstatus
*fhsp
);
199 static bool_t
myxdr_fhandle(XDR
*xdrs
, fhandle_t
*fh
);
200 static bool_t
myxdr_mountres3(XDR
*xdrs
, struct mountres3
*objp
);
201 static bool_t
myxdr_mountstat3(XDR
*xdrs
, enum mountstat3
*objp
);
202 static bool_t
myxdr_mountres3_ok(XDR
*xdrs
,
203 struct mountres3_ok
*objp
);
204 static bool_t
myxdr_fhandle3(XDR
*xdrs
, struct fhandle3
*objp
);
205 static enum clnt_stat
pmap_kgetport(struct knetconfig
*, struct netbuf
*,
206 rpcprog_t
, rpcvers_t
, rpcprot_t
);
207 static enum clnt_stat
mycallrpc(struct knetconfig
*, struct netbuf
*,
208 rpcprog_t
, rpcvers_t
, rpcproc_t
, xdrproc_t
,
209 char *, xdrproc_t
, char *, int, int);
210 static int ifioctl(TIUSER
*, int, struct netbuf
*);
211 static int getfile(char *, char *, struct netbuf
*, char *);
212 static int ping_prog(struct netbuf
*, uint_t prog
, uint_t vers
,
213 int proto
, enum clnt_stat
*);
214 static int mountnfs(struct netbuf
*, char *, char *,
216 static int mountnfs3(struct netbuf
*, char *, char *,
218 static int init_mountopts(struct nfs_args
*, int,
219 struct knetconfig
**, int *);
220 static int revarp_myaddr(TIUSER
*);
221 static void revarp_start(ldi_handle_t
, struct netbuf
*);
222 static void revarpinput(ldi_handle_t
, struct netbuf
*);
223 static void init_netbuf(struct netbuf
*);
224 static void free_netbuf(struct netbuf
*);
225 static int rtioctl(TIUSER
*, int, struct rtentry
*);
226 static void init_config(void);
228 static void cacheinit(void);
229 static int cacheinfo(char *, int, struct netbuf
*, char *, int);
230 static int dlifconfig(TIUSER
*, struct in_addr
*, struct in_addr
*,
231 struct in_addr
*, uint_t
);
232 static int setifflags(TIUSER
*, uint_t
);
234 static char *inet_ntoa(struct in_addr
);
235 static int inet_aton(char *, uchar_t
*);
236 static int isdigit(int);
239 * Should be in some common
240 * ethernet source file.
242 static struct ether_addr etherbroadcastaddr
= {
243 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
246 static struct ether_addr myether
;
249 * "ifname" is the interface name/unit as read from the boot
251 * "ndev" is the major device number of the network interface
253 * "ifunit" it the physical point of attachment for the network
254 * interface used to boot from.
256 * Both of these are initialized in "init_config()".
259 static char ifname
[IFNAMSIZ
];
260 static char ndev_path
[MAXPATHLEN
];
264 * XXX these should be shared
266 static struct knetconfig dl_udp_netconf
= {
267 NC_TPI_CLTS
, /* semantics */
268 NC_INET
, /* family */
269 NC_UDP
, /* protocol */
273 static struct knetconfig dl_tcp_netconf
= {
274 NC_TPI_COTS
, /* semantics */
275 NC_INET
, /* family */
276 NC_TCP
, /* protocol */
280 /* parameters from DHCP or bootparamd */
281 static PKT_LIST
*pl
= NULL
;
282 static uchar_t server_ip
[4];
283 static uchar_t dhcp_server_ip
[4];
284 static char *server_name_c
, *server_path_c
;
285 static char rootopts
[256];
288 * XXX Until we get the nfsmapid deadlocks all fixed, don't allow
289 * XXX a v4 root mount.
291 int nfs4_no_diskless_root_support
= 1;
294 mount_root(char *name
, char *path
, int version
, struct nfs_args
*args
,
299 struct knetconfig
*dl_cf
;
300 static int init_done
= 0;
304 printf("mount_root: name=%s\n", name
);
306 if (init_done
== 0) {
311 init_netbuf(args
->addr
);
314 rc
= getfile(name
, args
->hostname
, args
->addr
, path
);
315 } while (rc
== ETIMEDOUT
);
318 free_netbuf(args
->addr
);
322 ASSERT(args
->knconf
->knc_protofmly
!= NULL
);
323 ASSERT(args
->knconf
->knc_proto
!= NULL
);
327 rc
= mountnfs(args
->addr
, args
->hostname
, path
,
328 (fhandle_t
*)args
->fh
, &proto
);
331 rc
= mountnfs3(args
->addr
, args
->hostname
, path
,
332 (nfs_fh3
*)args
->fh
, &proto
);
335 ((struct sockaddr_in
*)args
->addr
->buf
)->sin_port
=
337 if (ping_prog(args
->addr
, NFS_PROGRAM
, NFS_V4
, IPPROTO_TCP
,
343 case RPC_PROGVERSMISMATCH
:
346 * Common failures if v4 unsupported or no TCP
348 rc
= EPROTONOSUPPORT
;
354 if (nfs4_no_diskless_root_support
)
355 rc
= EPROTONOSUPPORT
;
358 rc
= EPROTONOSUPPORT
;
367 dl_cf
= &dl_tcp_netconf
;
371 dl_cf
= &dl_udp_netconf
;
375 rc
= init_mountopts(args
, version
, &dl_cf
, vfsflags
);
378 * Copy knetconfig information from the template, note that the
379 * rdev field has been set by init_config above.
381 args
->knconf
->knc_semantics
= dl_cf
->knc_semantics
;
382 args
->knconf
->knc_rdev
= dl_cf
->knc_rdev
;
383 (void) strcpy(args
->knconf
->knc_protofmly
, dl_cf
->knc_protofmly
);
384 (void) strcpy(args
->knconf
->knc_proto
, dl_cf
->knc_proto
);
389 nfs_perror(rc
, "mount_root: mount %s:%s failed: %m\n",
390 args
->hostname
, path
);
392 printf("mount_root: leaving\n");
399 * Call mount daemon on server `sa' to mount path.
400 * `port' is set to nfs port and fh is the fhandle
401 * returned from the server.
404 mountnfs(struct netbuf
*sa
, char *server
,
405 char *path
, fhandle_t
*fh
, int *proto
)
411 printf("mountnfs: entered\n");
414 * Get the port number for the mount program.
415 * pmap_kgetport first tries a SunOS portmapper
416 * and, if no reply is received, will try a
417 * SVR4 rpcbind. Either way, `sa' is set to
418 * the correct address.
421 stat
= pmap_kgetport(&dl_udp_netconf
, sa
, (rpcprog_t
)MOUNTPROG
,
422 (rpcvers_t
)MOUNTVERS
, (rpcprot_t
)IPPROTO_UDP
);
424 if (stat
== RPC_TIMEDOUT
) {
426 "mountnfs: %s:%s portmap not responding",
428 } else if (stat
!= RPC_SUCCESS
) {
430 "mountnfs: pmap_kgetport RPC error %d (%s).",
431 stat
, clnt_sperrno(stat
));
432 return (ENXIO
); /* XXX */
434 } while (stat
== RPC_TIMEDOUT
);
437 * The correct port number has been
438 * put into `sa' by pmap_kgetport().
441 stat
= mycallrpc(&dl_udp_netconf
, sa
, (rpcprog_t
)MOUNTPROG
,
442 (rpcvers_t
)MOUNTVERS
, (rpcproc_t
)MOUNTPROC_MNT
,
443 xdr_bp_path_t
, (char *)&path
,
444 myxdr_fhstatus
, (char *)&fhs
,
445 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
446 if (stat
== RPC_TIMEDOUT
) {
448 "mountnfs: %s:%s mount server not responding",
451 } while (stat
== RPC_TIMEDOUT
);
453 if (stat
!= RPC_SUCCESS
) {
454 cmn_err(CE_WARN
, "mountnfs: RPC failed: error %d (%s).",
455 stat
, clnt_sperrno(stat
));
456 return (ENXIO
); /* XXX */
459 ((struct sockaddr_in
*)sa
->buf
)->sin_port
= htons(NFS_PORT
);
462 if (fhs
.fhs_status
!= 0) {
464 printf("mountnfs: fhs_status %d\n", fhs
.fhs_status
);
465 return (ENXIO
); /* XXX */
468 *proto
= IPPROTO_UDP
;
470 if (ping_prog(sa
, NFS_PROGRAM
, NFS_VERSION
, IPPROTO_TCP
, NULL
))
471 *proto
= IPPROTO_TCP
;
474 printf("mountnfs: leaving\n");
479 * Call mount daemon on server `sa' to mount path.
480 * `port' is set to nfs port and fh is the fhandle
481 * returned from the server.
484 mountnfs3(struct netbuf
*sa
, char *server
, char *path
, nfs_fh3
*fh
, int *proto
)
486 struct mountres3 mountres3
;
491 printf("mountnfs3: entered\n");
494 * Get the port number for the mount program.
495 * pmap_kgetport first tries a SunOS portmapper
496 * and, if no reply is received, will try a
497 * SVR4 rpcbind. Either way, `sa' is set to
498 * the correct address.
501 stat
= pmap_kgetport(&dl_udp_netconf
, sa
, (rpcprog_t
)MOUNTPROG
,
502 (rpcvers_t
)MOUNTVERS3
, (rpcprot_t
)IPPROTO_UDP
);
504 if (stat
== RPC_PROGVERSMISMATCH
) {
506 printf("mountnfs3: program/version mismatch\n");
507 return (EPROTONOSUPPORT
); /* XXX */
508 } else if (stat
== RPC_TIMEDOUT
) {
510 "mountnfs3: %s:%s portmap not responding",
512 } else if (stat
!= RPC_SUCCESS
) {
514 "mountnfs3: pmap_kgetport RPC error %d (%s).",
515 stat
, clnt_sperrno(stat
));
516 return (ENXIO
); /* XXX */
518 } while (stat
== RPC_TIMEDOUT
);
520 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
= NULL
;
521 mountres3
.mountres3_u
.mountinfo
.auth_flavors
.auth_flavors_val
= NULL
;
524 * The correct port number has been
525 * put into `sa' by pmap_kgetport().
528 stat
= mycallrpc(&dl_udp_netconf
, sa
, (rpcprog_t
)MOUNTPROG
,
529 (rpcvers_t
)MOUNTVERS3
, (rpcproc_t
)MOUNTPROC_MNT
,
530 xdr_bp_path_t
, (char *)&path
,
531 myxdr_mountres3
, (char *)&mountres3
,
532 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
533 if (stat
== RPC_TIMEDOUT
) {
535 "mountnfs3: %s:%s mount server not responding",
538 } while (stat
== RPC_TIMEDOUT
);
540 if (stat
== RPC_PROGVERSMISMATCH
) {
542 printf("mountnfs3: program/version mismatch\n");
543 ret
= EPROTONOSUPPORT
;
546 if (stat
!= RPC_SUCCESS
) {
547 cmn_err(CE_WARN
, "mountnfs3: RPC failed: error %d (%s).",
548 stat
, clnt_sperrno(stat
));
549 ret
= ENXIO
; /* XXX */
553 if (mountres3
.fhs_status
!= MNT_OK
) {
555 printf("mountnfs3: fhs_status %d\n",
556 mountres3
.fhs_status
);
557 ret
= ENXIO
; /* XXX */
561 ((struct sockaddr_in
*)sa
->buf
)->sin_port
= htons(NFS_PORT
);
563 *proto
= IPPROTO_UDP
;
565 if (ping_prog(sa
, NFS_PROGRAM
, NFS_V3
, IPPROTO_TCP
, NULL
)) {
566 *proto
= IPPROTO_TCP
;
569 fh
->fh3_length
= mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_len
;
570 bcopy(mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
,
571 fh
->fh3_u
.data
, fh
->fh3_length
);
574 xdr_free(myxdr_mountres3
, (caddr_t
)&mountres3
);
577 printf("mountnfs3: leaving\n");
582 ping_prog(struct netbuf
*call_addr
, uint_t prog
, uint_t vers
, int proto
,
583 enum clnt_stat
*statp
)
585 struct knetconfig
*knconf
;
587 int retries
= DEFAULT_RETRIES
;
591 knconf
= &dl_tcp_netconf
;
594 knconf
= &dl_udp_netconf
;
601 stat
= mycallrpc(knconf
, call_addr
, prog
, vers
, NULLPROC
,
602 xdr_void
, NULL
, xdr_void
, NULL
,
603 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
606 printf("ping_prog: %d return %d (%s)\n", proto
, stat
,
609 * Special case for TCP, it may "timeout" because it failed
610 * to establish an initial connection but it doesn't
611 * actually retry, so we do the retry.
612 * Persistence pays in diskless.
614 } while (stat
== RPC_TIMEDOUT
&& proto
== IPPROTO_TCP
&& retries
--);
619 if (stat
!= RPC_SUCCESS
)
624 static struct netbuf bootparam_addr
;
627 * Returns after filling in the following global variables:
638 struct bp_whoami_arg arg
;
639 struct bp_whoami_res res
;
644 int printed_waiting_msg
;
646 if ((rc
= t_kopen((file_t
*)NULL
, dl_udp_netconf
.knc_rdev
,
647 FREAD
|FWRITE
, &tiptr
, CRED())) != 0) {
648 nfs_perror(rc
, "whoami: t_kopen udp failed: %m.\n");
652 * Find out our local (IP) address.
654 if (rc
= revarp_myaddr(tiptr
)) {
655 nfs_perror(rc
, "whoami: revarp_myaddr failed: %m.\n");
656 (void) t_kclose(tiptr
, 0);
660 /* explicitly use the limited broadcast address */
662 ((struct sockaddr_in
*)sa
.buf
)->sin_family
= AF_INET
;
663 ((struct sockaddr_in
*)sa
.buf
)->sin_addr
.s_addr
=
664 htonl(INADDR_BROADCAST
);
665 sa
.len
= sizeof (struct sockaddr_in
);
668 * Pick up our local (IP) address.
671 if (rc
= ifioctl(tiptr
, SIOCGIFADDR
, &req
)) {
673 "whoami: couldn't get my IP address: %m.\n");
676 (void) t_kclose(tiptr
, 0);
681 * Set up the arguments expected by bootparamd.
683 arg
.client_address
.address_type
= IP_ADDR_TYPE
;
684 bcopy(&((struct sockaddr_in
*)req
.buf
)->sin_addr
,
685 &arg
.client_address
.bp_address
.ip_addr
, sizeof (struct in_addr
));
689 init_netbuf(&bootparam_addr
);
692 * Initial retransmission interval
694 tv
.tv_sec
= DEFAULT_TIMEO
;
696 res
.client_name
= kmem_alloc(MAX_MACHINE_NAME
+ 1, KM_SLEEP
);
697 res
.domain_name
= kmem_alloc(MAX_MACHINE_NAME
+ 1, KM_SLEEP
);
700 * Do a broadcast call to find a bootparam daemon that
701 * will tell us our hostname, domainname and any
702 * router that we have to use to talk to our NFS server.
704 printed_waiting_msg
= 0;
707 * pmap_rmt_call will first try the SunOS portmapper
708 * and if no reply is received will then try the SVR4
710 * Either way, `bootparam_addr' will be set to the
711 * correct address for the bootparamd that responds.
713 stat
= pmap_rmt_call(&dl_udp_netconf
, &sa
, TRUE
, BOOTPARAMPROG
,
714 BOOTPARAMVERS
, BOOTPARAMPROC_WHOAMI
,
715 xdr_bp_whoami_arg
, (caddr_t
)&arg
,
716 xdr_bp_whoami_res
, (caddr_t
)&res
,
717 tv
, &bootparam_addr
);
718 if (stat
== RPC_TIMEDOUT
&& !printed_waiting_msg
) {
720 "No bootparam server responding; still trying");
721 printed_waiting_msg
= 1;
724 * Retransmission interval for second and subsequent tries.
725 * We expect first pmap_rmt_call to retransmit and backoff to
726 * at least this value.
728 tv
.tv_sec
= WHOAMI_TIMEO
;
730 } while (stat
== RPC_TIMEDOUT
);
732 if (printed_waiting_msg
)
733 printf("Bootparam response received\n");
735 if (stat
!= RPC_SUCCESS
) {
736 /* XXX should get real error here */
739 "whoami: bootparam RPC failed: error %d (%s).",
740 stat
, clnt_sperrno(stat
));
744 namelen
= strlen(res
.client_name
);
745 if (namelen
> sizeof (utsname
.nodename
)) {
746 printf("whoami: hostname too long");
751 bcopy(res
.client_name
, &utsname
.nodename
, namelen
);
752 cmn_err(CE_CONT
, "?hostname: %s\n", utsname
.nodename
);
754 printf("whoami: no host name\n");
759 namelen
= strlen(res
.domain_name
);
761 if (namelen
> SYS_NMLN
) {
762 printf("whoami: domainname too long");
766 bcopy(res
.domain_name
, &srpc_domain
, namelen
);
767 cmn_err(CE_CONT
, "?domainname: %s\n", srpc_domain
);
769 printf("whoami: no domain name\n");
772 if (res
.router_address
.address_type
== IP_ADDR_TYPE
) {
773 struct rtentry rtentry
;
774 struct sockaddr_in
*sin
;
775 struct in_addr ipaddr
;
777 bcopy(&res
.router_address
.bp_address
.ip_addr
, &ipaddr
,
778 sizeof (struct in_addr
));
780 if (ipaddr
.s_addr
!= 0) {
781 sin
= (struct sockaddr_in
*)&rtentry
.rt_dst
;
782 bzero(sin
, sizeof (*sin
));
783 sin
->sin_family
= AF_INET
;
785 sin
= (struct sockaddr_in
*)&rtentry
.rt_gateway
;
786 bzero(sin
, sizeof (*sin
));
787 sin
->sin_family
= AF_INET
;
788 sin
->sin_addr
.s_addr
= ipaddr
.s_addr
;
790 rtentry
.rt_flags
= RTF_GATEWAY
| RTF_UP
;
792 if (rc
= rtioctl(tiptr
, SIOCADDRT
, &rtentry
)) {
794 "whoami: couldn't add route: %m.\n");
799 printf("whoami: unknown gateway addr family %d\n",
800 res
.router_address
.address_type
);
803 kmem_free(res
.client_name
, MAX_MACHINE_NAME
+ 1);
804 kmem_free(res
.domain_name
, MAX_MACHINE_NAME
+ 1);
806 (void) t_kclose(tiptr
, 0);
812 * 1) The ascii form of our root servers name in `server_name'.
813 * 2) Actual network address of our root server in `server_address'.
814 * 3) Whatever BOOTPARAMPROC_GETFILE returns for the fileid key, in
815 * `server_path'. If fileid is "root", it is the pathname of our
816 * root on the server.
819 getfile(char *fileid
,
820 char *server_name
, struct netbuf
*server_address
, char *server_path
)
822 struct bp_getfile_arg arg
;
823 struct bp_getfile_res res
;
826 static int using_cache
= FALSE
;
827 struct in_addr ipaddr
;
828 int timeo
= DEFAULT_TIMEO
;
829 int retries
= DEFAULT_RETRIES
;
832 printf("getfile: entered\n");
835 * Call cacheinfo() to see whether we can satisfy this request by using
836 * the information cached in memory by the boot program's DHCP
837 * implementation or boot properties rather than consult BOOTPARAMS,
838 * but while preserving the semantics of getfile(). We know that
839 * the server name is SYS_NMLN in length, and server_path is
840 * MAXPATHLEN (pn_alloc).
842 if (strcmp(fileid
, "root") == 0) {
843 if (cacheinfo(server_name
, SYS_NMLN
, server_address
,
844 server_path
, MAXPATHLEN
) == 0) {
852 * If using cache, rootopts is already available.
854 if (strcmp(fileid
, "rootopts") == 0 && using_cache
== TRUE
) {
855 return (rootopts
[0] != 0 ? 0 : ENXIO
);
858 if (bootparam_addr
.len
== 0) {
861 arg
.client_name
= (caddr_t
)&utsname
.nodename
;
862 arg
.file_id
= fileid
;
864 bzero(&res
, sizeof (res
));
865 res
.server_name
= kmem_alloc(MAX_MACHINE_NAME
+ 1, KM_SLEEP
);
866 res
.server_path
= kmem_alloc(MAX_MACHINE_NAME
+ 1, KM_SLEEP
);
869 * If we are not looking up the root file, we are looking
870 * up a non-critical option that should timeout quickly.
873 timeo
= GETFILE_TIMEO
;
874 retries
= GETFILE_RETRIES
;
878 * bootparam_addr was filled in by the call to
879 * whoami(), so now send an rpc message to the
880 * bootparam daemon requesting our server information.
881 * Use UDP to talk to bootparms.
883 stat
= mycallrpc(&dl_udp_netconf
, &bootparam_addr
,
884 (rpcprog_t
)BOOTPARAMPROG
, (rpcvers_t
)BOOTPARAMVERS
,
885 (rpcproc_t
)BOOTPARAMPROC_GETFILE
,
886 xdr_bp_getfile_arg
, (caddr_t
)&arg
,
887 xdr_bp_getfile_res
, (caddr_t
)&res
,
890 if (stat
== RPC_SUCCESS
) {
891 (void) strcpy(server_name
, res
.server_name
);
892 (void) strcpy(server_path
, res
.server_path
);
895 kmem_free(res
.server_name
, MAX_MACHINE_NAME
+ 1);
896 kmem_free(res
.server_path
, MAX_MACHINE_NAME
+ 1);
898 if (stat
!= RPC_SUCCESS
) {
900 cmn_err(CE_WARN
, "getfile: RPC failed: error %d (%s).",
901 stat
, clnt_sperrno(stat
));
902 return ((stat
== RPC_TIMEDOUT
) ? ETIMEDOUT
: ENXIO
); /* XXX */
905 if (*server_path
== '\0')
909 * If the fileid is "root", we must get back a server name, for
910 * other parameters a server name is not required
914 printf("getfile: leaving: non-root\n");
918 if (*server_name
== '\0')
921 switch (res
.server_address
.address_type
) {
924 * server_address is where we will get our root
927 ((struct sockaddr_in
*)server_address
->buf
)->sin_family
=
929 bcopy(&res
.server_address
.bp_address
.ip_addr
,
930 &ipaddr
, sizeof (ipaddr
));
931 if (ipaddr
.s_addr
== 0)
934 ((struct sockaddr_in
*)server_address
->buf
)->sin_addr
.s_addr
=
936 server_address
->len
= sizeof (struct sockaddr_in
);
940 printf("getfile: unknown address type %d\n",
941 res
.server_address
.address_type
);
942 return (EPROTONOSUPPORT
);
945 printf("getfile: leaving\n");
950 * If the boot property "bootp-response" exists, then OBP performed a
951 * successful DHCP lease acquisition for us and left the resultant ACK packet
952 * encoded at that location.
954 * If no such property exists (or the information is incomplete or garbled),
955 * the function returns -1.
962 struct in_addr braddr
;
963 struct in_addr subnet
;
966 struct sockaddr_in
*sin
;
967 static int once_only
= 0;
969 if (once_only
== 1) {
974 if (dhcack
== NULL
) {
979 printf("dhcp: dhcack %p, len %d\n", (void *)dhcack
,
983 pl
= kmem_alloc(sizeof (PKT_LIST
), KM_SLEEP
);
985 pl
->pkt
= kmem_alloc(pl
->len
, KM_SLEEP
);
986 bcopy(dhcack
, pl
->pkt
, dhcacklen
);
989 * For x86, ifname is not initialized
990 * in the netinstall case and dhcack interface name is
991 * set in strplumb(). So we only copy the name if ifname
995 (void) strlcpy(dhcifname
, ifname
, sizeof (dhcifname
));
997 /* remember the server_ip in dhcack */
998 bcopy((uchar_t
*)pl
->pkt
+ 20, dhcp_server_ip
, 4);
999 bzero(pl
->opts
, (DHCP_LAST_OPT
+ 1) * sizeof (DHCP_OPT
*));
1000 bzero(pl
->vs
, (VS_OPTION_END
- VS_OPTION_START
+ 1) *
1001 sizeof (DHCP_OPT
*));
1003 if (dhcp_options_scan(pl
, B_TRUE
) != 0) {
1004 /* garbled packet */
1005 cmn_err(CE_WARN
, "dhcp: DHCP packet parsing failed");
1006 kmem_free(pl
->pkt
, pl
->len
);
1007 kmem_free(pl
, sizeof (PKT_LIST
));
1013 if (pl
->opts
[CD_HOSTNAME
] != NULL
) {
1014 doptp
= pl
->opts
[CD_HOSTNAME
];
1016 if (i
>= SYS_NMLN
) {
1017 cmn_err(CE_WARN
, "dhcp: Hostname is too long");
1019 bcopy(doptp
->value
, utsname
.nodename
, i
);
1020 utsname
.nodename
[i
] = '\0';
1022 printf("hostname is %s\n",
1028 /* Set NIS domain name. */
1030 if (pl
->opts
[CD_NIS_DOMAIN
] != NULL
) {
1031 doptp
= pl
->opts
[CD_NIS_DOMAIN
];
1033 p
= (caddr_t
)doptp
->value
;
1038 "dhcp: NIS domainname too long.");
1040 bcopy(p
, srpc_domain
, i
);
1041 srpc_domain
[i
] = '\0';
1043 printf("dhcp: NIS domain name is %s\n",
1049 if (pl
->opts
[CD_SUBNETMASK
] != NULL
) {
1050 doptp
= pl
->opts
[CD_SUBNETMASK
];
1051 if (doptp
->len
!= sizeof (struct in_addr
)) {
1052 pl
->opts
[CD_SUBNETMASK
] = NULL
;
1053 cmn_err(CE_WARN
, "dhcp: netmask option malformed");
1055 bcopy(doptp
->value
, &subnet
, sizeof (struct in_addr
));
1057 printf("dhcp: setting netmask to: %s\n",
1061 struct in_addr myIPaddr
;
1063 myIPaddr
.s_addr
= pl
->pkt
->yiaddr
.s_addr
;
1064 cmn_err(CE_WARN
, "dhcp: no subnet mask supplied - inferring");
1065 if (IN_CLASSA(ntohl(myIPaddr
.s_addr
)))
1066 subnet
.s_addr
= htonl(IN_CLASSA_NET
);
1067 else if (IN_CLASSB(ntohl(myIPaddr
.s_addr
)))
1068 subnet
.s_addr
= htonl(IN_CLASSB_NET
);
1069 else if (IN_CLASSC(ntohl(myIPaddr
.s_addr
)))
1070 subnet
.s_addr
= htonl(IN_CLASSC_NET
);
1071 else if (IN_CLASSD(ntohl(myIPaddr
.s_addr
)))
1072 cmn_err(CE_WARN
, "dhcp: bad IP address (%s)",
1073 inet_ntoa(myIPaddr
));
1075 subnet
.s_addr
= htonl(IN_CLASSE_NET
);
1077 /* and broadcast address */
1078 if (pl
->opts
[CD_BROADCASTADDR
] != NULL
) {
1079 doptp
= pl
->opts
[CD_BROADCASTADDR
];
1080 if (doptp
->len
!= sizeof (struct in_addr
)) {
1081 pl
->opts
[CD_BROADCASTADDR
] = NULL
;
1083 printf("dhcp: broadcast address len %d\n",
1086 bcopy(doptp
->value
, &braddr
, sizeof (struct in_addr
));
1088 printf("dhcp: setting broadcast addr to: %s\n",
1093 printf("dhcp: no broadcast address supplied\n");
1094 braddr
.s_addr
= htonl(INADDR_BROADCAST
);
1096 /* and plumb and initialize interface */
1097 if ((rc
= t_kopen((file_t
*)NULL
, dl_udp_netconf
.knc_rdev
,
1098 FREAD
|FWRITE
, &tiptr
, CRED())) == 0) {
1099 if (rc
= dlifconfig(tiptr
, &pl
->pkt
->yiaddr
, &subnet
,
1100 &braddr
, IFF_DHCPRUNNING
)) {
1101 nfs_perror(rc
, "dhcp: dlifconfig failed: %m\n");
1102 kmem_free(pl
->pkt
, pl
->len
);
1103 kmem_free(pl
, sizeof (PKT_LIST
));
1105 (void) t_kclose(tiptr
, 0);
1110 if (pl
->opts
[CD_ROUTER
] != NULL
) {
1111 doptp
= pl
->opts
[CD_ROUTER
];
1112 if ((doptp
->len
% sizeof (struct in_addr
)) != 0) {
1113 pl
->opts
[CD_ROUTER
] = NULL
;
1118 nrouters
= doptp
->len
/ sizeof (struct in_addr
);
1119 for (tp
= doptp
->value
, i
= 0; i
< nrouters
;
1121 struct in_addr defr
;
1122 struct rtentry rtentry
;
1125 sizeof (struct in_addr
));
1126 if (defr
.s_addr
== 0)
1130 sockaddr_in
*)&rtentry
.rt_dst
;
1132 bzero(sin
, sizeof (*sin
));
1133 sin
->sin_family
= AF_INET
;
1136 sockaddr_in
*)&rtentry
.rt_gateway
;
1137 bzero(sin
, sizeof (*sin
));
1138 sin
->sin_family
= AF_INET
;
1139 sin
->sin_addr
= defr
;
1141 rtentry
.rt_flags
= RTF_GATEWAY
| RTF_UP
;
1143 if (rc
= rtioctl(tiptr
, SIOCADDRT
,
1146 "dhcp: couldn't add route "
1152 printf("dhcp: added route %s\n",
1155 tp
+= sizeof (struct in_addr
);
1160 (void) t_kclose(tiptr
, 0);
1164 printf("dhcpinit: leaving\n");
1170 * Initialize nfs mount info from properties and dhcp response.
1178 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1179 DDI_PROP_DONTPASS
, BP_SERVER_PATH
, &server_path_c
);
1180 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1181 DDI_PROP_DONTPASS
, BP_SERVER_NAME
, &server_name_c
);
1182 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1183 DDI_PROP_DONTPASS
, BP_SERVER_ROOTOPTS
, &str
) == DDI_SUCCESS
) {
1184 (void) strncpy(rootopts
, str
, 255);
1187 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1188 DDI_PROP_DONTPASS
, BP_SERVER_IP
, &str
) == DDI_SUCCESS
) {
1189 if (inet_aton(str
, server_ip
) != 0)
1190 cmn_err(CE_NOTE
, "server_ipaddr %s is invalid",
1194 printf("server ip is %s\n",
1195 inet_ntoa(*(struct in_addr
*)server_ip
));
1201 /* extract root path in server_path */
1202 if (server_path_c
== NULL
) {
1203 doptp
= pl
->vs
[VS_NFSMNT_ROOTPATH
];
1205 doptp
= pl
->opts
[CD_ROOT_PATH
];
1206 if (doptp
!= NULL
) {
1211 source
= doptp
->value
;
1216 * We have to consider three cases for root path:
1217 * "nfs://server_ip/path"
1221 if (bcmp(source
, "nfs://", 6) == 0) {
1227 * Search for next char after ':' or first '/'.
1228 * Note, the '/' is part of the path, but we do
1229 * not need to preserve the ':'.
1231 for (len
= 0; len
< size
; len
++) {
1232 if (source
[len
] == c
) {
1234 str
= (char *)(&source
[++len
]);
1236 str
= (char *)(&source
[len
++]);
1243 /* Do not override server_ip from property. */
1244 if ((*(uint_t
*)server_ip
) == 0) {
1245 char *ip
= kmem_alloc(len
, KM_SLEEP
);
1246 bcopy(source
, ip
, len
);
1248 if (inet_aton((ip
), server_ip
) != 0) {
1250 "server_ipaddr %s is "
1255 printf("server ip is %s\n",
1263 str
= (char *)doptp
->value
;
1266 server_path_c
= kmem_alloc(len
+ 1, KM_SLEEP
);
1267 bcopy(str
, server_path_c
, len
);
1268 server_path_c
[len
] = '\0';
1270 printf("dhcp: root path %s\n", server_path_c
);
1272 cmn_err(CE_WARN
, "dhcp: root server path missing");
1276 /* set server_name */
1277 if (server_name_c
== NULL
) {
1278 doptp
= pl
->vs
[VS_NFSMNT_ROOTSRVR_NAME
];
1279 if (doptp
!= NULL
) {
1280 server_name_c
= kmem_alloc(doptp
->len
+ 1, KM_SLEEP
);
1281 bcopy(doptp
->value
, server_name_c
, doptp
->len
);
1282 server_name_c
[doptp
->len
] = '\0';
1284 printf("dhcp: root server name %s\n",
1287 cmn_err(CE_WARN
, "dhcp: root server name missing");
1291 /* set root server_address */
1292 if ((*(uint_t
*)server_ip
) == 0) {
1293 doptp
= pl
->vs
[VS_NFSMNT_ROOTSRVR_IP
];
1295 bcopy(doptp
->value
, server_ip
, sizeof (server_ip
));
1297 printf("dhcp: root server IP address %s\n",
1298 inet_ntoa(*(struct in_addr
*)server_ip
));
1303 "dhcp: file server ip address missing,"
1304 " fallback to dhcp server as file server");
1305 bcopy(dhcp_server_ip
, server_ip
, sizeof (server_ip
));
1309 /* set root file system mount options */
1310 if (rootopts
[0] == 0) {
1311 doptp
= pl
->vs
[VS_NFSMNT_ROOTOPTS
];
1312 if (doptp
!= NULL
&& doptp
->len
< 255) {
1313 bcopy(doptp
->value
, rootopts
, doptp
->len
);
1314 rootopts
[doptp
->len
] = '\0';
1316 printf("dhcp: rootopts %s\n", rootopts
);
1317 } else if (dldebug
) {
1318 printf("dhcp: no rootopts or too long\n");
1323 /* now we are done with pl, just free it */
1324 kmem_free(pl
->pkt
, pl
->len
);
1325 kmem_free(pl
, sizeof (PKT_LIST
));
1330 cacheinfo(char *name
, int namelen
,
1331 struct netbuf
*server_address
, char *rootpath
, int pathlen
)
1333 static int init_done
= 0;
1334 struct sockaddr_in
*sin
;
1336 if (init_done
== 0) {
1341 /* server_path is a reliable indicator of cache availability */
1342 if (server_path_c
== NULL
)
1345 (void) strncpy(rootpath
, server_path_c
, pathlen
);
1346 if (server_name_c
) {
1347 (void) strncpy(name
, server_name_c
, namelen
);
1349 (void) strncpy(name
, "unknown", namelen
);
1352 sin
= (struct sockaddr_in
*)server_address
->buf
;
1353 sin
->sin_family
= AF_INET
;
1354 server_address
->len
= sizeof (struct sockaddr_in
);
1355 bcopy(server_ip
, &sin
->sin_addr
, sizeof (struct in_addr
));
1360 * Set this interface's IP address and netmask, and bring it up.
1363 dlifconfig(TIUSER
*tiptr
, struct in_addr
*myIPaddr
, struct in_addr
*mymask
,
1364 struct in_addr
*mybraddr
, uint_t flags
)
1368 struct sockaddr_in sin
;
1371 printf("dlifconfig: entered\n");
1372 printf("dlifconfig: addr %s\n", inet_ntoa(*myIPaddr
));
1373 printf("dlifconfig: mask %s\n", inet_ntoa(*mymask
));
1374 printf("dlifconfig: broadcast %s\n", inet_ntoa(*mybraddr
));
1377 bcopy(myIPaddr
, &sin
.sin_addr
, sizeof (struct in_addr
));
1378 sin
.sin_family
= AF_INET
;
1379 sbuf
.buf
= (caddr_t
)&sin
;
1380 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1381 if (rc
= ifioctl(tiptr
, SIOCSIFADDR
, &sbuf
)) {
1383 "dlifconfig: couldn't set interface net address: %m\n");
1387 if (mybraddr
->s_addr
!= INADDR_BROADCAST
) {
1388 bcopy(mybraddr
, &sin
.sin_addr
, sizeof (struct in_addr
));
1389 sin
.sin_family
= AF_INET
;
1390 sbuf
.buf
= (caddr_t
)&sin
;
1391 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1392 if (rc
= ifioctl(tiptr
, SIOCSIFBRDADDR
, &sbuf
)) {
1394 "dlifconfig: couldn't set interface broadcast addr: %m\n");
1399 bcopy(mymask
, &sin
.sin_addr
, sizeof (struct in_addr
));
1400 sin
.sin_family
= AF_INET
;
1401 sbuf
.buf
= (caddr_t
)&sin
;
1402 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1403 if (rc
= ifioctl(tiptr
, SIOCSIFNETMASK
, &sbuf
)) {
1405 "dlifconfig: couldn't set interface net address: %m\n");
1410 * Now turn on the interface.
1412 if (rc
= setifflags(tiptr
, IFF_UP
| flags
)) {
1414 "dlifconfig: couldn't enable network interface: %m\n");
1419 printf("dlifconfig: returned\n");
1424 inet_ntoa(struct in_addr in
)
1429 p
= (unsigned char *)&in
;
1430 (void) sprintf(b
, "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
1434 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1436 inet_aton(char *ipstr
, uchar_t
*ip
)
1439 uchar_t val
[4] = {0};
1448 val
[i
] = val
[i
] * 10 + (c
- '0');
1464 #define MAX_ADDR_SIZE 128
1467 * Initialize a netbuf suitable for
1468 * describing an address for the
1469 * transport defined by `tiptr'.
1472 init_netbuf(struct netbuf
*nbuf
)
1474 nbuf
->buf
= kmem_zalloc(MAX_ADDR_SIZE
, KM_SLEEP
);
1475 nbuf
->maxlen
= MAX_ADDR_SIZE
;
1480 free_netbuf(struct netbuf
*nbuf
)
1482 kmem_free(nbuf
->buf
, nbuf
->maxlen
);
1489 rtioctl(TIUSER
*tiptr
, int cmd
, struct rtentry
*rtentry
)
1491 struct strioctl iocb
;
1497 iocb
.ic_len
= sizeof (struct rtentry
);
1498 iocb
.ic_dp
= (caddr_t
)rtentry
;
1500 vp
= tiptr
->fp
->f_vnode
;
1501 rc
= kstr_ioctl(vp
, I_STR
, (intptr_t)&iocb
);
1503 nfs_perror(rc
, "rtioctl: kstr_ioctl failed: %m\n");
1508 * Send an ioctl down the stream defined
1511 * We isolate the ifreq dependencies in here. The
1512 * ioctl really ought to take a netbuf and be of
1513 * type TRANSPARENT - one day.
1516 ifioctl(TIUSER
*tiptr
, int cmd
, struct netbuf
*nbuf
)
1518 struct strioctl iocb
;
1524 * Now do the one requested.
1527 ifr
.ifr_addr
= *(struct sockaddr
*)nbuf
->buf
;
1528 (void) strncpy((caddr_t
)&ifr
.ifr_name
, ifname
, sizeof (ifr
.ifr_name
));
1531 iocb
.ic_len
= sizeof (ifr
);
1532 iocb
.ic_dp
= (caddr_t
)&ifr
;
1534 vp
= tiptr
->fp
->f_vnode
;
1535 rc
= kstr_ioctl(vp
, I_STR
, (intptr_t)&iocb
);
1537 nfs_perror(rc
, "ifioctl: kstr_ioctl failed: %m\n");
1544 if (nbuf
->len
== 0) {
1548 nbuf
->len
= sizeof (struct sockaddr
);
1549 *(struct sockaddr
*)nbuf
->buf
= ifr
.ifr_addr
;
1556 setifflags(TIUSER
*tiptr
, uint_t value
)
1560 struct strioctl iocb
;
1562 (void) strncpy((caddr_t
)&ifr
.ifr_name
, ifname
, sizeof (ifr
.ifr_name
));
1563 iocb
.ic_cmd
= SIOCGIFFLAGS
;
1565 iocb
.ic_len
= sizeof (ifr
);
1566 iocb
.ic_dp
= (caddr_t
)&ifr
;
1567 if (rc
= kstr_ioctl(tiptr
->fp
->f_vnode
, I_STR
, (intptr_t)&iocb
))
1570 ifr
.ifr_flags
|= value
;
1571 iocb
.ic_cmd
= SIOCSIFFLAGS
;
1572 return (kstr_ioctl(tiptr
->fp
->f_vnode
, I_STR
, (intptr_t)&iocb
));
1576 * REVerse Address Resolution Protocol (revarp)
1577 * is used by a diskless client to find out its
1578 * IP address when all it knows is its Ethernet address.
1580 * Open the ethernet driver, attach and bind
1581 * (DL_BIND_REQ) it, and then format a broadcast RARP
1582 * message for it to send. We pick up the reply and
1583 * let the caller set the interface address using SIOCSIFADDR.
1586 revarp_myaddr(TIUSER
*tiptr
)
1590 struct sockaddr_in sin
;
1594 struct netbuf myaddr
= {0, 0, NULL
};
1597 printf("revarp_myaddr: entered\n");
1599 if (rc
= ldi_ident_from_mod(&modlinkage
, &li
)) {
1601 "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1605 rc
= ldi_open_by_name(ndev_path
, FREAD
|FWRITE
, CRED(), &lh
, li
);
1606 ldi_ident_release(li
);
1609 "revarp_myaddr: ldi_open_by_name failed: %m\n");
1613 if (rc
= dl_attach(lh
, ifunit
, NULL
)) {
1614 nfs_perror(rc
, "revarp_myaddr: dl_attach failed: %m\n");
1615 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1619 if (rc
= dl_bind(lh
, ETHERTYPE_REVARP
, NULL
)) {
1620 nfs_perror(rc
, "revarp_myaddr: dl_bind failed: %m\n");
1621 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1625 if (rc
= dl_info(lh
, &info
, NULL
, NULL
, NULL
)) {
1626 nfs_perror(rc
, "revarp_myaddr: dl_info failed: %m\n");
1627 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1631 /* Initialize myaddr */
1632 myaddr
.maxlen
= info
.dl_addr_length
;
1633 myaddr
.buf
= kmem_alloc(myaddr
.maxlen
, KM_SLEEP
);
1635 revarp_start(lh
, &myaddr
);
1637 bcopy(myaddr
.buf
, &sin
.sin_addr
, myaddr
.len
);
1638 sin
.sin_family
= AF_INET
;
1640 sbuf
.buf
= (caddr_t
)&sin
;
1641 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1642 if (rc
= ifioctl(tiptr
, SIOCSIFADDR
, &sbuf
)) {
1644 "revarp_myaddr: couldn't set interface net address: %m\n");
1645 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1646 kmem_free(myaddr
.buf
, myaddr
.maxlen
);
1650 /* Now turn on the interface */
1651 if (rc
= setifflags(tiptr
, IFF_UP
)) {
1653 "revarp_myaddr: couldn't enable network interface: %m\n");
1656 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1657 kmem_free(myaddr
.buf
, myaddr
.maxlen
);
1662 revarp_start(ldi_handle_t lh
, struct netbuf
*myaddr
)
1664 struct ether_arp
*ea
;
1666 dl_unitdata_req_t
*dl_udata
;
1669 struct dladdr
*dlsap
;
1670 static int done
= 0;
1671 size_t addrlen
= ETHERADDRL
;
1673 if (dl_phys_addr(lh
, (uchar_t
*)&myether
, &addrlen
, NULL
) != 0 ||
1674 addrlen
!= ETHERADDRL
) {
1675 /* Fallback using per-node address */
1676 (void) localetheraddr(NULL
, &myether
);
1677 cmn_err(CE_CONT
, "?DLPI failed to get Ethernet address. Using "
1678 "system wide Ethernet address %s\n",
1679 ether_sprintf(&myether
));
1683 if (myaddr
->len
!= 0) {
1684 cmn_err(CE_CONT
, "?Found my IP address: %x (%d.%d.%d.%d)\n",
1685 *(int *)myaddr
->buf
,
1686 (uchar_t
)myaddr
->buf
[0], (uchar_t
)myaddr
->buf
[1],
1687 (uchar_t
)myaddr
->buf
[2], (uchar_t
)myaddr
->buf
[3]);
1692 cmn_err(CE_CONT
, "?Requesting Internet address for %s\n",
1693 ether_sprintf(&myether
));
1696 * Send another RARP request.
1698 if ((mp
= allocb(sizeof (dl_unitdata_req_t
) + sizeof (*dlsap
),
1699 BPRI_HI
)) == NULL
) {
1700 cmn_err(CE_WARN
, "revarp_myaddr: allocb no memory");
1703 if ((bp
= allocb(sizeof (struct ether_arp
), BPRI_HI
)) == NULL
) {
1704 cmn_err(CE_WARN
, "revarp_myaddr: allocb no memory");
1709 * Format the transmit request part.
1711 mp
->b_datap
->db_type
= M_PROTO
;
1712 dl_udata
= (dl_unitdata_req_t
*)mp
->b_wptr
;
1713 mp
->b_wptr
+= sizeof (dl_unitdata_req_t
) + sizeof (*dlsap
);
1714 dl_udata
->dl_primitive
= DL_UNITDATA_REQ
;
1715 dl_udata
->dl_dest_addr_length
= sizeof (*dlsap
);
1716 dl_udata
->dl_dest_addr_offset
= sizeof (*dl_udata
);
1717 dl_udata
->dl_priority
.dl_min
= 0;
1718 dl_udata
->dl_priority
.dl_max
= 0;
1720 dlsap
= (struct dladdr
*)(mp
->b_rptr
+ sizeof (*dl_udata
));
1721 bcopy(ðerbroadcastaddr
, &dlsap
->dl_phys
,
1722 sizeof (etherbroadcastaddr
));
1723 dlsap
->dl_sap
= ETHERTYPE_REVARP
;
1726 * Format the actual REVARP request.
1728 bzero(bp
->b_wptr
, sizeof (struct ether_arp
));
1729 ea
= (struct ether_arp
*)bp
->b_wptr
;
1730 bp
->b_wptr
+= sizeof (struct ether_arp
);
1731 ea
->arp_hrd
= htons(ARPHRD_ETHER
);
1732 ea
->arp_pro
= htons(ETHERTYPE_IP
);
1733 ea
->arp_hln
= sizeof (ea
->arp_sha
); /* hardware address length */
1734 ea
->arp_pln
= sizeof (ea
->arp_spa
); /* protocol address length */
1735 ea
->arp_op
= htons(REVARP_REQUEST
);
1736 ether_copy(&myether
, &ea
->arp_sha
);
1737 ether_copy(&myether
, &ea
->arp_tha
);
1741 if ((rc
= ldi_putmsg(lh
, mp
)) != 0) {
1742 nfs_perror(rc
, "revarp_start: ldi_putmsg failed: %m\n");
1745 revarpinput(lh
, myaddr
);
1751 * Client side Reverse-ARP input
1752 * Server side is handled by user level server
1755 revarpinput(ldi_handle_t lh
, struct netbuf
*myaddr
)
1757 struct ether_arp
*ea
;
1761 timestruc_t tv
, give_up
, now
;
1764 * Choose the time at which we will give up, and resend our
1767 gethrestime(&give_up
);
1768 give_up
.tv_sec
+= REVARP_TIMEO
;
1771 * Compute new timeout value.
1775 timespecsub(&tv
, &now
);
1777 * If we don't have at least one full second remaining, give up.
1778 * This means we might wait only just over 4.0 seconds, but that's
1783 rc
= ldi_getmsg(lh
, &mp
, &tv
);
1786 } else if (rc
!= 0) {
1787 nfs_perror(rc
, "revarpinput: ldi_getmsg failed: %m\n");
1791 if (mp
->b_cont
== NULL
) {
1792 printf("revarpinput: b_cont == NULL\n");
1796 if (mp
->b_datap
->db_type
!= M_PROTO
) {
1797 printf("revarpinput: bad header type %d\n",
1798 mp
->b_datap
->db_type
);
1804 if (bp
->b_wptr
- bp
->b_rptr
< sizeof (*ea
)) {
1805 printf("revarpinput: bad data len %d, expect %d\n",
1806 (int)(bp
->b_wptr
- bp
->b_rptr
), (int)sizeof (*ea
));
1810 ea
= (struct ether_arp
*)bp
->b_rptr
;
1812 if ((ushort_t
)ntohs(ea
->arp_pro
) != ETHERTYPE_IP
) {
1813 /* We could have received another broadcast arp packet. */
1815 printf("revarpinput: bad type %x\n",
1816 (ushort_t
)ntohs(ea
->arp_pro
));
1820 if ((ushort_t
)ntohs(ea
->arp_op
) != REVARP_REPLY
) {
1821 /* We could have received a broadcast arp request. */
1823 printf("revarpinput: bad op %x\n",
1824 (ushort_t
)ntohs(ea
->arp_op
));
1829 if (!ether_cmp(&ea
->arp_tha
, &myether
)) {
1830 bcopy(&ea
->arp_tpa
, myaddr
->buf
, sizeof (ea
->arp_tpa
));
1831 myaddr
->len
= sizeof (ea
->arp_tpa
);
1833 /* We could have gotten a broadcast arp response. */
1835 printf("revarpinput: got reply, but not my address\n");
1844 * From rpcsvc/mountxdr.c in SunOS. We can't
1845 * put this into the rpc directory because
1846 * it calls xdr_fhandle() which is in a
1850 myxdr_fhstatus(XDR
*xdrs
, struct fhstatus
*fhsp
)
1853 if (!xdr_int(xdrs
, &fhsp
->fhs_status
))
1855 if (fhsp
->fhs_status
== 0) {
1856 if (!myxdr_fhandle(xdrs
, &fhsp
->fhs_fh
))
1865 * File access handle
1866 * The fhandle struct is treated a opaque data on the wire
1869 myxdr_fhandle(XDR
*xdrs
, fhandle_t
*fh
)
1871 return (xdr_opaque(xdrs
, (caddr_t
)fh
, NFS_FHSIZE
));
1875 myxdr_mountres3(XDR
*xdrs
, struct mountres3
*objp
)
1877 if (!myxdr_mountstat3(xdrs
, &objp
->fhs_status
))
1879 switch (objp
->fhs_status
) {
1881 if (!myxdr_mountres3_ok(xdrs
, &objp
->mountres3_u
.mountinfo
))
1891 myxdr_mountstat3(XDR
*xdrs
, enum mountstat3
*objp
)
1893 return (xdr_enum(xdrs
, (enum_t
*)objp
));
1897 myxdr_mountres3_ok(XDR
*xdrs
, struct mountres3_ok
*objp
)
1899 if (!myxdr_fhandle3(xdrs
, &objp
->fhandle
))
1901 if (!xdr_array(xdrs
, (char **)&objp
->auth_flavors
.auth_flavors_val
,
1902 (uint_t
*)&objp
->auth_flavors
.auth_flavors_len
, ~0,
1903 sizeof (int), (xdrproc_t
)xdr_int
))
1909 myxdr_fhandle3(XDR
*xdrs
, struct fhandle3
*objp
)
1911 return (xdr_bytes(xdrs
, (char **)&objp
->fhandle3_val
,
1912 (uint_t
*)&objp
->fhandle3_len
, FHSIZE3
));
1916 * From SunOS pmap_clnt.c
1918 * Port mapper routines:
1919 * pmap_kgetport() - get port number.
1920 * pmap_rmt_call() - indirect call via port mapper.
1923 static enum clnt_stat
1924 pmap_kgetport(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
1925 rpcprog_t prog
, rpcvers_t vers
, rpcprot_t prot
)
1929 enum clnt_stat stat
;
1930 struct pmap pmap_parms
;
1936 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= htons(PMAPPORT
);
1938 pmap_parms
.pm_prog
= prog
;
1939 pmap_parms
.pm_vers
= vers
;
1940 pmap_parms
.pm_prot
= prot
;
1941 pmap_parms
.pm_port
= 0;
1942 for (tries
= 0; tries
< 5; tries
++) {
1943 stat
= mycallrpc(knconf
, call_addr
,
1944 PMAPPROG
, PMAPVERS
, PMAPPROC_GETPORT
,
1945 myxdr_pmap
, (char *)&pmap_parms
,
1946 xdr_u_short
, (char *)&port
,
1947 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
1949 if (stat
!= RPC_TIMEDOUT
)
1952 "pmap_kgetport: Portmapper not responding; still trying");
1955 if (stat
== RPC_PROGUNAVAIL
) {
1957 "pmap_kgetport: Portmapper failed - trying rpcbind");
1959 rpcb_parms
.r_prog
= prog
;
1960 rpcb_parms
.r_vers
= vers
;
1961 rpcb_parms
.r_netid
= knconf
->knc_proto
;
1962 rpcb_parms
.r_addr
= rpcb_parms
.r_owner
= "";
1964 for (tries
= 0; tries
< 5; tries
++) {
1965 stat
= mycallrpc(knconf
, call_addr
,
1966 RPCBPROG
, RPCBVERS
, RPCBPROC_GETADDR
,
1967 xdr_rpcb
, (char *)&rpcb_parms
,
1968 xdr_wrapstring
, (char *)&ua
,
1969 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
1971 if (stat
!= RPC_TIMEDOUT
)
1974 "pmap_kgetport: rpcbind not responding; still trying");
1977 if (stat
== RPC_SUCCESS
) {
1978 if ((ua
!= NULL
) && (ua
[0] != '\0')) {
1979 port
= rpc_uaddr2port(AF_INET
, ua
);
1981 /* Address unknown */
1982 stat
= RPC_PROGUNAVAIL
;
1987 if (stat
== RPC_SUCCESS
)
1988 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= ntohs(port
);
1994 * pmapper remote-call-service interface.
1995 * This routine is used to call the pmapper remote call service
1996 * which will look up a service program in the port maps, and then
1997 * remotely call that routine with the given parameters. This allows
1998 * programs to do a lookup and call in one step. In addition to the call_addr,
1999 * the caller provides a boolean hint about the destination address (TRUE if
2000 * address is a broadcast address, FALSE otherwise).
2002 * On return, `call addr' contains the port number for the
2003 * service requested, and `resp_addr' contains its IP address.
2005 static enum clnt_stat
2006 pmap_rmt_call(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
2007 bool_t bcast
, rpcprog_t progn
, rpcvers_t versn
, rpcproc_t procn
,
2008 xdrproc_t xdrargs
, caddr_t argsp
, xdrproc_t xdrres
, caddr_t resp
,
2009 struct timeval tout
, struct netbuf
*resp_addr
)
2012 enum clnt_stat stat
;
2015 struct rmtcallargs pmap_args
;
2016 struct rmtcallres pmap_res
;
2017 struct rpcb_rmtcallargs rpcb_args
;
2018 struct rpcb_rmtcallres rpcb_res
;
2019 char ua
[100]; /* XXX */
2021 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= htons(PMAPPORT
);
2023 rc
= clnt_tli_kcreate(knconf
, call_addr
, PMAPPROG
, PMAPVERS
,
2024 0, PMAP_RETRIES
, CRED(), &cl
);
2027 "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2028 return (RPC_SYSTEMERROR
); /* XXX */
2030 if (cl
== (CLIENT
*)NULL
) {
2031 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2035 (void) CLNT_CONTROL(cl
, CLSET_BCAST
, (char *)&bcast
);
2037 pmap_args
.prog
= progn
;
2038 pmap_args
.vers
= versn
;
2039 pmap_args
.proc
= procn
;
2040 pmap_args
.args_ptr
= argsp
;
2041 pmap_args
.xdr_args
= xdrargs
;
2042 pmap_res
.port_ptr
= &port
;
2043 pmap_res
.results_ptr
= resp
;
2044 pmap_res
.xdr_results
= xdrres
;
2045 stat
= clnt_clts_kcallit_addr(cl
, PMAPPROC_CALLIT
,
2046 myxdr_rmtcall_args
, (caddr_t
)&pmap_args
,
2047 myxdr_rmtcallres
, (caddr_t
)&pmap_res
,
2050 if (stat
== RPC_SUCCESS
) {
2051 ((struct sockaddr_in
*)resp_addr
->buf
)->sin_port
=
2052 htons((ushort_t
)port
);
2056 if (stat
!= RPC_PROGUNAVAIL
)
2059 cmn_err(CE_WARN
, "pmap_rmt_call: Portmapper failed - trying rpcbind");
2061 rc
= clnt_tli_kcreate(knconf
, call_addr
, RPCBPROG
, RPCBVERS
,
2062 0, PMAP_RETRIES
, CRED(), &cl
);
2064 nfs_perror(rc
, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2065 return (RPC_SYSTEMERROR
); /* XXX */
2069 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2073 rpcb_args
.prog
= progn
;
2074 rpcb_args
.vers
= versn
;
2075 rpcb_args
.proc
= procn
;
2076 rpcb_args
.args_ptr
= argsp
;
2077 rpcb_args
.xdr_args
= xdrargs
;
2078 rpcb_res
.addr_ptr
= ua
;
2079 rpcb_res
.results_ptr
= resp
;
2080 rpcb_res
.xdr_results
= xdrres
;
2081 stat
= clnt_clts_kcallit_addr(cl
, PMAPPROC_CALLIT
,
2082 xdr_rpcb_rmtcallargs
, (caddr_t
)&rpcb_args
,
2083 xdr_rpcb_rmtcallres
, (caddr_t
)&rpcb_res
,
2086 if (stat
== RPC_SUCCESS
)
2087 ((struct sockaddr_in
*)resp_addr
->buf
)->sin_port
=
2088 rpc_uaddr2port(AF_INET
, ua
);
2095 * XDR remote call arguments
2096 * written for XDR_ENCODE direction only
2099 myxdr_rmtcall_args(XDR
*xdrs
, struct rmtcallargs
*cap
)
2105 if (xdr_rpcprog(xdrs
, &(cap
->prog
)) &&
2106 xdr_rpcvers(xdrs
, &(cap
->vers
)) &&
2107 xdr_rpcproc(xdrs
, &(cap
->proc
))) {
2108 lenposition
= XDR_GETPOS(xdrs
);
2109 if (!xdr_u_int(xdrs
, &cap
->arglen
))
2111 argposition
= XDR_GETPOS(xdrs
);
2112 if (!(*(cap
->xdr_args
))(xdrs
, cap
->args_ptr
))
2114 position
= XDR_GETPOS(xdrs
);
2115 cap
->arglen
= (uint_t
)position
- (uint_t
)argposition
;
2116 XDR_SETPOS(xdrs
, lenposition
);
2117 if (!xdr_u_int(xdrs
, &cap
->arglen
))
2119 XDR_SETPOS(xdrs
, position
);
2126 * XDR remote call results
2127 * written for XDR_DECODE direction only
2130 myxdr_rmtcallres(XDR
*xdrs
, struct rmtcallres
*crp
)
2134 port_ptr
= (caddr_t
)crp
->port_ptr
;
2135 if (xdr_reference(xdrs
, &port_ptr
, sizeof (uint_t
), xdr_u_int
) &&
2136 xdr_u_int(xdrs
, &crp
->resultslen
)) {
2137 crp
->port_ptr
= (rpcport_t
*)port_ptr
;
2138 return ((*(crp
->xdr_results
))(xdrs
, crp
->results_ptr
));
2144 myxdr_pmap(XDR
*xdrs
, struct pmap
*regs
)
2146 if (xdr_rpcprog(xdrs
, ®s
->pm_prog
) &&
2147 xdr_rpcvers(xdrs
, ®s
->pm_vers
) &&
2148 xdr_rpcprot(xdrs
, ®s
->pm_prot
))
2149 return (xdr_rpcport(xdrs
, ®s
->pm_port
));
2155 * From SunOS callrpc.c
2157 static enum clnt_stat
2158 mycallrpc(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
2159 rpcprog_t prognum
, rpcvers_t versnum
, rpcproc_t procnum
,
2160 xdrproc_t inproc
, char *in
, xdrproc_t outproc
, char *out
,
2161 int timeo
, int retries
)
2165 enum clnt_stat cl_stat
;
2168 rc
= clnt_tli_kcreate(knconf
, call_addr
, prognum
, versnum
,
2169 0, retries
, CRED(), &cl
);
2171 nfs_perror(rc
, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2172 return (RPC_SYSTEMERROR
); /* XXX */
2176 cl_stat
= CLNT_CALL(cl
, procnum
, inproc
, in
, outproc
, out
, tv
);
2177 AUTH_DESTROY(cl
->cl_auth
);
2183 * Configure the 'default' interface based on existing boot properties.
2189 struct in_addr my_ip
, my_netmask
, my_router
, my_broadcast
;
2190 struct sockaddr_in
*sin
;
2193 struct rtentry rtentry
;
2195 my_ip
.s_addr
= my_netmask
.s_addr
= my_router
.s_addr
= 0;
2198 * No way of getting this right now. Collude with dlifconfig()
2199 * to let the protocol stack choose.
2201 my_broadcast
.s_addr
= INADDR_BROADCAST
;
2203 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2204 DDI_PROP_DONTPASS
, BP_HOST_IP
, &str
) == DDI_SUCCESS
) {
2205 if (inet_aton(str
, (uchar_t
*)&my_ip
) != 0)
2206 cmn_err(CE_NOTE
, "host-ip %s is invalid\n",
2210 printf("host ip is %s\n",
2213 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2214 DDI_PROP_DONTPASS
, BP_SUBNET_MASK
, &str
) == DDI_SUCCESS
) {
2215 if (inet_aton(str
, (uchar_t
*)&my_netmask
) != 0)
2216 cmn_err(CE_NOTE
, "subnet-mask %s is invalid\n",
2220 printf("subnet mask is %s\n",
2221 inet_ntoa(my_netmask
));
2223 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2224 DDI_PROP_DONTPASS
, BP_ROUTER_IP
, &str
) == DDI_SUCCESS
) {
2225 if (inet_aton(str
, (uchar_t
*)&my_router
) != 0)
2226 cmn_err(CE_NOTE
, "router-ip %s is invalid\n",
2230 printf("router ip is %s\n",
2231 inet_ntoa(my_router
));
2233 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2234 DDI_PROP_DONTPASS
, BP_SERVER_PATH
, &server_path_c
);
2235 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2236 DDI_PROP_DONTPASS
, BP_SERVER_NAME
, &server_name_c
);
2237 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2238 DDI_PROP_DONTPASS
, BP_SERVER_ROOTOPTS
, &str
) == DDI_SUCCESS
) {
2239 (void) strlcpy(rootopts
, str
, sizeof (rootopts
));
2242 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2243 DDI_PROP_DONTPASS
, BP_SERVER_IP
, &str
) == DDI_SUCCESS
) {
2244 if (inet_aton(str
, server_ip
) != 0)
2245 cmn_err(CE_NOTE
, "server-ip %s is invalid\n",
2249 printf("server ip is %s\n",
2250 inet_ntoa(*(struct in_addr
*)server_ip
));
2254 * We need all of these to configure based on properties.
2256 if ((my_ip
.s_addr
== 0) ||
2257 (my_netmask
.s_addr
== 0) ||
2258 (server_path_c
== NULL
) ||
2259 (server_name_c
== NULL
) ||
2260 (*(uint_t
*)server_ip
== 0))
2263 cmn_err(CE_CONT
, "?IP address: %s\n", inet_ntoa(my_ip
));
2264 cmn_err(CE_CONT
, "?IP netmask: %s\n", inet_ntoa(my_netmask
));
2265 if (my_router
.s_addr
!= 0)
2266 cmn_err(CE_CONT
, "?IP router: %s\n", inet_ntoa(my_router
));
2267 cmn_err(CE_CONT
, "?NFS server: %s (%s)\n", server_name_c
,
2268 inet_ntoa(*(struct in_addr
*)server_ip
));
2269 cmn_err(CE_CONT
, "?NFS path: %s\n", server_path_c
);
2272 * Configure the interface.
2274 if ((rc
= t_kopen((file_t
*)NULL
, dl_udp_netconf
.knc_rdev
,
2275 FREAD
|FWRITE
, &tiptr
, CRED())) != 0) {
2276 nfs_perror(rc
, "bp_netconfig: t_kopen udp failed: %m.\n");
2280 if ((rc
= dlifconfig(tiptr
, &my_ip
, &my_netmask
, &my_broadcast
,
2282 nfs_perror(rc
, "bp_netconfig: dlifconfig failed: %m.\n");
2283 (void) t_kclose(tiptr
, 0);
2287 if (my_router
.s_addr
!= 0) {
2289 * Add a default route.
2291 sin
= (struct sockaddr_in
*)&rtentry
.rt_dst
;
2292 bzero(sin
, sizeof (*sin
));
2293 sin
->sin_family
= AF_INET
;
2295 sin
= (struct sockaddr_in
*)&rtentry
.rt_gateway
;
2296 bzero(sin
, sizeof (*sin
));
2297 sin
->sin_family
= AF_INET
;
2298 sin
->sin_addr
= my_router
;
2300 rtentry
.rt_flags
= RTF_GATEWAY
| RTF_UP
;
2302 if ((rc
= rtioctl(tiptr
, SIOCADDRT
, &rtentry
)) != 0) {
2304 "bp_netconfig: couldn't add route: %m.\n");
2305 (void) t_kclose(tiptr
, 0);
2310 (void) t_kclose(tiptr
, 0);
2316 * The network device we will use to boot from is plumbed. Extract the details
2322 (void) strlcpy(ndev_path
, rootfs
.bo_devname
, sizeof (ndev_path
));
2323 (void) strlcpy(ifname
, rootfs
.bo_ifname
, sizeof (ifname
));
2324 ifunit
= rootfs
.bo_ppa
;
2327 * Assumes only one linkage array element.
2329 dl_udp_netconf
.knc_rdev
=
2330 makedevice(clone_major
, ddi_name_to_major("udp"));
2331 dl_tcp_netconf
.knc_rdev
=
2332 makedevice(clone_major
, ddi_name_to_major("tcp"));
2335 * Now we bringup the interface.
2336 * Try cached dhcp response first. If it fails, do rarp.
2338 if ((bp_netconfig() != 0) &&
2339 (dhcpinit() != 0) &&
2342 "%s: no response from interface", ifname
);
2344 printf("init_config: ifname %s is up\n", ifname
);
2348 * These options are duplicated in cmd/fs.d/nfs/mount/mount.c
2349 * Changes must be made to both lists.
2351 static char *optlist
[] = {
2358 #define OPT_NOQUOTA 3
2366 #define OPT_NOSUID 7
2370 #define OPT_REMOUNT 9
2372 #define OPT_NOSUB 10
2376 #define OPT_NOINTR 12
2380 #define OPT_SECURE 14
2382 #define OPT_RSIZE 15
2384 #define OPT_WSIZE 16
2386 #define OPT_TIMEO 17
2388 #define OPT_RETRANS 18
2390 #define OPT_ACTIMEO 19
2392 #define OPT_ACREGMIN 20
2394 #define OPT_ACREGMAX 21
2396 #define OPT_ACDIRMIN 22
2398 #define OPT_ACDIRMAX 23
2404 #define OPT_RETRY 26
2408 #define OPT_NOCTO 28
2410 #define OPT_LLOCK 29
2412 #define OPT_POSIX 30
2416 #define OPT_PROTO 32
2418 #define OPT_SEMISOFT 33
2420 #define OPT_NOPRINT 34
2424 #define OPT_LARGEFILES 36
2426 #define OPT_NOLARGEFILES 37
2427 MNTOPT_NOLARGEFILES
,
2428 #define OPT_PUBLIC 38
2430 #define OPT_DIRECTIO 39
2431 MNTOPT_FORCEDIRECTIO
,
2432 #define OPT_NODIRECTIO 40
2433 MNTOPT_NOFORCEDIRECTIO
,
2434 #define OPT_XATTR 41
2436 #define OPT_NOXATTR 42
2438 #define OPT_DEVICES 43
2440 #define OPT_NODEVICES 44
2442 #define OPT_SETUID 45
2444 #define OPT_NOSETUID 46
2448 #define OPT_NOEXEC 48
2456 return (ch
>= '0' && ch
<= '9');
2459 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2460 #define bad(val) (val == NULL || !isdigit(*val))
2468 if (!isdigit(c
= *p
)) {
2481 for (n
= '0' - c
; isdigit(c
= *++p
); ) {
2482 n
*= 10; /* two steps to avoid unnecessary overflow */
2483 n
+= '0' - c
; /* accum neg to avoid surprises at MAX */
2485 return (neg
? n
: -n
);
2489 * Default root read tsize XXX
2491 int nfs_root_rsize
= 8 * 1024; /* conservative for dumb NICs */
2492 int nfs4_root_rsize
= 32 * 1024; /* only runs on TCP be aggressive */
2495 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2497 int nfs_rootopts
= NFSMNT_NOCTO
|NFSMNT_LLOCK
|NFSMNT_INT
;
2500 init_mountopts(struct nfs_args
*args
, int version
, struct knetconfig
**dl_cf
,
2503 char servername
[SYS_NMLN
];
2504 static int first
= 0;
2505 struct netbuf server_address
;
2508 struct knetconfig
*cf
= *dl_cf
;
2509 char rootoptsbuf
[256];
2512 * Set default mount options
2514 args
->flags
= nfs_rootopts
;
2516 args
->flags
|= NFSMNT_ACREGMIN
;
2517 args
->acregmin
= ACMINMAX
;
2518 args
->flags
|= NFSMNT_ACREGMAX
;
2519 args
->acregmax
= ACMAXMAX
;
2520 args
->flags
|= NFSMNT_ACDIRMIN
;
2521 args
->acdirmin
= ACMINMAX
;
2522 args
->flags
|= NFSMNT_ACDIRMAX
;
2523 args
->acdirmax
= ACMAXMAX
;
2528 * Only look up the rootopts the first time, we store this in
2529 * a static buffer but we are guaranteed to be single threaded
2530 * and not reentrant.
2535 init_netbuf(&server_address
);
2537 if (getfile("rootopts", servername
, &server_address
,
2540 free_netbuf(&server_address
);
2543 free_netbuf(&server_address
);
2547 printf("rootopts = %s\n", rootopts
);
2550 * We have to preserve rootopts for second time.
2552 (void) strncpy(rootoptsbuf
, rootopts
, sizeof (rootoptsbuf
));
2553 rootoptsbuf
[sizeof (rootoptsbuf
) - 1] = '\0';
2558 switch (opt
= getsubopt(&opts
, optlist
, &val
)) {
2560 * Options that are defaults or meaningless so ignored
2571 case OPT_LARGEFILES
:
2577 *vfsflags
|= MS_RDONLY
;
2580 *vfsflags
&= ~(MS_RDONLY
);
2583 args
->flags
|= NFSMNT_SOFT
;
2584 args
->flags
&= ~(NFSMNT_SEMISOFT
);
2587 args
->flags
|= NFSMNT_SOFT
;
2588 args
->flags
|= NFSMNT_SEMISOFT
;
2591 args
->flags
&= ~(NFSMNT_SOFT
);
2592 args
->flags
&= ~(NFSMNT_SEMISOFT
);
2599 "nfs_dlboot: may not set root partition %s",
2603 args
->flags
|= NFSMNT_GRPID
;
2607 "nfs_dlboot: may not remount root partition");
2610 args
->flags
|= NFSMNT_INT
;
2613 args
->flags
&= ~(NFSMNT_INT
);
2616 args
->flags
|= NFSMNT_NOAC
;
2620 "nfs_dlboot: may not change root port number");
2624 "nfs_dlboot: root mounted auth_unix, secure ignored");
2627 args
->flags
|= NFSMNT_NOCTO
;
2632 "nfs_dlboot: invalid option: rsize");
2635 args
->flags
|= NFSMNT_RSIZE
;
2636 args
->rsize
= atoi(val
);
2641 "nfs_dlboot: invalid option: wsize");
2644 args
->flags
|= NFSMNT_WSIZE
;
2645 args
->wsize
= atoi(val
);
2650 "nfs_dlboot: invalid option: timeo");
2653 args
->flags
|= NFSMNT_TIMEO
;
2654 args
->timeo
= atoi(val
);
2659 "nfs_dlboot: invalid option: retrans");
2662 args
->flags
|= NFSMNT_RETRANS
;
2663 args
->retrans
= atoi(val
);
2668 "nfs_dlboot: invalid option: actimeo");
2671 args
->flags
|= NFSMNT_ACDIRMAX
;
2672 args
->flags
|= NFSMNT_ACREGMAX
;
2673 args
->flags
|= NFSMNT_ACDIRMIN
;
2674 args
->flags
|= NFSMNT_ACREGMIN
;
2675 args
->acdirmin
= args
->acregmin
= args
->acdirmax
=
2676 args
->acregmax
= atoi(val
);
2681 "nfs_dlboot: invalid option: acregmin");
2684 args
->flags
|= NFSMNT_ACREGMIN
;
2685 args
->acregmin
= atoi(val
);
2690 "nfs_dlboot: invalid option: acregmax");
2693 args
->flags
|= NFSMNT_ACREGMAX
;
2694 args
->acregmax
= atoi(val
);
2699 "nfs_dlboot: invalid option: acdirmin");
2702 args
->flags
|= NFSMNT_ACDIRMIN
;
2703 args
->acdirmin
= atoi(val
);
2708 "nfs_dlboot: invalid option: acdirmax");
2711 args
->flags
|= NFSMNT_ACDIRMAX
;
2712 args
->acdirmax
= atoi(val
);
2715 args
->flags
|= NFSMNT_LLOCK
;
2720 "nfs_dlboot: invalid option: vers");
2725 * If the requested version is less than what we
2726 * chose, pretend the chosen version doesn't exist
2728 if (vers
< version
) {
2729 return (EPROTONOSUPPORT
);
2731 if (vers
> version
) {
2733 "nfs_dlboot: version %d unavailable",
2740 * NFSv4 can only run over TCP, if they requested
2741 * UDP pretend v4 doesn't exist, they might not have
2742 * specified a version allowing a fallback to v2 or v3.
2744 if (version
== NFS_V4
&& strcmp(val
, NC_UDP
) == 0)
2745 return (EPROTONOSUPPORT
);
2747 * TCP is always chosen over UDP, so if the
2748 * requested is the same as the chosen either
2749 * they chose TCP when available or UDP on a UDP
2752 if (strcmp(cf
->knc_proto
, val
) == 0)
2755 * If we chose UDP, they must have requested TCP
2757 if (strcmp(cf
->knc_proto
, NC_TCP
) != 0) {
2759 "nfs_dlboot: TCP protocol unavailable");
2763 * They can only have requested UDP
2765 if (strcmp(val
, NC_UDP
) != 0) {
2767 "nfs_dlboot: unknown protocol");
2770 *dl_cf
= &dl_udp_netconf
;
2773 args
->flags
|= NFSMNT_NOPRINT
;
2775 case OPT_NOLARGEFILES
:
2777 "nfs_dlboot: NFS can't support nolargefiles");
2781 "nfs_dlboot: root mounted auth_unix, sec ignored");
2785 args
->flags
|= NFSMNT_DIRECTIO
;
2788 case OPT_NODIRECTIO
:
2789 args
->flags
&= ~(NFSMNT_DIRECTIO
);
2794 "nfs_dlboot: ignoring invalid option \"%s\"", val
);
2800 * Set some sane limits on read size
2802 if (!(args
->flags
& NFSMNT_RSIZE
) || args
->rsize
== 0) {
2804 * Establish defaults
2806 args
->flags
|= NFSMNT_RSIZE
;
2807 if (version
== NFS_V4
)
2808 args
->rsize
= nfs4_root_rsize
;
2810 args
->rsize
= nfs_root_rsize
;
2814 * No less than 512 bytes, otherwise it will take forever to boot
2816 if (args
->rsize
< 512)
2819 * If we are running over UDP, we cannot exceed 64KB, trim
2820 * to 56KB to allow room for headers.
2822 if (*dl_cf
== &dl_udp_netconf
&& args
->rsize
> (56 * 1024))
2823 args
->rsize
= 56 * 1024;