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.
26 #include <sys/param.h>
27 #include <sys/types.h>
28 #include <sys/systm.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>
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>
55 #include <net/route.h>
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>
64 #include <rpc/types.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>
77 #include <nfs/nfs_clnt.h>
78 #include <nfs/mount.h>
79 #include <sys/mntent.h>
82 #include <sys/sunddi.h>
83 #include <sys/sunldi.h>
84 #include <sys/esunddi.h>
86 #include <sys/errno.h>
87 #include <sys/modctl.h>
90 * RPC timers and retries
92 #define PMAP_RETRIES 5
93 #define DEFAULT_RETRIES 3
94 #define GETFILE_RETRIES 2
96 #define DEFAULT_TIMEO 3
97 #define WHOAMI_TIMEO 20
98 #define REVARP_TIMEO 5
99 #define GETFILE_TIMEO 1
102 * These are from the rpcgen'd version of mount.h XXX
104 #define MOUNTPROG 100005
105 #define MOUNTPROC_MNT 1
107 #define MOUNTVERS_POSIX 2
130 MNT3ERR_NAMETOOLONG
= 63,
131 MNT3ERR_NOTSUPP
= 10004,
132 MNT3ERR_SERVERFAULT
= 10006
135 struct mountres3_ok
{
136 struct fhandle3 fhandle
;
138 uint_t auth_flavors_len
;
139 int *auth_flavors_val
;
144 enum mountstat3 fhs_status
;
146 struct mountres3_ok mountinfo
;
151 * DLPI address format.
158 static struct modlmisc modlmisc
= {
159 &mod_miscops
, "Boot diskless"
162 static struct modlinkage modlinkage
= {
163 MODREV_1
, (void *)&modlmisc
, NULL
171 return (mod_install(&modlinkage
));
177 return (mod_remove(&modlinkage
));
181 _info(struct modinfo
*modinfop
)
183 return (mod_info(&modlinkage
, modinfop
));
187 static enum clnt_stat
pmap_rmt_call(struct knetconfig
*, struct netbuf
*,
188 bool_t
, rpcprog_t
, rpcvers_t
, rpcproc_t
, xdrproc_t
,
189 caddr_t
, xdrproc_t
, caddr_t
, struct timeval
,
191 static bool_t
myxdr_rmtcall_args(XDR
*, struct rmtcallargs
*);
192 static bool_t
myxdr_rmtcallres(XDR
*, struct rmtcallres
*);
193 static bool_t
myxdr_pmap(XDR
*, struct pmap
*);
194 static bool_t
myxdr_fhstatus(XDR
*xdrs
, struct fhstatus
*fhsp
);
195 static bool_t
myxdr_fhandle(XDR
*xdrs
, fhandle_t
*fh
);
196 static bool_t
myxdr_mountres3(XDR
*xdrs
, struct mountres3
*objp
);
197 static bool_t
myxdr_mountstat3(XDR
*xdrs
, enum mountstat3
*objp
);
198 static bool_t
myxdr_mountres3_ok(XDR
*xdrs
,
199 struct mountres3_ok
*objp
);
200 static bool_t
myxdr_fhandle3(XDR
*xdrs
, struct fhandle3
*objp
);
201 static enum clnt_stat
pmap_kgetport(struct knetconfig
*, struct netbuf
*,
202 rpcprog_t
, rpcvers_t
, rpcprot_t
);
203 static enum clnt_stat
mycallrpc(struct knetconfig
*, struct netbuf
*,
204 rpcprog_t
, rpcvers_t
, rpcproc_t
, xdrproc_t
,
205 char *, xdrproc_t
, char *, int, int);
206 static int ifioctl(TIUSER
*, int, struct netbuf
*);
207 static int getfile(char *, char *, struct netbuf
*, char *);
208 static int ping_prog(struct netbuf
*, uint_t prog
, uint_t vers
,
209 int proto
, enum clnt_stat
*);
210 static int mountnfs(struct netbuf
*, char *, char *,
212 static int mountnfs3(struct netbuf
*, char *, char *,
214 static int init_mountopts(struct nfs_args
*, int,
215 struct knetconfig
**, int *);
216 static int revarp_myaddr(TIUSER
*);
217 static void revarp_start(ldi_handle_t
, struct netbuf
*);
218 static void revarpinput(ldi_handle_t
, struct netbuf
*);
219 static void init_netbuf(struct netbuf
*);
220 static void free_netbuf(struct netbuf
*);
221 static int rtioctl(TIUSER
*, int, struct rtentry
*);
222 static void init_config(void);
224 static void cacheinit(void);
225 static int cacheinfo(char *, int, struct netbuf
*, char *, int);
226 static int dlifconfig(TIUSER
*, struct in_addr
*, struct in_addr
*,
227 struct in_addr
*, uint_t
);
228 static int setifflags(TIUSER
*, uint_t
);
230 static char *inet_ntoa(struct in_addr
);
231 static int inet_aton(char *, uchar_t
*);
232 static int isdigit(int);
235 * Should be in some common
236 * ethernet source file.
238 static struct ether_addr etherbroadcastaddr
= {
239 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
242 static struct ether_addr myether
;
245 * "ifname" is the interface name/unit as read from the boot
247 * "ndev" is the major device number of the network interface
249 * "ifunit" it the physical point of attachment for the network
250 * interface used to boot from.
252 * Both of these are initialized in "init_config()".
255 static char ifname
[IFNAMSIZ
];
256 static char ndev_path
[MAXPATHLEN
];
260 * XXX these should be shared
262 static struct knetconfig dl_udp_netconf
= {
263 NC_TPI_CLTS
, /* semantics */
264 NC_INET
, /* family */
265 NC_UDP
, /* protocol */
269 static struct knetconfig dl_tcp_netconf
= {
270 NC_TPI_COTS
, /* semantics */
271 NC_INET
, /* family */
272 NC_TCP
, /* protocol */
276 /* parameters from DHCP or bootparamd */
277 static PKT_LIST
*pl
= NULL
;
278 static uchar_t server_ip
[4];
279 static uchar_t dhcp_server_ip
[4];
280 static char *server_name_c
, *server_path_c
;
281 static char rootopts
[256];
284 * XXX Until we get the nfsmapid deadlocks all fixed, don't allow
285 * XXX a v4 root mount.
287 int nfs4_no_diskless_root_support
= 1;
290 mount_root(char *name
, char *path
, int version
, struct nfs_args
*args
,
295 struct knetconfig
*dl_cf
;
296 static int init_done
= 0;
300 printf("mount_root: name=%s\n", name
);
302 if (init_done
== 0) {
307 init_netbuf(args
->addr
);
310 rc
= getfile(name
, args
->hostname
, args
->addr
, path
);
311 } while (rc
== ETIMEDOUT
);
314 free_netbuf(args
->addr
);
318 ASSERT(args
->knconf
->knc_protofmly
!= NULL
);
319 ASSERT(args
->knconf
->knc_proto
!= NULL
);
323 rc
= mountnfs(args
->addr
, args
->hostname
, path
,
324 (fhandle_t
*)args
->fh
, &proto
);
327 rc
= mountnfs3(args
->addr
, args
->hostname
, path
,
328 (nfs_fh3
*)args
->fh
, &proto
);
331 ((struct sockaddr_in
*)args
->addr
->buf
)->sin_port
=
333 if (ping_prog(args
->addr
, NFS_PROGRAM
, NFS_V4
, IPPROTO_TCP
,
339 case RPC_PROGVERSMISMATCH
:
342 * Common failures if v4 unsupported or no TCP
344 rc
= EPROTONOSUPPORT
;
350 if (nfs4_no_diskless_root_support
)
351 rc
= EPROTONOSUPPORT
;
354 rc
= EPROTONOSUPPORT
;
363 dl_cf
= &dl_tcp_netconf
;
367 dl_cf
= &dl_udp_netconf
;
371 rc
= init_mountopts(args
, version
, &dl_cf
, vfsflags
);
374 * Copy knetconfig information from the template, note that the
375 * rdev field has been set by init_config above.
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
);
385 nfs_perror(rc
, "mount_root: mount %s:%s failed: %m\n",
386 args
->hostname
, path
);
388 printf("mount_root: leaving\n");
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.
400 mountnfs(struct netbuf
*sa
, char *server
,
401 char *path
, fhandle_t
*fh
, int *proto
)
407 printf("mountnfs: entered\n");
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.
417 stat
= pmap_kgetport(&dl_udp_netconf
, sa
, (rpcprog_t
)MOUNTPROG
,
418 (rpcvers_t
)MOUNTVERS
, (rpcprot_t
)IPPROTO_UDP
);
420 if (stat
== RPC_TIMEDOUT
) {
422 "mountnfs: %s:%s portmap not responding",
424 } else if (stat
!= RPC_SUCCESS
) {
426 "mountnfs: pmap_kgetport RPC error %d (%s).",
427 stat
, clnt_sperrno(stat
));
428 return (ENXIO
); /* XXX */
430 } while (stat
== RPC_TIMEDOUT
);
433 * The correct port number has been
434 * put into `sa' by pmap_kgetport().
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
) {
444 "mountnfs: %s:%s mount server not responding",
447 } while (stat
== RPC_TIMEDOUT
);
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 */
455 ((struct sockaddr_in
*)sa
->buf
)->sin_port
= htons(NFS_PORT
);
458 if (fhs
.fhs_status
!= 0) {
460 printf("mountnfs: fhs_status %d\n", fhs
.fhs_status
);
461 return (ENXIO
); /* XXX */
464 *proto
= IPPROTO_UDP
;
466 if (ping_prog(sa
, NFS_PROGRAM
, NFS_VERSION
, IPPROTO_TCP
, NULL
))
467 *proto
= IPPROTO_TCP
;
470 printf("mountnfs: leaving\n");
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.
480 mountnfs3(struct netbuf
*sa
, char *server
, char *path
, nfs_fh3
*fh
, int *proto
)
482 struct mountres3 mountres3
;
487 printf("mountnfs3: entered\n");
490 * Get the port number for the mount program.
491 * pmap_kgetport first tries a SunOS portmapper
492 * and, if no reply is received, will try a
493 * SVR4 rpcbind. Either way, `sa' is set to
494 * the correct address.
497 stat
= pmap_kgetport(&dl_udp_netconf
, sa
, (rpcprog_t
)MOUNTPROG
,
498 (rpcvers_t
)MOUNTVERS3
, (rpcprot_t
)IPPROTO_UDP
);
500 if (stat
== RPC_PROGVERSMISMATCH
) {
502 printf("mountnfs3: program/version mismatch\n");
503 return (EPROTONOSUPPORT
); /* XXX */
504 } else if (stat
== RPC_TIMEDOUT
) {
506 "mountnfs3: %s:%s portmap not responding",
508 } else if (stat
!= RPC_SUCCESS
) {
510 "mountnfs3: pmap_kgetport RPC error %d (%s).",
511 stat
, clnt_sperrno(stat
));
512 return (ENXIO
); /* XXX */
514 } while (stat
== RPC_TIMEDOUT
);
516 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
= NULL
;
517 mountres3
.mountres3_u
.mountinfo
.auth_flavors
.auth_flavors_val
= NULL
;
520 * The correct port number has been
521 * put into `sa' by pmap_kgetport().
524 stat
= mycallrpc(&dl_udp_netconf
, sa
, (rpcprog_t
)MOUNTPROG
,
525 (rpcvers_t
)MOUNTVERS3
, (rpcproc_t
)MOUNTPROC_MNT
,
526 xdr_bp_path_t
, (char *)&path
,
527 myxdr_mountres3
, (char *)&mountres3
,
528 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
529 if (stat
== RPC_TIMEDOUT
) {
531 "mountnfs3: %s:%s mount server not responding",
534 } while (stat
== RPC_TIMEDOUT
);
536 if (stat
== RPC_PROGVERSMISMATCH
) {
538 printf("mountnfs3: program/version mismatch\n");
539 ret
= EPROTONOSUPPORT
;
542 if (stat
!= RPC_SUCCESS
) {
543 cmn_err(CE_WARN
, "mountnfs3: RPC failed: error %d (%s).",
544 stat
, clnt_sperrno(stat
));
545 ret
= ENXIO
; /* XXX */
549 if (mountres3
.fhs_status
!= MNT_OK
) {
551 printf("mountnfs3: fhs_status %d\n",
552 mountres3
.fhs_status
);
553 ret
= ENXIO
; /* XXX */
557 ((struct sockaddr_in
*)sa
->buf
)->sin_port
= htons(NFS_PORT
);
559 *proto
= IPPROTO_UDP
;
561 if (ping_prog(sa
, NFS_PROGRAM
, NFS_V3
, IPPROTO_TCP
, NULL
)) {
562 *proto
= IPPROTO_TCP
;
565 fh
->fh3_length
= mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_len
;
566 bcopy(mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
,
567 fh
->fh3_u
.data
, fh
->fh3_length
);
570 xdr_free(myxdr_mountres3
, (caddr_t
)&mountres3
);
573 printf("mountnfs3: leaving\n");
578 ping_prog(struct netbuf
*call_addr
, uint_t prog
, uint_t vers
, int proto
,
579 enum clnt_stat
*statp
)
581 struct knetconfig
*knconf
;
583 int retries
= DEFAULT_RETRIES
;
587 knconf
= &dl_tcp_netconf
;
590 knconf
= &dl_udp_netconf
;
597 stat
= mycallrpc(knconf
, call_addr
, prog
, vers
, NULLPROC
,
598 xdr_void
, NULL
, xdr_void
, NULL
,
599 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
602 printf("ping_prog: %d return %d (%s)\n", proto
, stat
,
605 * Special case for TCP, it may "timeout" because it failed
606 * to establish an initial connection but it doesn't
607 * actually retry, so we do the retry.
608 * Persistence pays in diskless.
610 } while (stat
== RPC_TIMEDOUT
&& proto
== IPPROTO_TCP
&& retries
--);
615 if (stat
!= RPC_SUCCESS
)
620 static struct netbuf bootparam_addr
;
623 * Returns after filling in the following global variables:
634 struct bp_whoami_arg arg
;
635 struct bp_whoami_res res
;
640 int printed_waiting_msg
;
642 if ((rc
= t_kopen((file_t
*)NULL
, dl_udp_netconf
.knc_rdev
,
643 FREAD
|FWRITE
, &tiptr
, CRED())) != 0) {
644 nfs_perror(rc
, "whoami: t_kopen udp failed: %m.\n");
648 * Find out our local (IP) address.
650 if (rc
= revarp_myaddr(tiptr
)) {
651 nfs_perror(rc
, "whoami: revarp_myaddr failed: %m.\n");
652 (void) t_kclose(tiptr
, 0);
656 /* explicitly use the limited broadcast address */
658 ((struct sockaddr_in
*)sa
.buf
)->sin_family
= AF_INET
;
659 ((struct sockaddr_in
*)sa
.buf
)->sin_addr
.s_addr
=
660 htonl(INADDR_BROADCAST
);
661 sa
.len
= sizeof (struct sockaddr_in
);
664 * Pick up our local (IP) address.
667 if (rc
= ifioctl(tiptr
, SIOCGIFADDR
, &req
)) {
669 "whoami: couldn't get my IP address: %m.\n");
672 (void) t_kclose(tiptr
, 0);
677 * Set up the arguments expected by bootparamd.
679 arg
.client_address
.address_type
= IP_ADDR_TYPE
;
680 bcopy(&((struct sockaddr_in
*)req
.buf
)->sin_addr
,
681 &arg
.client_address
.bp_address
.ip_addr
, sizeof (struct in_addr
));
685 init_netbuf(&bootparam_addr
);
688 * Initial retransmission interval
690 tv
.tv_sec
= DEFAULT_TIMEO
;
692 res
.client_name
= kmem_alloc(MAX_MACHINE_NAME
+ 1, KM_SLEEP
);
693 res
.domain_name
= kmem_alloc(MAX_MACHINE_NAME
+ 1, KM_SLEEP
);
696 * Do a broadcast call to find a bootparam daemon that
697 * will tell us our hostname, domainname and any
698 * router that we have to use to talk to our NFS server.
700 printed_waiting_msg
= 0;
703 * pmap_rmt_call will first try the SunOS portmapper
704 * and if no reply is received will then try the SVR4
706 * Either way, `bootparam_addr' will be set to the
707 * correct address for the bootparamd that responds.
709 stat
= pmap_rmt_call(&dl_udp_netconf
, &sa
, TRUE
, BOOTPARAMPROG
,
710 BOOTPARAMVERS
, BOOTPARAMPROC_WHOAMI
,
711 xdr_bp_whoami_arg
, (caddr_t
)&arg
,
712 xdr_bp_whoami_res
, (caddr_t
)&res
,
713 tv
, &bootparam_addr
);
714 if (stat
== RPC_TIMEDOUT
&& !printed_waiting_msg
) {
716 "No bootparam server responding; still trying");
717 printed_waiting_msg
= 1;
720 * Retransmission interval for second and subsequent tries.
721 * We expect first pmap_rmt_call to retransmit and backoff to
722 * at least this value.
724 tv
.tv_sec
= WHOAMI_TIMEO
;
726 } while (stat
== RPC_TIMEDOUT
);
728 if (printed_waiting_msg
)
729 printf("Bootparam response received\n");
731 if (stat
!= RPC_SUCCESS
) {
732 /* XXX should get real error here */
735 "whoami: bootparam RPC failed: error %d (%s).",
736 stat
, clnt_sperrno(stat
));
740 namelen
= strlen(res
.client_name
);
741 if (namelen
> sizeof (utsname
.nodename
)) {
742 printf("whoami: hostname too long");
747 bcopy(res
.client_name
, &utsname
.nodename
, namelen
);
748 cmn_err(CE_CONT
, "?hostname: %s\n", utsname
.nodename
);
750 printf("whoami: no host name\n");
755 namelen
= strlen(res
.domain_name
);
757 if (namelen
> SYS_NMLN
) {
758 printf("whoami: domainname too long");
762 bcopy(res
.domain_name
, &srpc_domain
, namelen
);
763 cmn_err(CE_CONT
, "?domainname: %s\n", srpc_domain
);
765 printf("whoami: no domain name\n");
768 if (res
.router_address
.address_type
== IP_ADDR_TYPE
) {
769 struct rtentry rtentry
;
770 struct sockaddr_in
*sin
;
771 struct in_addr ipaddr
;
773 bcopy(&res
.router_address
.bp_address
.ip_addr
, &ipaddr
,
774 sizeof (struct in_addr
));
776 if (ipaddr
.s_addr
!= 0) {
777 sin
= (struct sockaddr_in
*)&rtentry
.rt_dst
;
778 bzero(sin
, sizeof (*sin
));
779 sin
->sin_family
= AF_INET
;
781 sin
= (struct sockaddr_in
*)&rtentry
.rt_gateway
;
782 bzero(sin
, sizeof (*sin
));
783 sin
->sin_family
= AF_INET
;
784 sin
->sin_addr
.s_addr
= ipaddr
.s_addr
;
786 rtentry
.rt_flags
= RTF_GATEWAY
| RTF_UP
;
788 if (rc
= rtioctl(tiptr
, SIOCADDRT
, &rtentry
)) {
790 "whoami: couldn't add route: %m.\n");
795 printf("whoami: unknown gateway addr family %d\n",
796 res
.router_address
.address_type
);
799 kmem_free(res
.client_name
, MAX_MACHINE_NAME
+ 1);
800 kmem_free(res
.domain_name
, MAX_MACHINE_NAME
+ 1);
802 (void) t_kclose(tiptr
, 0);
808 * 1) The ascii form of our root servers name in `server_name'.
809 * 2) Actual network address of our root server in `server_address'.
810 * 3) Whatever BOOTPARAMPROC_GETFILE returns for the fileid key, in
811 * `server_path'. If fileid is "root", it is the pathname of our
812 * root on the server.
815 getfile(char *fileid
,
816 char *server_name
, struct netbuf
*server_address
, char *server_path
)
818 struct bp_getfile_arg arg
;
819 struct bp_getfile_res res
;
822 static int using_cache
= FALSE
;
823 struct in_addr ipaddr
;
824 int timeo
= DEFAULT_TIMEO
;
825 int retries
= DEFAULT_RETRIES
;
828 printf("getfile: entered\n");
831 * Call cacheinfo() to see whether we can satisfy this request by using
832 * the information cached in memory by the boot program's DHCP
833 * implementation or boot properties rather than consult BOOTPARAMS,
834 * but while preserving the semantics of getfile(). We know that
835 * the server name is SYS_NMLN in length, and server_path is
836 * MAXPATHLEN (pn_alloc).
838 if (strcmp(fileid
, "root") == 0) {
839 if (cacheinfo(server_name
, SYS_NMLN
, server_address
,
840 server_path
, MAXPATHLEN
) == 0) {
848 * If using cache, rootopts is already available.
850 if (strcmp(fileid
, "rootopts") == 0 && using_cache
== TRUE
) {
851 return (rootopts
[0] != 0 ? 0 : ENXIO
);
854 if (bootparam_addr
.len
== 0) {
857 arg
.client_name
= (caddr_t
)&utsname
.nodename
;
858 arg
.file_id
= fileid
;
860 bzero(&res
, sizeof (res
));
861 res
.server_name
= kmem_alloc(MAX_MACHINE_NAME
+ 1, KM_SLEEP
);
862 res
.server_path
= kmem_alloc(MAX_MACHINE_NAME
+ 1, KM_SLEEP
);
865 * If we are not looking up the root file, we are looking
866 * up a non-critical option that should timeout quickly.
869 timeo
= GETFILE_TIMEO
;
870 retries
= GETFILE_RETRIES
;
874 * bootparam_addr was filled in by the call to
875 * whoami(), so now send an rpc message to the
876 * bootparam daemon requesting our server information.
877 * Use UDP to talk to bootparms.
879 stat
= mycallrpc(&dl_udp_netconf
, &bootparam_addr
,
880 (rpcprog_t
)BOOTPARAMPROG
, (rpcvers_t
)BOOTPARAMVERS
,
881 (rpcproc_t
)BOOTPARAMPROC_GETFILE
,
882 xdr_bp_getfile_arg
, (caddr_t
)&arg
,
883 xdr_bp_getfile_res
, (caddr_t
)&res
,
886 if (stat
== RPC_SUCCESS
) {
887 (void) strcpy(server_name
, res
.server_name
);
888 (void) strcpy(server_path
, res
.server_path
);
891 kmem_free(res
.server_name
, MAX_MACHINE_NAME
+ 1);
892 kmem_free(res
.server_path
, MAX_MACHINE_NAME
+ 1);
894 if (stat
!= RPC_SUCCESS
) {
896 cmn_err(CE_WARN
, "getfile: RPC failed: error %d (%s).",
897 stat
, clnt_sperrno(stat
));
898 return ((stat
== RPC_TIMEDOUT
) ? ETIMEDOUT
: ENXIO
); /* XXX */
901 if (*server_path
== '\0')
905 * If the fileid is "root", we must get back a server name, for
906 * other parameters a server name is not required
910 printf("getfile: leaving: non-root\n");
914 if (*server_name
== '\0')
917 switch (res
.server_address
.address_type
) {
920 * server_address is where we will get our root
923 ((struct sockaddr_in
*)server_address
->buf
)->sin_family
=
925 bcopy(&res
.server_address
.bp_address
.ip_addr
,
926 &ipaddr
, sizeof (ipaddr
));
927 if (ipaddr
.s_addr
== 0)
930 ((struct sockaddr_in
*)server_address
->buf
)->sin_addr
.s_addr
=
932 server_address
->len
= sizeof (struct sockaddr_in
);
936 printf("getfile: unknown address type %d\n",
937 res
.server_address
.address_type
);
938 return (EPROTONOSUPPORT
);
941 printf("getfile: leaving\n");
946 * If the boot property "bootp-response" exists, then OBP performed a
947 * successful DHCP lease acquisition for us and left the resultant ACK packet
948 * encoded at that location.
950 * If no such property exists (or the information is incomplete or garbled),
951 * the function returns -1.
958 struct in_addr braddr
;
959 struct in_addr subnet
;
962 struct sockaddr_in
*sin
;
963 static int once_only
= 0;
965 if (once_only
== 1) {
970 if (dhcack
== NULL
) {
975 printf("dhcp: dhcack %p, len %d\n", (void *)dhcack
,
979 pl
= kmem_alloc(sizeof (PKT_LIST
), KM_SLEEP
);
981 pl
->pkt
= kmem_alloc(pl
->len
, KM_SLEEP
);
982 bcopy(dhcack
, pl
->pkt
, dhcacklen
);
985 * For x86, ifname is not initialized
986 * in the netinstall case and dhcack interface name is
987 * set in strplumb(). So we only copy the name if ifname
991 (void) strlcpy(dhcifname
, ifname
, sizeof (dhcifname
));
993 /* remember the server_ip in dhcack */
994 bcopy((uchar_t
*)pl
->pkt
+ 20, dhcp_server_ip
, 4);
995 bzero(pl
->opts
, (DHCP_LAST_OPT
+ 1) * sizeof (DHCP_OPT
*));
996 bzero(pl
->vs
, (VS_OPTION_END
- VS_OPTION_START
+ 1) *
997 sizeof (DHCP_OPT
*));
999 if (dhcp_options_scan(pl
, B_TRUE
) != 0) {
1000 /* garbled packet */
1001 cmn_err(CE_WARN
, "dhcp: DHCP packet parsing failed");
1002 kmem_free(pl
->pkt
, pl
->len
);
1003 kmem_free(pl
, sizeof (PKT_LIST
));
1009 if (pl
->opts
[CD_HOSTNAME
] != NULL
) {
1010 doptp
= pl
->opts
[CD_HOSTNAME
];
1012 if (i
>= SYS_NMLN
) {
1013 cmn_err(CE_WARN
, "dhcp: Hostname is too long");
1015 bcopy(doptp
->value
, utsname
.nodename
, i
);
1016 utsname
.nodename
[i
] = '\0';
1018 printf("hostname is %s\n",
1024 /* Set NIS domain name. */
1026 if (pl
->opts
[CD_NIS_DOMAIN
] != NULL
) {
1027 doptp
= pl
->opts
[CD_NIS_DOMAIN
];
1029 p
= (caddr_t
)doptp
->value
;
1034 "dhcp: NIS domainname too long.");
1036 bcopy(p
, srpc_domain
, i
);
1037 srpc_domain
[i
] = '\0';
1039 printf("dhcp: NIS domain name is %s\n",
1045 if (pl
->opts
[CD_SUBNETMASK
] != NULL
) {
1046 doptp
= pl
->opts
[CD_SUBNETMASK
];
1047 if (doptp
->len
!= sizeof (struct in_addr
)) {
1048 pl
->opts
[CD_SUBNETMASK
] = NULL
;
1049 cmn_err(CE_WARN
, "dhcp: netmask option malformed");
1051 bcopy(doptp
->value
, &subnet
, sizeof (struct in_addr
));
1053 printf("dhcp: setting netmask to: %s\n",
1057 struct in_addr myIPaddr
;
1059 myIPaddr
.s_addr
= pl
->pkt
->yiaddr
.s_addr
;
1060 cmn_err(CE_WARN
, "dhcp: no subnet mask supplied - inferring");
1061 if (IN_CLASSA(ntohl(myIPaddr
.s_addr
)))
1062 subnet
.s_addr
= htonl(IN_CLASSA_NET
);
1063 else if (IN_CLASSB(ntohl(myIPaddr
.s_addr
)))
1064 subnet
.s_addr
= htonl(IN_CLASSB_NET
);
1065 else if (IN_CLASSC(ntohl(myIPaddr
.s_addr
)))
1066 subnet
.s_addr
= htonl(IN_CLASSC_NET
);
1067 else if (IN_CLASSD(ntohl(myIPaddr
.s_addr
)))
1068 cmn_err(CE_WARN
, "dhcp: bad IP address (%s)",
1069 inet_ntoa(myIPaddr
));
1071 subnet
.s_addr
= htonl(IN_CLASSE_NET
);
1073 /* and broadcast address */
1074 if (pl
->opts
[CD_BROADCASTADDR
] != NULL
) {
1075 doptp
= pl
->opts
[CD_BROADCASTADDR
];
1076 if (doptp
->len
!= sizeof (struct in_addr
)) {
1077 pl
->opts
[CD_BROADCASTADDR
] = NULL
;
1079 printf("dhcp: broadcast address len %d\n",
1082 bcopy(doptp
->value
, &braddr
, sizeof (struct in_addr
));
1084 printf("dhcp: setting broadcast addr to: %s\n",
1089 printf("dhcp: no broadcast address supplied\n");
1090 braddr
.s_addr
= htonl(INADDR_BROADCAST
);
1092 /* and plumb and initialize interface */
1093 if ((rc
= t_kopen((file_t
*)NULL
, dl_udp_netconf
.knc_rdev
,
1094 FREAD
|FWRITE
, &tiptr
, CRED())) == 0) {
1095 if (rc
= dlifconfig(tiptr
, &pl
->pkt
->yiaddr
, &subnet
,
1096 &braddr
, IFF_DHCPRUNNING
)) {
1097 nfs_perror(rc
, "dhcp: dlifconfig failed: %m\n");
1098 kmem_free(pl
->pkt
, pl
->len
);
1099 kmem_free(pl
, sizeof (PKT_LIST
));
1101 (void) t_kclose(tiptr
, 0);
1106 if (pl
->opts
[CD_ROUTER
] != NULL
) {
1107 doptp
= pl
->opts
[CD_ROUTER
];
1108 if ((doptp
->len
% sizeof (struct in_addr
)) != 0) {
1109 pl
->opts
[CD_ROUTER
] = NULL
;
1114 nrouters
= doptp
->len
/ sizeof (struct in_addr
);
1115 for (tp
= doptp
->value
, i
= 0; i
< nrouters
;
1117 struct in_addr defr
;
1118 struct rtentry rtentry
;
1121 sizeof (struct in_addr
));
1122 if (defr
.s_addr
== 0)
1126 sockaddr_in
*)&rtentry
.rt_dst
;
1128 bzero(sin
, sizeof (*sin
));
1129 sin
->sin_family
= AF_INET
;
1132 sockaddr_in
*)&rtentry
.rt_gateway
;
1133 bzero(sin
, sizeof (*sin
));
1134 sin
->sin_family
= AF_INET
;
1135 sin
->sin_addr
= defr
;
1137 rtentry
.rt_flags
= RTF_GATEWAY
| RTF_UP
;
1139 if (rc
= rtioctl(tiptr
, SIOCADDRT
,
1142 "dhcp: couldn't add route "
1148 printf("dhcp: added route %s\n",
1151 tp
+= sizeof (struct in_addr
);
1156 (void) t_kclose(tiptr
, 0);
1160 printf("dhcpinit: leaving\n");
1166 * Initialize nfs mount info from properties and dhcp response.
1174 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1175 DDI_PROP_DONTPASS
, BP_SERVER_PATH
, &server_path_c
);
1176 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1177 DDI_PROP_DONTPASS
, BP_SERVER_NAME
, &server_name_c
);
1178 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1179 DDI_PROP_DONTPASS
, BP_SERVER_ROOTOPTS
, &str
) == DDI_SUCCESS
) {
1180 (void) strncpy(rootopts
, str
, 255);
1183 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1184 DDI_PROP_DONTPASS
, BP_SERVER_IP
, &str
) == DDI_SUCCESS
) {
1185 if (inet_aton(str
, server_ip
) != 0)
1186 cmn_err(CE_NOTE
, "server_ipaddr %s is invalid",
1190 printf("server ip is %s\n",
1191 inet_ntoa(*(struct in_addr
*)server_ip
));
1197 /* extract root path in server_path */
1198 if (server_path_c
== NULL
) {
1199 doptp
= pl
->vs
[VS_NFSMNT_ROOTPATH
];
1201 doptp
= pl
->opts
[CD_ROOT_PATH
];
1202 if (doptp
!= NULL
) {
1207 source
= doptp
->value
;
1212 * We have to consider three cases for root path:
1213 * "nfs://server_ip/path"
1217 if (bcmp(source
, "nfs://", 6) == 0) {
1223 * Search for next char after ':' or first '/'.
1224 * Note, the '/' is part of the path, but we do
1225 * not need to preserve the ':'.
1227 for (len
= 0; len
< size
; len
++) {
1228 if (source
[len
] == c
) {
1230 str
= (char *)(&source
[++len
]);
1232 str
= (char *)(&source
[len
++]);
1239 /* Do not override server_ip from property. */
1240 if ((*(uint_t
*)server_ip
) == 0) {
1241 char *ip
= kmem_alloc(len
, KM_SLEEP
);
1242 bcopy(source
, ip
, len
);
1244 if (inet_aton((ip
), server_ip
) != 0) {
1246 "server_ipaddr %s is "
1251 printf("server ip is %s\n",
1259 str
= (char *)doptp
->value
;
1262 server_path_c
= kmem_alloc(len
+ 1, KM_SLEEP
);
1263 bcopy(str
, server_path_c
, len
);
1264 server_path_c
[len
] = '\0';
1266 printf("dhcp: root path %s\n", server_path_c
);
1268 cmn_err(CE_WARN
, "dhcp: root server path missing");
1272 /* set server_name */
1273 if (server_name_c
== NULL
) {
1274 doptp
= pl
->vs
[VS_NFSMNT_ROOTSRVR_NAME
];
1275 if (doptp
!= NULL
) {
1276 server_name_c
= kmem_alloc(doptp
->len
+ 1, KM_SLEEP
);
1277 bcopy(doptp
->value
, server_name_c
, doptp
->len
);
1278 server_name_c
[doptp
->len
] = '\0';
1280 printf("dhcp: root server name %s\n",
1283 cmn_err(CE_WARN
, "dhcp: root server name missing");
1287 /* set root server_address */
1288 if ((*(uint_t
*)server_ip
) == 0) {
1289 doptp
= pl
->vs
[VS_NFSMNT_ROOTSRVR_IP
];
1291 bcopy(doptp
->value
, server_ip
, sizeof (server_ip
));
1293 printf("dhcp: root server IP address %s\n",
1294 inet_ntoa(*(struct in_addr
*)server_ip
));
1299 "dhcp: file server ip address missing,"
1300 " fallback to dhcp server as file server");
1301 bcopy(dhcp_server_ip
, server_ip
, sizeof (server_ip
));
1305 /* set root file system mount options */
1306 if (rootopts
[0] == 0) {
1307 doptp
= pl
->vs
[VS_NFSMNT_ROOTOPTS
];
1308 if (doptp
!= NULL
&& doptp
->len
< 255) {
1309 bcopy(doptp
->value
, rootopts
, doptp
->len
);
1310 rootopts
[doptp
->len
] = '\0';
1312 printf("dhcp: rootopts %s\n", rootopts
);
1313 } else if (dldebug
) {
1314 printf("dhcp: no rootopts or too long\n");
1319 /* now we are done with pl, just free it */
1320 kmem_free(pl
->pkt
, pl
->len
);
1321 kmem_free(pl
, sizeof (PKT_LIST
));
1326 cacheinfo(char *name
, int namelen
,
1327 struct netbuf
*server_address
, char *rootpath
, int pathlen
)
1329 static int init_done
= 0;
1330 struct sockaddr_in
*sin
;
1332 if (init_done
== 0) {
1337 /* server_path is a reliable indicator of cache availability */
1338 if (server_path_c
== NULL
)
1341 (void) strncpy(rootpath
, server_path_c
, pathlen
);
1342 if (server_name_c
) {
1343 (void) strncpy(name
, server_name_c
, namelen
);
1345 (void) strncpy(name
, "unknown", namelen
);
1348 sin
= (struct sockaddr_in
*)server_address
->buf
;
1349 sin
->sin_family
= AF_INET
;
1350 server_address
->len
= sizeof (struct sockaddr_in
);
1351 bcopy(server_ip
, &sin
->sin_addr
, sizeof (struct in_addr
));
1356 * Set this interface's IP address and netmask, and bring it up.
1359 dlifconfig(TIUSER
*tiptr
, struct in_addr
*myIPaddr
, struct in_addr
*mymask
,
1360 struct in_addr
*mybraddr
, uint_t flags
)
1364 struct sockaddr_in sin
;
1367 printf("dlifconfig: entered\n");
1368 printf("dlifconfig: addr %s\n", inet_ntoa(*myIPaddr
));
1369 printf("dlifconfig: mask %s\n", inet_ntoa(*mymask
));
1370 printf("dlifconfig: broadcast %s\n", inet_ntoa(*mybraddr
));
1373 bcopy(myIPaddr
, &sin
.sin_addr
, sizeof (struct in_addr
));
1374 sin
.sin_family
= AF_INET
;
1375 sbuf
.buf
= (caddr_t
)&sin
;
1376 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1377 if (rc
= ifioctl(tiptr
, SIOCSIFADDR
, &sbuf
)) {
1379 "dlifconfig: couldn't set interface net address: %m\n");
1383 if (mybraddr
->s_addr
!= INADDR_BROADCAST
) {
1384 bcopy(mybraddr
, &sin
.sin_addr
, sizeof (struct in_addr
));
1385 sin
.sin_family
= AF_INET
;
1386 sbuf
.buf
= (caddr_t
)&sin
;
1387 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1388 if (rc
= ifioctl(tiptr
, SIOCSIFBRDADDR
, &sbuf
)) {
1390 "dlifconfig: couldn't set interface broadcast addr: %m\n");
1395 bcopy(mymask
, &sin
.sin_addr
, sizeof (struct in_addr
));
1396 sin
.sin_family
= AF_INET
;
1397 sbuf
.buf
= (caddr_t
)&sin
;
1398 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1399 if (rc
= ifioctl(tiptr
, SIOCSIFNETMASK
, &sbuf
)) {
1401 "dlifconfig: couldn't set interface net address: %m\n");
1406 * Now turn on the interface.
1408 if (rc
= setifflags(tiptr
, IFF_UP
| flags
)) {
1410 "dlifconfig: couldn't enable network interface: %m\n");
1415 printf("dlifconfig: returned\n");
1420 inet_ntoa(struct in_addr in
)
1425 p
= (unsigned char *)&in
;
1426 (void) sprintf(b
, "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
1430 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1432 inet_aton(char *ipstr
, uchar_t
*ip
)
1435 uchar_t val
[4] = {0};
1444 val
[i
] = val
[i
] * 10 + (c
- '0');
1460 #define MAX_ADDR_SIZE 128
1463 * Initialize a netbuf suitable for
1464 * describing an address for the
1465 * transport defined by `tiptr'.
1468 init_netbuf(struct netbuf
*nbuf
)
1470 nbuf
->buf
= kmem_zalloc(MAX_ADDR_SIZE
, KM_SLEEP
);
1471 nbuf
->maxlen
= MAX_ADDR_SIZE
;
1476 free_netbuf(struct netbuf
*nbuf
)
1478 kmem_free(nbuf
->buf
, nbuf
->maxlen
);
1485 rtioctl(TIUSER
*tiptr
, int cmd
, struct rtentry
*rtentry
)
1487 struct strioctl iocb
;
1493 iocb
.ic_len
= sizeof (struct rtentry
);
1494 iocb
.ic_dp
= (caddr_t
)rtentry
;
1496 vp
= tiptr
->fp
->f_vnode
;
1497 rc
= kstr_ioctl(vp
, I_STR
, (intptr_t)&iocb
);
1499 nfs_perror(rc
, "rtioctl: kstr_ioctl failed: %m\n");
1504 * Send an ioctl down the stream defined
1507 * We isolate the ifreq dependencies in here. The
1508 * ioctl really ought to take a netbuf and be of
1509 * type TRANSPARENT - one day.
1512 ifioctl(TIUSER
*tiptr
, int cmd
, struct netbuf
*nbuf
)
1514 struct strioctl iocb
;
1520 * Now do the one requested.
1523 ifr
.ifr_addr
= *(struct sockaddr
*)nbuf
->buf
;
1524 (void) strncpy((caddr_t
)&ifr
.ifr_name
, ifname
, sizeof (ifr
.ifr_name
));
1527 iocb
.ic_len
= sizeof (ifr
);
1528 iocb
.ic_dp
= (caddr_t
)&ifr
;
1530 vp
= tiptr
->fp
->f_vnode
;
1531 rc
= kstr_ioctl(vp
, I_STR
, (intptr_t)&iocb
);
1533 nfs_perror(rc
, "ifioctl: kstr_ioctl failed: %m\n");
1540 if (nbuf
->len
== 0) {
1544 nbuf
->len
= sizeof (struct sockaddr
);
1545 *(struct sockaddr
*)nbuf
->buf
= ifr
.ifr_addr
;
1552 setifflags(TIUSER
*tiptr
, uint_t value
)
1556 struct strioctl iocb
;
1558 (void) strncpy((caddr_t
)&ifr
.ifr_name
, ifname
, sizeof (ifr
.ifr_name
));
1559 iocb
.ic_cmd
= SIOCGIFFLAGS
;
1561 iocb
.ic_len
= sizeof (ifr
);
1562 iocb
.ic_dp
= (caddr_t
)&ifr
;
1563 if (rc
= kstr_ioctl(tiptr
->fp
->f_vnode
, I_STR
, (intptr_t)&iocb
))
1566 ifr
.ifr_flags
|= value
;
1567 iocb
.ic_cmd
= SIOCSIFFLAGS
;
1568 return (kstr_ioctl(tiptr
->fp
->f_vnode
, I_STR
, (intptr_t)&iocb
));
1572 * REVerse Address Resolution Protocol (revarp)
1573 * is used by a diskless client to find out its
1574 * IP address when all it knows is its Ethernet address.
1576 * Open the ethernet driver, attach and bind
1577 * (DL_BIND_REQ) it, and then format a broadcast RARP
1578 * message for it to send. We pick up the reply and
1579 * let the caller set the interface address using SIOCSIFADDR.
1582 revarp_myaddr(TIUSER
*tiptr
)
1586 struct sockaddr_in sin
;
1590 struct netbuf myaddr
= {0, 0, NULL
};
1593 printf("revarp_myaddr: entered\n");
1595 if (rc
= ldi_ident_from_mod(&modlinkage
, &li
)) {
1597 "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1601 rc
= ldi_open_by_name(ndev_path
, FREAD
|FWRITE
, CRED(), &lh
, li
);
1602 ldi_ident_release(li
);
1605 "revarp_myaddr: ldi_open_by_name failed: %m\n");
1609 if (rc
= dl_attach(lh
, ifunit
, NULL
)) {
1610 nfs_perror(rc
, "revarp_myaddr: dl_attach failed: %m\n");
1611 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1615 if (rc
= dl_bind(lh
, ETHERTYPE_REVARP
, NULL
)) {
1616 nfs_perror(rc
, "revarp_myaddr: dl_bind failed: %m\n");
1617 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1621 if (rc
= dl_info(lh
, &info
, NULL
, NULL
, NULL
)) {
1622 nfs_perror(rc
, "revarp_myaddr: dl_info failed: %m\n");
1623 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1627 /* Initialize myaddr */
1628 myaddr
.maxlen
= info
.dl_addr_length
;
1629 myaddr
.buf
= kmem_alloc(myaddr
.maxlen
, KM_SLEEP
);
1631 revarp_start(lh
, &myaddr
);
1633 bcopy(myaddr
.buf
, &sin
.sin_addr
, myaddr
.len
);
1634 sin
.sin_family
= AF_INET
;
1636 sbuf
.buf
= (caddr_t
)&sin
;
1637 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1638 if (rc
= ifioctl(tiptr
, SIOCSIFADDR
, &sbuf
)) {
1640 "revarp_myaddr: couldn't set interface net address: %m\n");
1641 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1642 kmem_free(myaddr
.buf
, myaddr
.maxlen
);
1646 /* Now turn on the interface */
1647 if (rc
= setifflags(tiptr
, IFF_UP
)) {
1649 "revarp_myaddr: couldn't enable network interface: %m\n");
1652 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1653 kmem_free(myaddr
.buf
, myaddr
.maxlen
);
1658 revarp_start(ldi_handle_t lh
, struct netbuf
*myaddr
)
1660 struct ether_arp
*ea
;
1662 dl_unitdata_req_t
*dl_udata
;
1665 struct dladdr
*dlsap
;
1666 static int done
= 0;
1667 size_t addrlen
= ETHERADDRL
;
1669 if (dl_phys_addr(lh
, (uchar_t
*)&myether
, &addrlen
, NULL
) != 0 ||
1670 addrlen
!= ETHERADDRL
) {
1671 /* Fallback using per-node address */
1672 (void) localetheraddr(NULL
, &myether
);
1673 cmn_err(CE_CONT
, "?DLPI failed to get Ethernet address. Using "
1674 "system wide Ethernet address %s\n",
1675 ether_sprintf(&myether
));
1679 if (myaddr
->len
!= 0) {
1680 cmn_err(CE_CONT
, "?Found my IP address: %x (%d.%d.%d.%d)\n",
1681 *(int *)myaddr
->buf
,
1682 (uchar_t
)myaddr
->buf
[0], (uchar_t
)myaddr
->buf
[1],
1683 (uchar_t
)myaddr
->buf
[2], (uchar_t
)myaddr
->buf
[3]);
1688 cmn_err(CE_CONT
, "?Requesting Internet address for %s\n",
1689 ether_sprintf(&myether
));
1692 * Send another RARP request.
1694 if ((mp
= allocb(sizeof (dl_unitdata_req_t
) + sizeof (*dlsap
),
1695 BPRI_HI
)) == NULL
) {
1696 cmn_err(CE_WARN
, "revarp_myaddr: allocb no memory");
1699 if ((bp
= allocb(sizeof (struct ether_arp
), BPRI_HI
)) == NULL
) {
1700 cmn_err(CE_WARN
, "revarp_myaddr: allocb no memory");
1705 * Format the transmit request part.
1707 mp
->b_datap
->db_type
= M_PROTO
;
1708 dl_udata
= (dl_unitdata_req_t
*)mp
->b_wptr
;
1709 mp
->b_wptr
+= sizeof (dl_unitdata_req_t
) + sizeof (*dlsap
);
1710 dl_udata
->dl_primitive
= DL_UNITDATA_REQ
;
1711 dl_udata
->dl_dest_addr_length
= sizeof (*dlsap
);
1712 dl_udata
->dl_dest_addr_offset
= sizeof (*dl_udata
);
1713 dl_udata
->dl_priority
.dl_min
= 0;
1714 dl_udata
->dl_priority
.dl_max
= 0;
1716 dlsap
= (struct dladdr
*)(mp
->b_rptr
+ sizeof (*dl_udata
));
1717 bcopy(ðerbroadcastaddr
, &dlsap
->dl_phys
,
1718 sizeof (etherbroadcastaddr
));
1719 dlsap
->dl_sap
= ETHERTYPE_REVARP
;
1722 * Format the actual REVARP request.
1724 bzero(bp
->b_wptr
, sizeof (struct ether_arp
));
1725 ea
= (struct ether_arp
*)bp
->b_wptr
;
1726 bp
->b_wptr
+= sizeof (struct ether_arp
);
1727 ea
->arp_hrd
= htons(ARPHRD_ETHER
);
1728 ea
->arp_pro
= htons(ETHERTYPE_IP
);
1729 ea
->arp_hln
= sizeof (ea
->arp_sha
); /* hardware address length */
1730 ea
->arp_pln
= sizeof (ea
->arp_spa
); /* protocol address length */
1731 ea
->arp_op
= htons(REVARP_REQUEST
);
1732 ether_copy(&myether
, &ea
->arp_sha
);
1733 ether_copy(&myether
, &ea
->arp_tha
);
1737 if ((rc
= ldi_putmsg(lh
, mp
)) != 0) {
1738 nfs_perror(rc
, "revarp_start: ldi_putmsg failed: %m\n");
1741 revarpinput(lh
, myaddr
);
1747 * Client side Reverse-ARP input
1748 * Server side is handled by user level server
1751 revarpinput(ldi_handle_t lh
, struct netbuf
*myaddr
)
1753 struct ether_arp
*ea
;
1757 timestruc_t tv
, give_up
, now
;
1760 * Choose the time at which we will give up, and resend our
1763 gethrestime(&give_up
);
1764 give_up
.tv_sec
+= REVARP_TIMEO
;
1767 * Compute new timeout value.
1771 timespecsub(&tv
, &now
);
1773 * If we don't have at least one full second remaining, give up.
1774 * This means we might wait only just over 4.0 seconds, but that's
1779 rc
= ldi_getmsg(lh
, &mp
, &tv
);
1782 } else if (rc
!= 0) {
1783 nfs_perror(rc
, "revarpinput: ldi_getmsg failed: %m\n");
1787 if (mp
->b_cont
== NULL
) {
1788 printf("revarpinput: b_cont == NULL\n");
1792 if (mp
->b_datap
->db_type
!= M_PROTO
) {
1793 printf("revarpinput: bad header type %d\n",
1794 mp
->b_datap
->db_type
);
1800 if (bp
->b_wptr
- bp
->b_rptr
< sizeof (*ea
)) {
1801 printf("revarpinput: bad data len %d, expect %d\n",
1802 (int)(bp
->b_wptr
- bp
->b_rptr
), (int)sizeof (*ea
));
1806 ea
= (struct ether_arp
*)bp
->b_rptr
;
1808 if ((ushort_t
)ntohs(ea
->arp_pro
) != ETHERTYPE_IP
) {
1809 /* We could have received another broadcast arp packet. */
1811 printf("revarpinput: bad type %x\n",
1812 (ushort_t
)ntohs(ea
->arp_pro
));
1816 if ((ushort_t
)ntohs(ea
->arp_op
) != REVARP_REPLY
) {
1817 /* We could have received a broadcast arp request. */
1819 printf("revarpinput: bad op %x\n",
1820 (ushort_t
)ntohs(ea
->arp_op
));
1825 if (!ether_cmp(&ea
->arp_tha
, &myether
)) {
1826 bcopy(&ea
->arp_tpa
, myaddr
->buf
, sizeof (ea
->arp_tpa
));
1827 myaddr
->len
= sizeof (ea
->arp_tpa
);
1829 /* We could have gotten a broadcast arp response. */
1831 printf("revarpinput: got reply, but not my address\n");
1840 * From rpcsvc/mountxdr.c in SunOS. We can't
1841 * put this into the rpc directory because
1842 * it calls xdr_fhandle() which is in a
1846 myxdr_fhstatus(XDR
*xdrs
, struct fhstatus
*fhsp
)
1849 if (!xdr_int(xdrs
, &fhsp
->fhs_status
))
1851 if (fhsp
->fhs_status
== 0) {
1852 if (!myxdr_fhandle(xdrs
, &fhsp
->fhs_fh
))
1861 * File access handle
1862 * The fhandle struct is treated a opaque data on the wire
1865 myxdr_fhandle(XDR
*xdrs
, fhandle_t
*fh
)
1867 return (xdr_opaque(xdrs
, (caddr_t
)fh
, NFS_FHSIZE
));
1871 myxdr_mountres3(XDR
*xdrs
, struct mountres3
*objp
)
1873 if (!myxdr_mountstat3(xdrs
, &objp
->fhs_status
))
1875 switch (objp
->fhs_status
) {
1877 if (!myxdr_mountres3_ok(xdrs
, &objp
->mountres3_u
.mountinfo
))
1887 myxdr_mountstat3(XDR
*xdrs
, enum mountstat3
*objp
)
1889 return (xdr_enum(xdrs
, (enum_t
*)objp
));
1893 myxdr_mountres3_ok(XDR
*xdrs
, struct mountres3_ok
*objp
)
1895 if (!myxdr_fhandle3(xdrs
, &objp
->fhandle
))
1897 if (!xdr_array(xdrs
, (char **)&objp
->auth_flavors
.auth_flavors_val
,
1898 (uint_t
*)&objp
->auth_flavors
.auth_flavors_len
, ~0,
1899 sizeof (int), (xdrproc_t
)xdr_int
))
1905 myxdr_fhandle3(XDR
*xdrs
, struct fhandle3
*objp
)
1907 return (xdr_bytes(xdrs
, (char **)&objp
->fhandle3_val
,
1908 (uint_t
*)&objp
->fhandle3_len
, FHSIZE3
));
1912 * From SunOS pmap_clnt.c
1914 * Port mapper routines:
1915 * pmap_kgetport() - get port number.
1916 * pmap_rmt_call() - indirect call via port mapper.
1919 static enum clnt_stat
1920 pmap_kgetport(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
1921 rpcprog_t prog
, rpcvers_t vers
, rpcprot_t prot
)
1925 enum clnt_stat stat
;
1926 struct pmap pmap_parms
;
1932 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= htons(PMAPPORT
);
1934 pmap_parms
.pm_prog
= prog
;
1935 pmap_parms
.pm_vers
= vers
;
1936 pmap_parms
.pm_prot
= prot
;
1937 pmap_parms
.pm_port
= 0;
1938 for (tries
= 0; tries
< 5; tries
++) {
1939 stat
= mycallrpc(knconf
, call_addr
,
1940 PMAPPROG
, PMAPVERS
, PMAPPROC_GETPORT
,
1941 myxdr_pmap
, (char *)&pmap_parms
,
1942 xdr_u_short
, (char *)&port
,
1943 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
1945 if (stat
!= RPC_TIMEDOUT
)
1948 "pmap_kgetport: Portmapper not responding; still trying");
1951 if (stat
== RPC_PROGUNAVAIL
) {
1953 "pmap_kgetport: Portmapper failed - trying rpcbind");
1955 rpcb_parms
.r_prog
= prog
;
1956 rpcb_parms
.r_vers
= vers
;
1957 rpcb_parms
.r_netid
= knconf
->knc_proto
;
1958 rpcb_parms
.r_addr
= rpcb_parms
.r_owner
= "";
1960 for (tries
= 0; tries
< 5; tries
++) {
1961 stat
= mycallrpc(knconf
, call_addr
,
1962 RPCBPROG
, RPCBVERS
, RPCBPROC_GETADDR
,
1963 xdr_rpcb
, (char *)&rpcb_parms
,
1964 xdr_wrapstring
, (char *)&ua
,
1965 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
1967 if (stat
!= RPC_TIMEDOUT
)
1970 "pmap_kgetport: rpcbind not responding; still trying");
1973 if (stat
== RPC_SUCCESS
) {
1974 if ((ua
!= NULL
) && (ua
[0] != '\0')) {
1975 port
= rpc_uaddr2port(AF_INET
, ua
);
1977 /* Address unknown */
1978 stat
= RPC_PROGUNAVAIL
;
1983 if (stat
== RPC_SUCCESS
)
1984 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= ntohs(port
);
1990 * pmapper remote-call-service interface.
1991 * This routine is used to call the pmapper remote call service
1992 * which will look up a service program in the port maps, and then
1993 * remotely call that routine with the given parameters. This allows
1994 * programs to do a lookup and call in one step. In addition to the call_addr,
1995 * the caller provides a boolean hint about the destination address (TRUE if
1996 * address is a broadcast address, FALSE otherwise).
1998 * On return, `call addr' contains the port number for the
1999 * service requested, and `resp_addr' contains its IP address.
2001 static enum clnt_stat
2002 pmap_rmt_call(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
2003 bool_t bcast
, rpcprog_t progn
, rpcvers_t versn
, rpcproc_t procn
,
2004 xdrproc_t xdrargs
, caddr_t argsp
, xdrproc_t xdrres
, caddr_t resp
,
2005 struct timeval tout
, struct netbuf
*resp_addr
)
2008 enum clnt_stat stat
;
2011 struct rmtcallargs pmap_args
;
2012 struct rmtcallres pmap_res
;
2013 struct rpcb_rmtcallargs rpcb_args
;
2014 struct rpcb_rmtcallres rpcb_res
;
2015 char ua
[100]; /* XXX */
2017 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= htons(PMAPPORT
);
2019 rc
= clnt_tli_kcreate(knconf
, call_addr
, PMAPPROG
, PMAPVERS
,
2020 0, PMAP_RETRIES
, CRED(), &cl
);
2023 "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2024 return (RPC_SYSTEMERROR
); /* XXX */
2026 if (cl
== (CLIENT
*)NULL
) {
2027 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2031 (void) CLNT_CONTROL(cl
, CLSET_BCAST
, (char *)&bcast
);
2033 pmap_args
.prog
= progn
;
2034 pmap_args
.vers
= versn
;
2035 pmap_args
.proc
= procn
;
2036 pmap_args
.args_ptr
= argsp
;
2037 pmap_args
.xdr_args
= xdrargs
;
2038 pmap_res
.port_ptr
= &port
;
2039 pmap_res
.results_ptr
= resp
;
2040 pmap_res
.xdr_results
= xdrres
;
2041 stat
= clnt_clts_kcallit_addr(cl
, PMAPPROC_CALLIT
,
2042 myxdr_rmtcall_args
, (caddr_t
)&pmap_args
,
2043 myxdr_rmtcallres
, (caddr_t
)&pmap_res
,
2046 if (stat
== RPC_SUCCESS
) {
2047 ((struct sockaddr_in
*)resp_addr
->buf
)->sin_port
=
2048 htons((ushort_t
)port
);
2052 if (stat
!= RPC_PROGUNAVAIL
)
2055 cmn_err(CE_WARN
, "pmap_rmt_call: Portmapper failed - trying rpcbind");
2057 rc
= clnt_tli_kcreate(knconf
, call_addr
, RPCBPROG
, RPCBVERS
,
2058 0, PMAP_RETRIES
, CRED(), &cl
);
2060 nfs_perror(rc
, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2061 return (RPC_SYSTEMERROR
); /* XXX */
2065 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2069 rpcb_args
.prog
= progn
;
2070 rpcb_args
.vers
= versn
;
2071 rpcb_args
.proc
= procn
;
2072 rpcb_args
.args_ptr
= argsp
;
2073 rpcb_args
.xdr_args
= xdrargs
;
2074 rpcb_res
.addr_ptr
= ua
;
2075 rpcb_res
.results_ptr
= resp
;
2076 rpcb_res
.xdr_results
= xdrres
;
2077 stat
= clnt_clts_kcallit_addr(cl
, PMAPPROC_CALLIT
,
2078 xdr_rpcb_rmtcallargs
, (caddr_t
)&rpcb_args
,
2079 xdr_rpcb_rmtcallres
, (caddr_t
)&rpcb_res
,
2082 if (stat
== RPC_SUCCESS
)
2083 ((struct sockaddr_in
*)resp_addr
->buf
)->sin_port
=
2084 rpc_uaddr2port(AF_INET
, ua
);
2091 * XDR remote call arguments
2092 * written for XDR_ENCODE direction only
2095 myxdr_rmtcall_args(XDR
*xdrs
, struct rmtcallargs
*cap
)
2101 if (xdr_rpcprog(xdrs
, &(cap
->prog
)) &&
2102 xdr_rpcvers(xdrs
, &(cap
->vers
)) &&
2103 xdr_rpcproc(xdrs
, &(cap
->proc
))) {
2104 lenposition
= XDR_GETPOS(xdrs
);
2105 if (!xdr_u_int(xdrs
, &cap
->arglen
))
2107 argposition
= XDR_GETPOS(xdrs
);
2108 if (!(*(cap
->xdr_args
))(xdrs
, cap
->args_ptr
))
2110 position
= XDR_GETPOS(xdrs
);
2111 cap
->arglen
= (uint_t
)position
- (uint_t
)argposition
;
2112 XDR_SETPOS(xdrs
, lenposition
);
2113 if (!xdr_u_int(xdrs
, &cap
->arglen
))
2115 XDR_SETPOS(xdrs
, position
);
2122 * XDR remote call results
2123 * written for XDR_DECODE direction only
2126 myxdr_rmtcallres(XDR
*xdrs
, struct rmtcallres
*crp
)
2130 port_ptr
= (caddr_t
)crp
->port_ptr
;
2131 if (xdr_reference(xdrs
, &port_ptr
, sizeof (uint_t
), xdr_u_int
) &&
2132 xdr_u_int(xdrs
, &crp
->resultslen
)) {
2133 crp
->port_ptr
= (rpcport_t
*)port_ptr
;
2134 return ((*(crp
->xdr_results
))(xdrs
, crp
->results_ptr
));
2140 myxdr_pmap(XDR
*xdrs
, struct pmap
*regs
)
2142 if (xdr_rpcprog(xdrs
, ®s
->pm_prog
) &&
2143 xdr_rpcvers(xdrs
, ®s
->pm_vers
) &&
2144 xdr_rpcprot(xdrs
, ®s
->pm_prot
))
2145 return (xdr_rpcport(xdrs
, ®s
->pm_port
));
2151 * From SunOS callrpc.c
2153 static enum clnt_stat
2154 mycallrpc(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
2155 rpcprog_t prognum
, rpcvers_t versnum
, rpcproc_t procnum
,
2156 xdrproc_t inproc
, char *in
, xdrproc_t outproc
, char *out
,
2157 int timeo
, int retries
)
2161 enum clnt_stat cl_stat
;
2164 rc
= clnt_tli_kcreate(knconf
, call_addr
, prognum
, versnum
,
2165 0, retries
, CRED(), &cl
);
2167 nfs_perror(rc
, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2168 return (RPC_SYSTEMERROR
); /* XXX */
2172 cl_stat
= CLNT_CALL(cl
, procnum
, inproc
, in
, outproc
, out
, tv
);
2173 AUTH_DESTROY(cl
->cl_auth
);
2179 * Configure the 'default' interface based on existing boot properties.
2185 struct in_addr my_ip
, my_netmask
, my_router
, my_broadcast
;
2186 struct sockaddr_in
*sin
;
2189 struct rtentry rtentry
;
2191 my_ip
.s_addr
= my_netmask
.s_addr
= my_router
.s_addr
= 0;
2194 * No way of getting this right now. Collude with dlifconfig()
2195 * to let the protocol stack choose.
2197 my_broadcast
.s_addr
= INADDR_BROADCAST
;
2199 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2200 DDI_PROP_DONTPASS
, BP_HOST_IP
, &str
) == DDI_SUCCESS
) {
2201 if (inet_aton(str
, (uchar_t
*)&my_ip
) != 0)
2202 cmn_err(CE_NOTE
, "host-ip %s is invalid\n",
2206 printf("host ip is %s\n",
2209 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2210 DDI_PROP_DONTPASS
, BP_SUBNET_MASK
, &str
) == DDI_SUCCESS
) {
2211 if (inet_aton(str
, (uchar_t
*)&my_netmask
) != 0)
2212 cmn_err(CE_NOTE
, "subnet-mask %s is invalid\n",
2216 printf("subnet mask is %s\n",
2217 inet_ntoa(my_netmask
));
2219 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2220 DDI_PROP_DONTPASS
, BP_ROUTER_IP
, &str
) == DDI_SUCCESS
) {
2221 if (inet_aton(str
, (uchar_t
*)&my_router
) != 0)
2222 cmn_err(CE_NOTE
, "router-ip %s is invalid\n",
2226 printf("router ip is %s\n",
2227 inet_ntoa(my_router
));
2229 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2230 DDI_PROP_DONTPASS
, BP_SERVER_PATH
, &server_path_c
);
2231 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2232 DDI_PROP_DONTPASS
, BP_SERVER_NAME
, &server_name_c
);
2233 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2234 DDI_PROP_DONTPASS
, BP_SERVER_ROOTOPTS
, &str
) == DDI_SUCCESS
) {
2235 (void) strlcpy(rootopts
, str
, sizeof (rootopts
));
2238 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2239 DDI_PROP_DONTPASS
, BP_SERVER_IP
, &str
) == DDI_SUCCESS
) {
2240 if (inet_aton(str
, server_ip
) != 0)
2241 cmn_err(CE_NOTE
, "server-ip %s is invalid\n",
2245 printf("server ip is %s\n",
2246 inet_ntoa(*(struct in_addr
*)server_ip
));
2250 * We need all of these to configure based on properties.
2252 if ((my_ip
.s_addr
== 0) ||
2253 (my_netmask
.s_addr
== 0) ||
2254 (server_path_c
== NULL
) ||
2255 (server_name_c
== NULL
) ||
2256 (*(uint_t
*)server_ip
== 0))
2259 cmn_err(CE_CONT
, "?IP address: %s\n", inet_ntoa(my_ip
));
2260 cmn_err(CE_CONT
, "?IP netmask: %s\n", inet_ntoa(my_netmask
));
2261 if (my_router
.s_addr
!= 0)
2262 cmn_err(CE_CONT
, "?IP router: %s\n", inet_ntoa(my_router
));
2263 cmn_err(CE_CONT
, "?NFS server: %s (%s)\n", server_name_c
,
2264 inet_ntoa(*(struct in_addr
*)server_ip
));
2265 cmn_err(CE_CONT
, "?NFS path: %s\n", server_path_c
);
2268 * Configure the interface.
2270 if ((rc
= t_kopen((file_t
*)NULL
, dl_udp_netconf
.knc_rdev
,
2271 FREAD
|FWRITE
, &tiptr
, CRED())) != 0) {
2272 nfs_perror(rc
, "bp_netconfig: t_kopen udp failed: %m.\n");
2276 if ((rc
= dlifconfig(tiptr
, &my_ip
, &my_netmask
, &my_broadcast
,
2278 nfs_perror(rc
, "bp_netconfig: dlifconfig failed: %m.\n");
2279 (void) t_kclose(tiptr
, 0);
2283 if (my_router
.s_addr
!= 0) {
2285 * Add a default route.
2287 sin
= (struct sockaddr_in
*)&rtentry
.rt_dst
;
2288 bzero(sin
, sizeof (*sin
));
2289 sin
->sin_family
= AF_INET
;
2291 sin
= (struct sockaddr_in
*)&rtentry
.rt_gateway
;
2292 bzero(sin
, sizeof (*sin
));
2293 sin
->sin_family
= AF_INET
;
2294 sin
->sin_addr
= my_router
;
2296 rtentry
.rt_flags
= RTF_GATEWAY
| RTF_UP
;
2298 if ((rc
= rtioctl(tiptr
, SIOCADDRT
, &rtentry
)) != 0) {
2300 "bp_netconfig: couldn't add route: %m.\n");
2301 (void) t_kclose(tiptr
, 0);
2306 (void) t_kclose(tiptr
, 0);
2312 * The network device we will use to boot from is plumbed. Extract the details
2318 (void) strlcpy(ndev_path
, rootfs
.bo_devname
, sizeof (ndev_path
));
2319 (void) strlcpy(ifname
, rootfs
.bo_ifname
, sizeof (ifname
));
2320 ifunit
= rootfs
.bo_ppa
;
2323 * Assumes only one linkage array element.
2325 dl_udp_netconf
.knc_rdev
=
2326 makedevice(clone_major
, ddi_name_to_major("udp"));
2327 dl_tcp_netconf
.knc_rdev
=
2328 makedevice(clone_major
, ddi_name_to_major("tcp"));
2331 * Now we bringup the interface.
2332 * Try cached dhcp response first. If it fails, do rarp.
2334 if ((bp_netconfig() != 0) &&
2335 (dhcpinit() != 0) &&
2338 "%s: no response from interface", ifname
);
2340 printf("init_config: ifname %s is up\n", ifname
);
2344 * These options are duplicated in cmd/fs.d/nfs/mount/mount.c
2345 * Changes must be made to both lists.
2347 static char *optlist
[] = {
2354 #define OPT_NOQUOTA 3
2362 #define OPT_NOSUID 7
2366 #define OPT_REMOUNT 9
2368 #define OPT_NOSUB 10
2372 #define OPT_NOINTR 12
2376 #define OPT_SECURE 14
2378 #define OPT_RSIZE 15
2380 #define OPT_WSIZE 16
2382 #define OPT_TIMEO 17
2384 #define OPT_RETRANS 18
2386 #define OPT_ACTIMEO 19
2388 #define OPT_ACREGMIN 20
2390 #define OPT_ACREGMAX 21
2392 #define OPT_ACDIRMIN 22
2394 #define OPT_ACDIRMAX 23
2400 #define OPT_RETRY 26
2404 #define OPT_NOCTO 28
2406 #define OPT_LLOCK 29
2408 #define OPT_POSIX 30
2412 #define OPT_PROTO 32
2414 #define OPT_SEMISOFT 33
2416 #define OPT_NOPRINT 34
2420 #define OPT_LARGEFILES 36
2422 #define OPT_NOLARGEFILES 37
2423 MNTOPT_NOLARGEFILES
,
2424 #define OPT_PUBLIC 38
2426 #define OPT_DIRECTIO 39
2427 MNTOPT_FORCEDIRECTIO
,
2428 #define OPT_NODIRECTIO 40
2429 MNTOPT_NOFORCEDIRECTIO
,
2430 #define OPT_XATTR 41
2432 #define OPT_NOXATTR 42
2434 #define OPT_DEVICES 43
2436 #define OPT_NODEVICES 44
2438 #define OPT_SETUID 45
2440 #define OPT_NOSETUID 46
2444 #define OPT_NOEXEC 48
2452 return (ch
>= '0' && ch
<= '9');
2455 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2456 #define bad(val) (val == NULL || !isdigit(*val))
2464 if (!isdigit(c
= *p
)) {
2477 for (n
= '0' - c
; isdigit(c
= *++p
); ) {
2478 n
*= 10; /* two steps to avoid unnecessary overflow */
2479 n
+= '0' - c
; /* accum neg to avoid surprises at MAX */
2481 return (neg
? n
: -n
);
2485 * Default root read tsize XXX
2487 int nfs_root_rsize
= 8 * 1024; /* conservative for dumb NICs */
2488 int nfs4_root_rsize
= 32 * 1024; /* only runs on TCP be aggressive */
2491 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2493 int nfs_rootopts
= NFSMNT_NOCTO
|NFSMNT_LLOCK
|NFSMNT_INT
;
2496 init_mountopts(struct nfs_args
*args
, int version
, struct knetconfig
**dl_cf
,
2499 char servername
[SYS_NMLN
];
2500 static int first
= 0;
2501 struct netbuf server_address
;
2504 struct knetconfig
*cf
= *dl_cf
;
2505 char rootoptsbuf
[256];
2508 * Set default mount options
2510 args
->flags
= nfs_rootopts
;
2512 args
->flags
|= NFSMNT_ACREGMIN
;
2513 args
->acregmin
= ACMINMAX
;
2514 args
->flags
|= NFSMNT_ACREGMAX
;
2515 args
->acregmax
= ACMAXMAX
;
2516 args
->flags
|= NFSMNT_ACDIRMIN
;
2517 args
->acdirmin
= ACMINMAX
;
2518 args
->flags
|= NFSMNT_ACDIRMAX
;
2519 args
->acdirmax
= ACMAXMAX
;
2524 * Only look up the rootopts the first time, we store this in
2525 * a static buffer but we are guaranteed to be single threaded
2526 * and not reentrant.
2531 init_netbuf(&server_address
);
2533 if (getfile("rootopts", servername
, &server_address
,
2536 free_netbuf(&server_address
);
2539 free_netbuf(&server_address
);
2543 printf("rootopts = %s\n", rootopts
);
2546 * We have to preserve rootopts for second time.
2548 (void) strncpy(rootoptsbuf
, rootopts
, sizeof (rootoptsbuf
));
2549 rootoptsbuf
[sizeof (rootoptsbuf
) - 1] = '\0';
2554 switch (opt
= getsubopt(&opts
, optlist
, &val
)) {
2556 * Options that are defaults or meaningless so ignored
2567 case OPT_LARGEFILES
:
2573 *vfsflags
|= MS_RDONLY
;
2576 *vfsflags
&= ~(MS_RDONLY
);
2579 args
->flags
|= NFSMNT_SOFT
;
2580 args
->flags
&= ~(NFSMNT_SEMISOFT
);
2583 args
->flags
|= NFSMNT_SOFT
;
2584 args
->flags
|= NFSMNT_SEMISOFT
;
2587 args
->flags
&= ~(NFSMNT_SOFT
);
2588 args
->flags
&= ~(NFSMNT_SEMISOFT
);
2595 "nfs_dlboot: may not set root partition %s",
2599 args
->flags
|= NFSMNT_GRPID
;
2603 "nfs_dlboot: may not remount root partition");
2606 args
->flags
|= NFSMNT_INT
;
2609 args
->flags
&= ~(NFSMNT_INT
);
2612 args
->flags
|= NFSMNT_NOAC
;
2616 "nfs_dlboot: may not change root port number");
2620 "nfs_dlboot: root mounted auth_unix, secure ignored");
2623 args
->flags
|= NFSMNT_NOCTO
;
2628 "nfs_dlboot: invalid option: rsize");
2631 args
->flags
|= NFSMNT_RSIZE
;
2632 args
->rsize
= atoi(val
);
2637 "nfs_dlboot: invalid option: wsize");
2640 args
->flags
|= NFSMNT_WSIZE
;
2641 args
->wsize
= atoi(val
);
2646 "nfs_dlboot: invalid option: timeo");
2649 args
->flags
|= NFSMNT_TIMEO
;
2650 args
->timeo
= atoi(val
);
2655 "nfs_dlboot: invalid option: retrans");
2658 args
->flags
|= NFSMNT_RETRANS
;
2659 args
->retrans
= atoi(val
);
2664 "nfs_dlboot: invalid option: actimeo");
2667 args
->flags
|= NFSMNT_ACDIRMAX
;
2668 args
->flags
|= NFSMNT_ACREGMAX
;
2669 args
->flags
|= NFSMNT_ACDIRMIN
;
2670 args
->flags
|= NFSMNT_ACREGMIN
;
2671 args
->acdirmin
= args
->acregmin
= args
->acdirmax
=
2672 args
->acregmax
= atoi(val
);
2677 "nfs_dlboot: invalid option: acregmin");
2680 args
->flags
|= NFSMNT_ACREGMIN
;
2681 args
->acregmin
= atoi(val
);
2686 "nfs_dlboot: invalid option: acregmax");
2689 args
->flags
|= NFSMNT_ACREGMAX
;
2690 args
->acregmax
= atoi(val
);
2695 "nfs_dlboot: invalid option: acdirmin");
2698 args
->flags
|= NFSMNT_ACDIRMIN
;
2699 args
->acdirmin
= atoi(val
);
2704 "nfs_dlboot: invalid option: acdirmax");
2707 args
->flags
|= NFSMNT_ACDIRMAX
;
2708 args
->acdirmax
= atoi(val
);
2711 args
->flags
|= NFSMNT_LLOCK
;
2716 "nfs_dlboot: invalid option: vers");
2721 * If the requested version is less than what we
2722 * chose, pretend the chosen version doesn't exist
2724 if (vers
< version
) {
2725 return (EPROTONOSUPPORT
);
2727 if (vers
> version
) {
2729 "nfs_dlboot: version %d unavailable",
2736 * NFSv4 can only run over TCP, if they requested
2737 * UDP pretend v4 doesn't exist, they might not have
2738 * specified a version allowing a fallback to v2 or v3.
2740 if (version
== NFS_V4
&& strcmp(val
, NC_UDP
) == 0)
2741 return (EPROTONOSUPPORT
);
2743 * TCP is always chosen over UDP, so if the
2744 * requested is the same as the chosen either
2745 * they chose TCP when available or UDP on a UDP
2748 if (strcmp(cf
->knc_proto
, val
) == 0)
2751 * If we chose UDP, they must have requested TCP
2753 if (strcmp(cf
->knc_proto
, NC_TCP
) != 0) {
2755 "nfs_dlboot: TCP protocol unavailable");
2759 * They can only have requested UDP
2761 if (strcmp(val
, NC_UDP
) != 0) {
2763 "nfs_dlboot: unknown protocol");
2766 *dl_cf
= &dl_udp_netconf
;
2769 args
->flags
|= NFSMNT_NOPRINT
;
2771 case OPT_NOLARGEFILES
:
2773 "nfs_dlboot: NFS can't support nolargefiles");
2777 "nfs_dlboot: root mounted auth_unix, sec ignored");
2781 args
->flags
|= NFSMNT_DIRECTIO
;
2784 case OPT_NODIRECTIO
:
2785 args
->flags
&= ~(NFSMNT_DIRECTIO
);
2790 "nfs_dlboot: ignoring invalid option \"%s\"", val
);
2796 * Set some sane limits on read size
2798 if (!(args
->flags
& NFSMNT_RSIZE
) || args
->rsize
== 0) {
2800 * Establish defaults
2802 args
->flags
|= NFSMNT_RSIZE
;
2803 if (version
== NFS_V4
)
2804 args
->rsize
= nfs4_root_rsize
;
2806 args
->rsize
= nfs_root_rsize
;
2810 * No less than 512 bytes, otherwise it will take forever to boot
2812 if (args
->rsize
< 512)
2815 * If we are running over UDP, we cannot exceed 64KB, trim
2816 * to 56KB to allow room for headers.
2818 if (*dl_cf
== &dl_udp_netconf
&& args
->rsize
> (56 * 1024))
2819 args
->rsize
= 56 * 1024;