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
!= (uint32_t)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
) {
1205 for (len
= 0; len
< doptp
->len
; len
++) {
1206 if (doptp
->value
[len
] == ':') {
1207 str
= (char *)(&doptp
->value
[++len
]);
1212 /* Do not override server_ip from property. */
1213 if ((*(uint_t
*)server_ip
) == 0) {
1214 char *ip
= kmem_alloc(len
, KM_SLEEP
);
1215 bcopy(doptp
->value
, ip
, len
);
1217 if (inet_aton((ip
), server_ip
) != 0) {
1219 "server_ipaddr %s is "
1224 printf("server ip is %s\n",
1230 len
= doptp
->len
- len
;
1232 str
= (char *)doptp
->value
;
1235 server_path_c
= kmem_alloc(len
+ 1, KM_SLEEP
);
1236 bcopy(str
, server_path_c
, len
);
1237 server_path_c
[len
] = '\0';
1239 printf("dhcp: root path %s\n", server_path_c
);
1241 cmn_err(CE_WARN
, "dhcp: root server path missing");
1245 /* set server_name */
1246 if (server_name_c
== NULL
) {
1247 doptp
= pl
->vs
[VS_NFSMNT_ROOTSRVR_NAME
];
1248 if (doptp
!= NULL
) {
1249 server_name_c
= kmem_alloc(doptp
->len
+ 1, KM_SLEEP
);
1250 bcopy(doptp
->value
, server_name_c
, doptp
->len
);
1251 server_name_c
[doptp
->len
] = '\0';
1253 printf("dhcp: root server name %s\n",
1256 cmn_err(CE_WARN
, "dhcp: root server name missing");
1260 /* set root server_address */
1261 if ((*(uint_t
*)server_ip
) == 0) {
1262 doptp
= pl
->vs
[VS_NFSMNT_ROOTSRVR_IP
];
1264 bcopy(doptp
->value
, server_ip
, sizeof (server_ip
));
1266 printf("dhcp: root server IP address %s\n",
1267 inet_ntoa(*(struct in_addr
*)server_ip
));
1272 "dhcp: file server ip address missing,"
1273 " fallback to dhcp server as file server");
1274 bcopy(dhcp_server_ip
, server_ip
, sizeof (server_ip
));
1278 /* set root file system mount options */
1279 if (rootopts
[0] == 0) {
1280 doptp
= pl
->vs
[VS_NFSMNT_ROOTOPTS
];
1281 if (doptp
!= NULL
&& doptp
->len
< 255) {
1282 bcopy(doptp
->value
, rootopts
, doptp
->len
);
1283 rootopts
[doptp
->len
] = '\0';
1285 printf("dhcp: rootopts %s\n", rootopts
);
1286 } else if (dldebug
) {
1287 printf("dhcp: no rootopts or too long\n");
1292 /* now we are done with pl, just free it */
1293 kmem_free(pl
->pkt
, pl
->len
);
1294 kmem_free(pl
, sizeof (PKT_LIST
));
1299 cacheinfo(char *name
, int namelen
,
1300 struct netbuf
*server_address
, char *rootpath
, int pathlen
)
1302 static int init_done
= 0;
1303 struct sockaddr_in
*sin
;
1305 if (init_done
== 0) {
1310 /* server_path is a reliable indicator of cache availability */
1311 if (server_path_c
== NULL
)
1314 (void) strncpy(rootpath
, server_path_c
, pathlen
);
1315 if (server_name_c
) {
1316 (void) strncpy(name
, server_name_c
, namelen
);
1318 (void) strncpy(name
, "unknown", namelen
);
1321 sin
= (struct sockaddr_in
*)server_address
->buf
;
1322 sin
->sin_family
= AF_INET
;
1323 server_address
->len
= sizeof (struct sockaddr_in
);
1324 bcopy(server_ip
, &sin
->sin_addr
, sizeof (struct in_addr
));
1329 * Set this interface's IP address and netmask, and bring it up.
1332 dlifconfig(TIUSER
*tiptr
, struct in_addr
*myIPaddr
, struct in_addr
*mymask
,
1333 struct in_addr
*mybraddr
, uint_t flags
)
1337 struct sockaddr_in sin
;
1340 printf("dlifconfig: entered\n");
1341 printf("dlifconfig: addr %s\n", inet_ntoa(*myIPaddr
));
1342 printf("dlifconfig: mask %s\n", inet_ntoa(*mymask
));
1343 printf("dlifconfig: broadcast %s\n", inet_ntoa(*mybraddr
));
1346 bcopy(myIPaddr
, &sin
.sin_addr
, sizeof (struct in_addr
));
1347 sin
.sin_family
= AF_INET
;
1348 sbuf
.buf
= (caddr_t
)&sin
;
1349 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1350 if (rc
= ifioctl(tiptr
, SIOCSIFADDR
, &sbuf
)) {
1352 "dlifconfig: couldn't set interface net address: %m\n");
1356 if (mybraddr
->s_addr
!= INADDR_BROADCAST
) {
1357 bcopy(mybraddr
, &sin
.sin_addr
, sizeof (struct in_addr
));
1358 sin
.sin_family
= AF_INET
;
1359 sbuf
.buf
= (caddr_t
)&sin
;
1360 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1361 if (rc
= ifioctl(tiptr
, SIOCSIFBRDADDR
, &sbuf
)) {
1363 "dlifconfig: couldn't set interface broadcast addr: %m\n");
1368 bcopy(mymask
, &sin
.sin_addr
, sizeof (struct in_addr
));
1369 sin
.sin_family
= AF_INET
;
1370 sbuf
.buf
= (caddr_t
)&sin
;
1371 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1372 if (rc
= ifioctl(tiptr
, SIOCSIFNETMASK
, &sbuf
)) {
1374 "dlifconfig: couldn't set interface net address: %m\n");
1379 * Now turn on the interface.
1381 if (rc
= setifflags(tiptr
, IFF_UP
| flags
)) {
1383 "dlifconfig: couldn't enable network interface: %m\n");
1388 printf("dlifconfig: returned\n");
1393 inet_ntoa(struct in_addr in
)
1398 p
= (unsigned char *)&in
;
1399 (void) sprintf(b
, "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
1403 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1405 inet_aton(char *ipstr
, uchar_t
*ip
)
1408 uchar_t val
[4] = {0};
1417 val
[i
] = val
[i
] * 10 + (c
- '0');
1433 #define MAX_ADDR_SIZE 128
1436 * Initialize a netbuf suitable for
1437 * describing an address for the
1438 * transport defined by `tiptr'.
1441 init_netbuf(struct netbuf
*nbuf
)
1443 nbuf
->buf
= kmem_zalloc(MAX_ADDR_SIZE
, KM_SLEEP
);
1444 nbuf
->maxlen
= MAX_ADDR_SIZE
;
1449 free_netbuf(struct netbuf
*nbuf
)
1451 kmem_free(nbuf
->buf
, nbuf
->maxlen
);
1458 rtioctl(TIUSER
*tiptr
, int cmd
, struct rtentry
*rtentry
)
1460 struct strioctl iocb
;
1466 iocb
.ic_len
= sizeof (struct rtentry
);
1467 iocb
.ic_dp
= (caddr_t
)rtentry
;
1469 vp
= tiptr
->fp
->f_vnode
;
1470 rc
= kstr_ioctl(vp
, I_STR
, (intptr_t)&iocb
);
1472 nfs_perror(rc
, "rtioctl: kstr_ioctl failed: %m\n");
1477 * Send an ioctl down the stream defined
1480 * We isolate the ifreq dependencies in here. The
1481 * ioctl really ought to take a netbuf and be of
1482 * type TRANSPARENT - one day.
1485 ifioctl(TIUSER
*tiptr
, int cmd
, struct netbuf
*nbuf
)
1487 struct strioctl iocb
;
1493 * Now do the one requested.
1496 ifr
.ifr_addr
= *(struct sockaddr
*)nbuf
->buf
;
1497 (void) strncpy((caddr_t
)&ifr
.ifr_name
, ifname
, sizeof (ifr
.ifr_name
));
1500 iocb
.ic_len
= sizeof (ifr
);
1501 iocb
.ic_dp
= (caddr_t
)&ifr
;
1503 vp
= tiptr
->fp
->f_vnode
;
1504 rc
= kstr_ioctl(vp
, I_STR
, (intptr_t)&iocb
);
1506 nfs_perror(rc
, "ifioctl: kstr_ioctl failed: %m\n");
1513 if (nbuf
->len
== 0) {
1517 nbuf
->len
= sizeof (struct sockaddr
);
1518 *(struct sockaddr
*)nbuf
->buf
= ifr
.ifr_addr
;
1525 setifflags(TIUSER
*tiptr
, uint_t value
)
1529 struct strioctl iocb
;
1531 (void) strncpy((caddr_t
)&ifr
.ifr_name
, ifname
, sizeof (ifr
.ifr_name
));
1532 iocb
.ic_cmd
= SIOCGIFFLAGS
;
1534 iocb
.ic_len
= sizeof (ifr
);
1535 iocb
.ic_dp
= (caddr_t
)&ifr
;
1536 if (rc
= kstr_ioctl(tiptr
->fp
->f_vnode
, I_STR
, (intptr_t)&iocb
))
1539 ifr
.ifr_flags
|= value
;
1540 iocb
.ic_cmd
= SIOCSIFFLAGS
;
1541 return (kstr_ioctl(tiptr
->fp
->f_vnode
, I_STR
, (intptr_t)&iocb
));
1545 * REVerse Address Resolution Protocol (revarp)
1546 * is used by a diskless client to find out its
1547 * IP address when all it knows is its Ethernet address.
1549 * Open the ethernet driver, attach and bind
1550 * (DL_BIND_REQ) it, and then format a broadcast RARP
1551 * message for it to send. We pick up the reply and
1552 * let the caller set the interface address using SIOCSIFADDR.
1555 revarp_myaddr(TIUSER
*tiptr
)
1559 struct sockaddr_in sin
;
1563 struct netbuf myaddr
= {0, 0, NULL
};
1566 printf("revarp_myaddr: entered\n");
1568 if (rc
= ldi_ident_from_mod(&modlinkage
, &li
)) {
1570 "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1574 rc
= ldi_open_by_name(ndev_path
, FREAD
|FWRITE
, CRED(), &lh
, li
);
1575 ldi_ident_release(li
);
1578 "revarp_myaddr: ldi_open_by_name failed: %m\n");
1582 if (rc
= dl_attach(lh
, ifunit
, NULL
)) {
1583 nfs_perror(rc
, "revarp_myaddr: dl_attach failed: %m\n");
1584 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1588 if (rc
= dl_bind(lh
, ETHERTYPE_REVARP
, NULL
)) {
1589 nfs_perror(rc
, "revarp_myaddr: dl_bind failed: %m\n");
1590 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1594 if (rc
= dl_info(lh
, &info
, NULL
, NULL
, NULL
)) {
1595 nfs_perror(rc
, "revarp_myaddr: dl_info failed: %m\n");
1596 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1600 /* Initialize myaddr */
1601 myaddr
.maxlen
= info
.dl_addr_length
;
1602 myaddr
.buf
= kmem_alloc(myaddr
.maxlen
, KM_SLEEP
);
1604 revarp_start(lh
, &myaddr
);
1606 bcopy(myaddr
.buf
, &sin
.sin_addr
, myaddr
.len
);
1607 sin
.sin_family
= AF_INET
;
1609 sbuf
.buf
= (caddr_t
)&sin
;
1610 sbuf
.maxlen
= sbuf
.len
= sizeof (sin
);
1611 if (rc
= ifioctl(tiptr
, SIOCSIFADDR
, &sbuf
)) {
1613 "revarp_myaddr: couldn't set interface net address: %m\n");
1614 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1615 kmem_free(myaddr
.buf
, myaddr
.maxlen
);
1619 /* Now turn on the interface */
1620 if (rc
= setifflags(tiptr
, IFF_UP
)) {
1622 "revarp_myaddr: couldn't enable network interface: %m\n");
1625 (void) ldi_close(lh
, FREAD
|FWRITE
, CRED());
1626 kmem_free(myaddr
.buf
, myaddr
.maxlen
);
1631 revarp_start(ldi_handle_t lh
, struct netbuf
*myaddr
)
1633 struct ether_arp
*ea
;
1635 dl_unitdata_req_t
*dl_udata
;
1638 struct dladdr
*dlsap
;
1639 static int done
= 0;
1640 size_t addrlen
= ETHERADDRL
;
1642 if (dl_phys_addr(lh
, (uchar_t
*)&myether
, &addrlen
, NULL
) != 0 ||
1643 addrlen
!= ETHERADDRL
) {
1644 /* Fallback using per-node address */
1645 (void) localetheraddr(NULL
, &myether
);
1646 cmn_err(CE_CONT
, "?DLPI failed to get Ethernet address. Using "
1647 "system wide Ethernet address %s\n",
1648 ether_sprintf(&myether
));
1652 if (myaddr
->len
!= 0) {
1653 cmn_err(CE_CONT
, "?Found my IP address: %x (%d.%d.%d.%d)\n",
1654 *(int *)myaddr
->buf
,
1655 (uchar_t
)myaddr
->buf
[0], (uchar_t
)myaddr
->buf
[1],
1656 (uchar_t
)myaddr
->buf
[2], (uchar_t
)myaddr
->buf
[3]);
1661 cmn_err(CE_CONT
, "?Requesting Internet address for %s\n",
1662 ether_sprintf(&myether
));
1665 * Send another RARP request.
1667 if ((mp
= allocb(sizeof (dl_unitdata_req_t
) + sizeof (*dlsap
),
1668 BPRI_HI
)) == NULL
) {
1669 cmn_err(CE_WARN
, "revarp_myaddr: allocb no memory");
1672 if ((bp
= allocb(sizeof (struct ether_arp
), BPRI_HI
)) == NULL
) {
1673 cmn_err(CE_WARN
, "revarp_myaddr: allocb no memory");
1678 * Format the transmit request part.
1680 mp
->b_datap
->db_type
= M_PROTO
;
1681 dl_udata
= (dl_unitdata_req_t
*)mp
->b_wptr
;
1682 mp
->b_wptr
+= sizeof (dl_unitdata_req_t
) + sizeof (*dlsap
);
1683 dl_udata
->dl_primitive
= DL_UNITDATA_REQ
;
1684 dl_udata
->dl_dest_addr_length
= sizeof (*dlsap
);
1685 dl_udata
->dl_dest_addr_offset
= sizeof (*dl_udata
);
1686 dl_udata
->dl_priority
.dl_min
= 0;
1687 dl_udata
->dl_priority
.dl_max
= 0;
1689 dlsap
= (struct dladdr
*)(mp
->b_rptr
+ sizeof (*dl_udata
));
1690 bcopy(ðerbroadcastaddr
, &dlsap
->dl_phys
,
1691 sizeof (etherbroadcastaddr
));
1692 dlsap
->dl_sap
= ETHERTYPE_REVARP
;
1695 * Format the actual REVARP request.
1697 bzero(bp
->b_wptr
, sizeof (struct ether_arp
));
1698 ea
= (struct ether_arp
*)bp
->b_wptr
;
1699 bp
->b_wptr
+= sizeof (struct ether_arp
);
1700 ea
->arp_hrd
= htons(ARPHRD_ETHER
);
1701 ea
->arp_pro
= htons(ETHERTYPE_IP
);
1702 ea
->arp_hln
= sizeof (ea
->arp_sha
); /* hardware address length */
1703 ea
->arp_pln
= sizeof (ea
->arp_spa
); /* protocol address length */
1704 ea
->arp_op
= htons(REVARP_REQUEST
);
1705 ether_copy(&myether
, &ea
->arp_sha
);
1706 ether_copy(&myether
, &ea
->arp_tha
);
1710 if ((rc
= ldi_putmsg(lh
, mp
)) != 0) {
1711 nfs_perror(rc
, "revarp_start: ldi_putmsg failed: %m\n");
1714 revarpinput(lh
, myaddr
);
1720 * Client side Reverse-ARP input
1721 * Server side is handled by user level server
1724 revarpinput(ldi_handle_t lh
, struct netbuf
*myaddr
)
1726 struct ether_arp
*ea
;
1730 timestruc_t tv
, give_up
, now
;
1733 * Choose the time at which we will give up, and resend our
1736 gethrestime(&give_up
);
1737 give_up
.tv_sec
+= REVARP_TIMEO
;
1740 * Compute new timeout value.
1744 timespecsub(&tv
, &now
);
1746 * If we don't have at least one full second remaining, give up.
1747 * This means we might wait only just over 4.0 seconds, but that's
1752 rc
= ldi_getmsg(lh
, &mp
, &tv
);
1755 } else if (rc
!= 0) {
1756 nfs_perror(rc
, "revarpinput: ldi_getmsg failed: %m\n");
1760 if (mp
->b_cont
== NULL
) {
1761 printf("revarpinput: b_cont == NULL\n");
1765 if (mp
->b_datap
->db_type
!= M_PROTO
) {
1766 printf("revarpinput: bad header type %d\n",
1767 mp
->b_datap
->db_type
);
1773 if (bp
->b_wptr
- bp
->b_rptr
< sizeof (*ea
)) {
1774 printf("revarpinput: bad data len %d, expect %d\n",
1775 (int)(bp
->b_wptr
- bp
->b_rptr
), (int)sizeof (*ea
));
1779 ea
= (struct ether_arp
*)bp
->b_rptr
;
1781 if ((ushort_t
)ntohs(ea
->arp_pro
) != ETHERTYPE_IP
) {
1782 /* We could have received another broadcast arp packet. */
1784 printf("revarpinput: bad type %x\n",
1785 (ushort_t
)ntohs(ea
->arp_pro
));
1789 if ((ushort_t
)ntohs(ea
->arp_op
) != REVARP_REPLY
) {
1790 /* We could have received a broadcast arp request. */
1792 printf("revarpinput: bad op %x\n",
1793 (ushort_t
)ntohs(ea
->arp_op
));
1798 if (!ether_cmp(&ea
->arp_tha
, &myether
)) {
1799 bcopy(&ea
->arp_tpa
, myaddr
->buf
, sizeof (ea
->arp_tpa
));
1800 myaddr
->len
= sizeof (ea
->arp_tpa
);
1802 /* We could have gotten a broadcast arp response. */
1804 printf("revarpinput: got reply, but not my address\n");
1813 * From rpcsvc/mountxdr.c in SunOS. We can't
1814 * put this into the rpc directory because
1815 * it calls xdr_fhandle() which is in a
1819 myxdr_fhstatus(XDR
*xdrs
, struct fhstatus
*fhsp
)
1822 if (!xdr_int(xdrs
, &fhsp
->fhs_status
))
1824 if (fhsp
->fhs_status
== 0) {
1825 if (!myxdr_fhandle(xdrs
, &fhsp
->fhs_fh
))
1834 * File access handle
1835 * The fhandle struct is treated a opaque data on the wire
1838 myxdr_fhandle(XDR
*xdrs
, fhandle_t
*fh
)
1840 return (xdr_opaque(xdrs
, (caddr_t
)fh
, NFS_FHSIZE
));
1844 myxdr_mountres3(XDR
*xdrs
, struct mountres3
*objp
)
1846 if (!myxdr_mountstat3(xdrs
, &objp
->fhs_status
))
1848 switch (objp
->fhs_status
) {
1850 if (!myxdr_mountres3_ok(xdrs
, &objp
->mountres3_u
.mountinfo
))
1860 myxdr_mountstat3(XDR
*xdrs
, enum mountstat3
*objp
)
1862 return (xdr_enum(xdrs
, (enum_t
*)objp
));
1866 myxdr_mountres3_ok(XDR
*xdrs
, struct mountres3_ok
*objp
)
1868 if (!myxdr_fhandle3(xdrs
, &objp
->fhandle
))
1870 if (!xdr_array(xdrs
, (char **)&objp
->auth_flavors
.auth_flavors_val
,
1871 (uint_t
*)&objp
->auth_flavors
.auth_flavors_len
, ~0,
1872 sizeof (int), (xdrproc_t
)xdr_int
))
1878 myxdr_fhandle3(XDR
*xdrs
, struct fhandle3
*objp
)
1880 return (xdr_bytes(xdrs
, (char **)&objp
->fhandle3_val
,
1881 (uint_t
*)&objp
->fhandle3_len
, FHSIZE3
));
1885 * From SunOS pmap_clnt.c
1887 * Port mapper routines:
1888 * pmap_kgetport() - get port number.
1889 * pmap_rmt_call() - indirect call via port mapper.
1892 static enum clnt_stat
1893 pmap_kgetport(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
1894 rpcprog_t prog
, rpcvers_t vers
, rpcprot_t prot
)
1898 enum clnt_stat stat
;
1899 struct pmap pmap_parms
;
1905 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= htons(PMAPPORT
);
1907 pmap_parms
.pm_prog
= prog
;
1908 pmap_parms
.pm_vers
= vers
;
1909 pmap_parms
.pm_prot
= prot
;
1910 pmap_parms
.pm_port
= 0;
1911 for (tries
= 0; tries
< 5; tries
++) {
1912 stat
= mycallrpc(knconf
, call_addr
,
1913 PMAPPROG
, PMAPVERS
, PMAPPROC_GETPORT
,
1914 myxdr_pmap
, (char *)&pmap_parms
,
1915 xdr_u_short
, (char *)&port
,
1916 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
1918 if (stat
!= RPC_TIMEDOUT
)
1921 "pmap_kgetport: Portmapper not responding; still trying");
1924 if (stat
== RPC_PROGUNAVAIL
) {
1926 "pmap_kgetport: Portmapper failed - trying rpcbind");
1928 rpcb_parms
.r_prog
= prog
;
1929 rpcb_parms
.r_vers
= vers
;
1930 rpcb_parms
.r_netid
= knconf
->knc_proto
;
1931 rpcb_parms
.r_addr
= rpcb_parms
.r_owner
= "";
1933 for (tries
= 0; tries
< 5; tries
++) {
1934 stat
= mycallrpc(knconf
, call_addr
,
1935 RPCBPROG
, RPCBVERS
, RPCBPROC_GETADDR
,
1936 xdr_rpcb
, (char *)&rpcb_parms
,
1937 xdr_wrapstring
, (char *)&ua
,
1938 DEFAULT_TIMEO
, DEFAULT_RETRIES
);
1940 if (stat
!= RPC_TIMEDOUT
)
1943 "pmap_kgetport: rpcbind not responding; still trying");
1946 if (stat
== RPC_SUCCESS
) {
1947 if ((ua
!= NULL
) && (ua
[0] != '\0')) {
1948 port
= rpc_uaddr2port(AF_INET
, ua
);
1950 /* Address unknown */
1951 stat
= RPC_PROGUNAVAIL
;
1956 if (stat
== RPC_SUCCESS
)
1957 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= ntohs(port
);
1963 * pmapper remote-call-service interface.
1964 * This routine is used to call the pmapper remote call service
1965 * which will look up a service program in the port maps, and then
1966 * remotely call that routine with the given parameters. This allows
1967 * programs to do a lookup and call in one step. In addition to the call_addr,
1968 * the caller provides a boolean hint about the destination address (TRUE if
1969 * address is a broadcast address, FALSE otherwise).
1971 * On return, `call addr' contains the port number for the
1972 * service requested, and `resp_addr' contains its IP address.
1974 static enum clnt_stat
1975 pmap_rmt_call(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
1976 bool_t bcast
, rpcprog_t progn
, rpcvers_t versn
, rpcproc_t procn
,
1977 xdrproc_t xdrargs
, caddr_t argsp
, xdrproc_t xdrres
, caddr_t resp
,
1978 struct timeval tout
, struct netbuf
*resp_addr
)
1981 enum clnt_stat stat
;
1984 struct rmtcallargs pmap_args
;
1985 struct rmtcallres pmap_res
;
1986 struct rpcb_rmtcallargs rpcb_args
;
1987 struct rpcb_rmtcallres rpcb_res
;
1988 char ua
[100]; /* XXX */
1990 ((struct sockaddr_in
*)call_addr
->buf
)->sin_port
= htons(PMAPPORT
);
1992 rc
= clnt_tli_kcreate(knconf
, call_addr
, PMAPPROG
, PMAPVERS
,
1993 0, PMAP_RETRIES
, CRED(), &cl
);
1996 "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
1997 return (RPC_SYSTEMERROR
); /* XXX */
1999 if (cl
== (CLIENT
*)NULL
) {
2000 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2004 (void) CLNT_CONTROL(cl
, CLSET_BCAST
, (char *)&bcast
);
2006 pmap_args
.prog
= progn
;
2007 pmap_args
.vers
= versn
;
2008 pmap_args
.proc
= procn
;
2009 pmap_args
.args_ptr
= argsp
;
2010 pmap_args
.xdr_args
= xdrargs
;
2011 pmap_res
.port_ptr
= &port
;
2012 pmap_res
.results_ptr
= resp
;
2013 pmap_res
.xdr_results
= xdrres
;
2014 stat
= clnt_clts_kcallit_addr(cl
, PMAPPROC_CALLIT
,
2015 myxdr_rmtcall_args
, (caddr_t
)&pmap_args
,
2016 myxdr_rmtcallres
, (caddr_t
)&pmap_res
,
2019 if (stat
== RPC_SUCCESS
) {
2020 ((struct sockaddr_in
*)resp_addr
->buf
)->sin_port
=
2021 htons((ushort_t
)port
);
2025 if (stat
!= RPC_PROGUNAVAIL
)
2028 cmn_err(CE_WARN
, "pmap_rmt_call: Portmapper failed - trying rpcbind");
2030 rc
= clnt_tli_kcreate(knconf
, call_addr
, RPCBPROG
, RPCBVERS
,
2031 0, PMAP_RETRIES
, CRED(), &cl
);
2033 nfs_perror(rc
, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2034 return (RPC_SYSTEMERROR
); /* XXX */
2038 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2042 rpcb_args
.prog
= progn
;
2043 rpcb_args
.vers
= versn
;
2044 rpcb_args
.proc
= procn
;
2045 rpcb_args
.args_ptr
= argsp
;
2046 rpcb_args
.xdr_args
= xdrargs
;
2047 rpcb_res
.addr_ptr
= ua
;
2048 rpcb_res
.results_ptr
= resp
;
2049 rpcb_res
.xdr_results
= xdrres
;
2050 stat
= clnt_clts_kcallit_addr(cl
, PMAPPROC_CALLIT
,
2051 xdr_rpcb_rmtcallargs
, (caddr_t
)&rpcb_args
,
2052 xdr_rpcb_rmtcallres
, (caddr_t
)&rpcb_res
,
2055 if (stat
== RPC_SUCCESS
)
2056 ((struct sockaddr_in
*)resp_addr
->buf
)->sin_port
=
2057 rpc_uaddr2port(AF_INET
, ua
);
2064 * XDR remote call arguments
2065 * written for XDR_ENCODE direction only
2068 myxdr_rmtcall_args(XDR
*xdrs
, struct rmtcallargs
*cap
)
2074 if (xdr_rpcprog(xdrs
, &(cap
->prog
)) &&
2075 xdr_rpcvers(xdrs
, &(cap
->vers
)) &&
2076 xdr_rpcproc(xdrs
, &(cap
->proc
))) {
2077 lenposition
= XDR_GETPOS(xdrs
);
2078 if (!xdr_u_int(xdrs
, &cap
->arglen
))
2080 argposition
= XDR_GETPOS(xdrs
);
2081 if (!(*(cap
->xdr_args
))(xdrs
, cap
->args_ptr
))
2083 position
= XDR_GETPOS(xdrs
);
2084 cap
->arglen
= (uint_t
)position
- (uint_t
)argposition
;
2085 XDR_SETPOS(xdrs
, lenposition
);
2086 if (!xdr_u_int(xdrs
, &cap
->arglen
))
2088 XDR_SETPOS(xdrs
, position
);
2095 * XDR remote call results
2096 * written for XDR_DECODE direction only
2099 myxdr_rmtcallres(XDR
*xdrs
, struct rmtcallres
*crp
)
2103 port_ptr
= (caddr_t
)crp
->port_ptr
;
2104 if (xdr_reference(xdrs
, &port_ptr
, sizeof (uint_t
), xdr_u_int
) &&
2105 xdr_u_int(xdrs
, &crp
->resultslen
)) {
2106 crp
->port_ptr
= (rpcport_t
*)port_ptr
;
2107 return ((*(crp
->xdr_results
))(xdrs
, crp
->results_ptr
));
2113 myxdr_pmap(XDR
*xdrs
, struct pmap
*regs
)
2115 if (xdr_rpcprog(xdrs
, ®s
->pm_prog
) &&
2116 xdr_rpcvers(xdrs
, ®s
->pm_vers
) &&
2117 xdr_rpcprot(xdrs
, ®s
->pm_prot
))
2118 return (xdr_rpcport(xdrs
, ®s
->pm_port
));
2124 * From SunOS callrpc.c
2126 static enum clnt_stat
2127 mycallrpc(struct knetconfig
*knconf
, struct netbuf
*call_addr
,
2128 rpcprog_t prognum
, rpcvers_t versnum
, rpcproc_t procnum
,
2129 xdrproc_t inproc
, char *in
, xdrproc_t outproc
, char *out
,
2130 int timeo
, int retries
)
2134 enum clnt_stat cl_stat
;
2137 rc
= clnt_tli_kcreate(knconf
, call_addr
, prognum
, versnum
,
2138 0, retries
, CRED(), &cl
);
2140 nfs_perror(rc
, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2141 return (RPC_SYSTEMERROR
); /* XXX */
2145 cl_stat
= CLNT_CALL(cl
, procnum
, inproc
, in
, outproc
, out
, tv
);
2146 AUTH_DESTROY(cl
->cl_auth
);
2152 * Configure the 'default' interface based on existing boot properties.
2158 struct in_addr my_ip
, my_netmask
, my_router
, my_broadcast
;
2159 struct sockaddr_in
*sin
;
2162 struct rtentry rtentry
;
2164 my_ip
.s_addr
= my_netmask
.s_addr
= my_router
.s_addr
= 0;
2167 * No way of getting this right now. Collude with dlifconfig()
2168 * to let the protocol stack choose.
2170 my_broadcast
.s_addr
= INADDR_BROADCAST
;
2172 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2173 DDI_PROP_DONTPASS
, BP_HOST_IP
, &str
) == DDI_SUCCESS
) {
2174 if (inet_aton(str
, (uchar_t
*)&my_ip
) != 0)
2175 cmn_err(CE_NOTE
, "host-ip %s is invalid\n",
2179 printf("host ip is %s\n",
2182 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2183 DDI_PROP_DONTPASS
, BP_SUBNET_MASK
, &str
) == DDI_SUCCESS
) {
2184 if (inet_aton(str
, (uchar_t
*)&my_netmask
) != 0)
2185 cmn_err(CE_NOTE
, "subnet-mask %s is invalid\n",
2189 printf("subnet mask is %s\n",
2190 inet_ntoa(my_netmask
));
2192 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2193 DDI_PROP_DONTPASS
, BP_ROUTER_IP
, &str
) == DDI_SUCCESS
) {
2194 if (inet_aton(str
, (uchar_t
*)&my_router
) != 0)
2195 cmn_err(CE_NOTE
, "router-ip %s is invalid\n",
2199 printf("router ip is %s\n",
2200 inet_ntoa(my_router
));
2202 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2203 DDI_PROP_DONTPASS
, BP_SERVER_PATH
, &server_path_c
);
2204 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2205 DDI_PROP_DONTPASS
, BP_SERVER_NAME
, &server_name_c
);
2206 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2207 DDI_PROP_DONTPASS
, BP_SERVER_ROOTOPTS
, &str
) == DDI_SUCCESS
) {
2208 (void) strlcpy(rootopts
, str
, sizeof (rootopts
));
2211 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
2212 DDI_PROP_DONTPASS
, BP_SERVER_IP
, &str
) == DDI_SUCCESS
) {
2213 if (inet_aton(str
, server_ip
) != 0)
2214 cmn_err(CE_NOTE
, "server-ip %s is invalid\n",
2218 printf("server ip is %s\n",
2219 inet_ntoa(*(struct in_addr
*)server_ip
));
2223 * We need all of these to configure based on properties.
2225 if ((my_ip
.s_addr
== 0) ||
2226 (my_netmask
.s_addr
== 0) ||
2227 (server_path_c
== NULL
) ||
2228 (server_name_c
== NULL
) ||
2229 (*(uint_t
*)server_ip
== 0))
2232 cmn_err(CE_CONT
, "?IP address: %s\n", inet_ntoa(my_ip
));
2233 cmn_err(CE_CONT
, "?IP netmask: %s\n", inet_ntoa(my_netmask
));
2234 if (my_router
.s_addr
!= 0)
2235 cmn_err(CE_CONT
, "?IP router: %s\n", inet_ntoa(my_router
));
2236 cmn_err(CE_CONT
, "?NFS server: %s (%s)\n", server_name_c
,
2237 inet_ntoa(*(struct in_addr
*)server_ip
));
2238 cmn_err(CE_CONT
, "?NFS path: %s\n", server_path_c
);
2241 * Configure the interface.
2243 if ((rc
= t_kopen((file_t
*)NULL
, dl_udp_netconf
.knc_rdev
,
2244 FREAD
|FWRITE
, &tiptr
, CRED())) != 0) {
2245 nfs_perror(rc
, "bp_netconfig: t_kopen udp failed: %m.\n");
2249 if ((rc
= dlifconfig(tiptr
, &my_ip
, &my_netmask
, &my_broadcast
,
2251 nfs_perror(rc
, "bp_netconfig: dlifconfig failed: %m.\n");
2252 (void) t_kclose(tiptr
, 0);
2256 if (my_router
.s_addr
!= 0) {
2258 * Add a default route.
2260 sin
= (struct sockaddr_in
*)&rtentry
.rt_dst
;
2261 bzero(sin
, sizeof (*sin
));
2262 sin
->sin_family
= AF_INET
;
2264 sin
= (struct sockaddr_in
*)&rtentry
.rt_gateway
;
2265 bzero(sin
, sizeof (*sin
));
2266 sin
->sin_family
= AF_INET
;
2267 sin
->sin_addr
= my_router
;
2269 rtentry
.rt_flags
= RTF_GATEWAY
| RTF_UP
;
2271 if ((rc
= rtioctl(tiptr
, SIOCADDRT
, &rtentry
)) != 0) {
2273 "bp_netconfig: couldn't add route: %m.\n");
2274 (void) t_kclose(tiptr
, 0);
2279 (void) t_kclose(tiptr
, 0);
2285 * The network device we will use to boot from is plumbed. Extract the details
2291 (void) strlcpy(ndev_path
, rootfs
.bo_devname
, sizeof (ndev_path
));
2292 (void) strlcpy(ifname
, rootfs
.bo_ifname
, sizeof (ifname
));
2293 ifunit
= rootfs
.bo_ppa
;
2296 * Assumes only one linkage array element.
2298 dl_udp_netconf
.knc_rdev
=
2299 makedevice(clone_major
, ddi_name_to_major("udp"));
2300 dl_tcp_netconf
.knc_rdev
=
2301 makedevice(clone_major
, ddi_name_to_major("tcp"));
2304 * Now we bringup the interface.
2305 * Try cached dhcp response first. If it fails, do rarp.
2307 if ((bp_netconfig() != 0) &&
2308 (dhcpinit() != 0) &&
2311 "%s: no response from interface", ifname
);
2313 printf("init_config: ifname %s is up\n", ifname
);
2317 * These options are duplicated in cmd/fs.d/nfs/mount/mount.c
2318 * Changes must be made to both lists.
2320 static char *optlist
[] = {
2327 #define OPT_NOQUOTA 3
2335 #define OPT_NOSUID 7
2339 #define OPT_REMOUNT 9
2341 #define OPT_NOSUB 10
2345 #define OPT_NOINTR 12
2349 #define OPT_SECURE 14
2351 #define OPT_RSIZE 15
2353 #define OPT_WSIZE 16
2355 #define OPT_TIMEO 17
2357 #define OPT_RETRANS 18
2359 #define OPT_ACTIMEO 19
2361 #define OPT_ACREGMIN 20
2363 #define OPT_ACREGMAX 21
2365 #define OPT_ACDIRMIN 22
2367 #define OPT_ACDIRMAX 23
2373 #define OPT_RETRY 26
2377 #define OPT_NOCTO 28
2379 #define OPT_LLOCK 29
2381 #define OPT_POSIX 30
2385 #define OPT_PROTO 32
2387 #define OPT_SEMISOFT 33
2389 #define OPT_NOPRINT 34
2393 #define OPT_LARGEFILES 36
2395 #define OPT_NOLARGEFILES 37
2396 MNTOPT_NOLARGEFILES
,
2397 #define OPT_PUBLIC 38
2399 #define OPT_DIRECTIO 39
2400 MNTOPT_FORCEDIRECTIO
,
2401 #define OPT_NODIRECTIO 40
2402 MNTOPT_NOFORCEDIRECTIO
,
2403 #define OPT_XATTR 41
2405 #define OPT_NOXATTR 42
2407 #define OPT_DEVICES 43
2409 #define OPT_NODEVICES 44
2411 #define OPT_SETUID 45
2413 #define OPT_NOSETUID 46
2417 #define OPT_NOEXEC 48
2425 return (ch
>= '0' && ch
<= '9');
2428 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2429 #define bad(val) (val == NULL || !isdigit(*val))
2437 if (!isdigit(c
= *p
)) {
2450 for (n
= '0' - c
; isdigit(c
= *++p
); ) {
2451 n
*= 10; /* two steps to avoid unnecessary overflow */
2452 n
+= '0' - c
; /* accum neg to avoid surprises at MAX */
2454 return (neg
? n
: -n
);
2458 * Default root read tsize XXX
2460 int nfs_root_rsize
= 8 * 1024; /* conservative for dumb NICs */
2461 int nfs4_root_rsize
= 32 * 1024; /* only runs on TCP be aggressive */
2464 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2466 int nfs_rootopts
= NFSMNT_NOCTO
|NFSMNT_LLOCK
|NFSMNT_INT
;
2469 init_mountopts(struct nfs_args
*args
, int version
, struct knetconfig
**dl_cf
,
2472 char servername
[SYS_NMLN
];
2473 static int first
= 0;
2474 struct netbuf server_address
;
2477 struct knetconfig
*cf
= *dl_cf
;
2478 char rootoptsbuf
[256];
2481 * Set default mount options
2483 args
->flags
= nfs_rootopts
;
2485 args
->flags
|= NFSMNT_ACREGMIN
;
2486 args
->acregmin
= ACMINMAX
;
2487 args
->flags
|= NFSMNT_ACREGMAX
;
2488 args
->acregmax
= ACMAXMAX
;
2489 args
->flags
|= NFSMNT_ACDIRMIN
;
2490 args
->acdirmin
= ACMINMAX
;
2491 args
->flags
|= NFSMNT_ACDIRMAX
;
2492 args
->acdirmax
= ACMAXMAX
;
2497 * Only look up the rootopts the first time, we store this in
2498 * a static buffer but we are guaranteed to be single threaded
2499 * and not reentrant.
2504 init_netbuf(&server_address
);
2506 if (getfile("rootopts", servername
, &server_address
,
2509 free_netbuf(&server_address
);
2512 free_netbuf(&server_address
);
2516 printf("rootopts = %s\n", rootopts
);
2519 * We have to preserve rootopts for second time.
2521 (void) strncpy(rootoptsbuf
, rootopts
, sizeof (rootoptsbuf
));
2522 rootoptsbuf
[sizeof (rootoptsbuf
) - 1] = '\0';
2527 switch (opt
= getsubopt(&opts
, optlist
, &val
)) {
2529 * Options that are defaults or meaningless so ignored
2540 case OPT_LARGEFILES
:
2546 *vfsflags
|= MS_RDONLY
;
2549 *vfsflags
&= ~(MS_RDONLY
);
2552 args
->flags
|= NFSMNT_SOFT
;
2553 args
->flags
&= ~(NFSMNT_SEMISOFT
);
2556 args
->flags
|= NFSMNT_SOFT
;
2557 args
->flags
|= NFSMNT_SEMISOFT
;
2560 args
->flags
&= ~(NFSMNT_SOFT
);
2561 args
->flags
&= ~(NFSMNT_SEMISOFT
);
2568 "nfs_dlboot: may not set root partition %s",
2572 args
->flags
|= NFSMNT_GRPID
;
2576 "nfs_dlboot: may not remount root partition");
2579 args
->flags
|= NFSMNT_INT
;
2582 args
->flags
&= ~(NFSMNT_INT
);
2585 args
->flags
|= NFSMNT_NOAC
;
2589 "nfs_dlboot: may not change root port number");
2593 "nfs_dlboot: root mounted auth_unix, secure ignored");
2596 args
->flags
|= NFSMNT_NOCTO
;
2601 "nfs_dlboot: invalid option: rsize");
2604 args
->flags
|= NFSMNT_RSIZE
;
2605 args
->rsize
= atoi(val
);
2610 "nfs_dlboot: invalid option: wsize");
2613 args
->flags
|= NFSMNT_WSIZE
;
2614 args
->wsize
= atoi(val
);
2619 "nfs_dlboot: invalid option: timeo");
2622 args
->flags
|= NFSMNT_TIMEO
;
2623 args
->timeo
= atoi(val
);
2628 "nfs_dlboot: invalid option: retrans");
2631 args
->flags
|= NFSMNT_RETRANS
;
2632 args
->retrans
= atoi(val
);
2637 "nfs_dlboot: invalid option: actimeo");
2640 args
->flags
|= NFSMNT_ACDIRMAX
;
2641 args
->flags
|= NFSMNT_ACREGMAX
;
2642 args
->flags
|= NFSMNT_ACDIRMIN
;
2643 args
->flags
|= NFSMNT_ACREGMIN
;
2644 args
->acdirmin
= args
->acregmin
= args
->acdirmax
=
2645 args
->acregmax
= atoi(val
);
2650 "nfs_dlboot: invalid option: acregmin");
2653 args
->flags
|= NFSMNT_ACREGMIN
;
2654 args
->acregmin
= atoi(val
);
2659 "nfs_dlboot: invalid option: acregmax");
2662 args
->flags
|= NFSMNT_ACREGMAX
;
2663 args
->acregmax
= atoi(val
);
2668 "nfs_dlboot: invalid option: acdirmin");
2671 args
->flags
|= NFSMNT_ACDIRMIN
;
2672 args
->acdirmin
= atoi(val
);
2677 "nfs_dlboot: invalid option: acdirmax");
2680 args
->flags
|= NFSMNT_ACDIRMAX
;
2681 args
->acdirmax
= atoi(val
);
2684 args
->flags
|= NFSMNT_LLOCK
;
2689 "nfs_dlboot: invalid option: vers");
2694 * If the requested version is less than what we
2695 * chose, pretend the chosen version doesn't exist
2697 if (vers
< version
) {
2698 return (EPROTONOSUPPORT
);
2700 if (vers
> version
) {
2702 "nfs_dlboot: version %d unavailable",
2709 * NFSv4 can only run over TCP, if they requested
2710 * UDP pretend v4 doesn't exist, they might not have
2711 * specified a version allowing a fallback to v2 or v3.
2713 if (version
== NFS_V4
&& strcmp(val
, NC_UDP
) == 0)
2714 return (EPROTONOSUPPORT
);
2716 * TCP is always chosen over UDP, so if the
2717 * requested is the same as the chosen either
2718 * they chose TCP when available or UDP on a UDP
2721 if (strcmp(cf
->knc_proto
, val
) == 0)
2724 * If we chose UDP, they must have requested TCP
2726 if (strcmp(cf
->knc_proto
, NC_TCP
) != 0) {
2728 "nfs_dlboot: TCP protocol unavailable");
2732 * They can only have requested UDP
2734 if (strcmp(val
, NC_UDP
) != 0) {
2736 "nfs_dlboot: unknown protocol");
2739 *dl_cf
= &dl_udp_netconf
;
2742 args
->flags
|= NFSMNT_NOPRINT
;
2744 case OPT_NOLARGEFILES
:
2746 "nfs_dlboot: NFS can't support nolargefiles");
2750 "nfs_dlboot: root mounted auth_unix, sec ignored");
2754 args
->flags
|= NFSMNT_DIRECTIO
;
2757 case OPT_NODIRECTIO
:
2758 args
->flags
&= ~(NFSMNT_DIRECTIO
);
2763 "nfs_dlboot: ignoring invalid option \"%s\"", val
);
2769 * Set some sane limits on read size
2771 if (!(args
->flags
& NFSMNT_RSIZE
) || args
->rsize
== 0) {
2773 * Establish defaults
2775 args
->flags
|= NFSMNT_RSIZE
;
2776 if (version
== NFS_V4
)
2777 args
->rsize
= nfs4_root_rsize
;
2779 args
->rsize
= nfs_root_rsize
;
2783 * No less than 512 bytes, otherwise it will take forever to boot
2785 if (args
->rsize
< 512)
2788 * If we are running over UDP, we cannot exceed 64KB, trim
2789 * to 56KB to allow room for headers.
2791 if (*dl_cf
== &dl_udp_netconf
&& args
->rsize
> (56 * 1024))
2792 args
->rsize
= 56 * 1024;