Merge commit 'ea01a15a654b9e1c7b37d958f4d1911882ed7781'
[unleashed.git] / kernel / fs / nfs / nfs_dlinet.c
blob726b5c26de6446d2d12dce430133fd419f11a2e1
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
29 #include <sys/cred.h>
30 #include <sys/user.h>
31 #include <sys/file.h>
32 #include <sys/stream.h>
33 #include <sys/strsubr.h>
34 #include <sys/stropts.h>
35 #include <sys/strsun.h>
36 #include <sys/debug.h>
37 #include <sys/tiuser.h>
38 #include <sys/sockio.h>
39 #include <sys/socket.h>
40 #include <sys/t_kuser.h>
41 #include <sys/utsname.h>
42 #include <sys/systeminfo.h>
43 #include <sys/netconfig.h>
44 #include <sys/ethernet.h>
45 #include <sys/dlpi.h>
46 #include <sys/vfs.h>
47 #include <sys/sysmacros.h>
48 #include <sys/bootconf.h>
49 #include <sys/bootprops.h>
50 #include <sys/cmn_err.h>
51 #include <sys/promif.h>
52 #include <sys/mount.h>
54 #include <net/if.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>
65 #include <rpc/rpc.h>
66 #include <rpc/xdr.h>
67 #include <rpc/auth.h>
68 #include <rpc/clnt.h>
69 #include <rpc/pmap_clnt.h>
70 #include <rpc/pmap_rmt.h>
71 #include <rpc/pmap_prot.h>
72 #include <rpc/bootparam.h>
73 #include <rpc/rpcb_prot.h>
75 #include <nfs/nfs.h>
76 #include <nfs/nfs4.h>
77 #include <nfs/nfs_clnt.h>
78 #include <nfs/mount.h>
79 #include <sys/mntent.h>
81 #include <sys/kstr.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
106 #define MOUNTVERS 1
107 #define MOUNTVERS_POSIX 2
108 #define MOUNTVERS3 3
110 struct fhstatus {
111 int fhs_status;
112 fhandle_t fhs_fh;
115 #define FHSIZE3 64
117 struct fhandle3 {
118 uint_t fhandle3_len;
119 char *fhandle3_val;
122 enum mountstat3 {
123 MNT_OK = 0,
124 MNT3ERR_PERM = 1,
125 MNT3ERR_NOENT = 2,
126 MNT3ERR_IO = 5,
127 MNT3ERR_ACCES = 13,
128 MNT3ERR_NOTDIR = 20,
129 MNT3ERR_INVAL = 22,
130 MNT3ERR_NAMETOOLONG = 63,
131 MNT3ERR_NOTSUPP = 10004,
132 MNT3ERR_SERVERFAULT = 10006
135 struct mountres3_ok {
136 struct fhandle3 fhandle;
137 struct {
138 uint_t auth_flavors_len;
139 int *auth_flavors_val;
140 } auth_flavors;
143 struct mountres3 {
144 enum mountstat3 fhs_status;
145 union {
146 struct mountres3_ok mountinfo;
147 } mountres3_u;
151 * DLPI address format.
153 struct dladdr {
154 uchar_t dl_phys[6];
155 ushort_t dl_sap;
158 static struct modlmisc modlmisc = {
159 &mod_miscops, "Boot diskless"
162 static struct modlinkage modlinkage = {
163 MODREV_1, (void *)&modlmisc, NULL
166 static int dldebug;
169 _init(void)
171 return (mod_install(&modlinkage));
175 _fini(void)
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,
190 struct netbuf *);
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 *,
211 fhandle_t *, int *);
212 static int mountnfs3(struct netbuf *, char *, char *,
213 nfs_fh3 *, int *);
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
246 * arguments.
247 * "ndev" is the major device number of the network interface
248 * used to boot from.
249 * "ifunit" it the physical point of attachment for the network
250 * interface used to boot from.
252 * Both of these are initialized in "init_config()".
255 static char ifname[IFNAMSIZ];
256 static char ndev_path[MAXPATHLEN];
257 static int ifunit;
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 */
266 0, /* device */
269 static struct knetconfig dl_tcp_netconf = {
270 NC_TPI_COTS, /* semantics */
271 NC_INET, /* family */
272 NC_TCP, /* protocol */
273 0, /* device */
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,
291 int *vfsflags)
293 int rc;
294 int proto;
295 struct knetconfig *dl_cf;
296 static int init_done = 0;
297 enum clnt_stat stat;
299 if (dldebug)
300 printf("mount_root: name=%s\n", name);
302 if (init_done == 0) {
303 init_config();
304 init_done = 1;
307 init_netbuf(args->addr);
309 do {
310 rc = getfile(name, args->hostname, args->addr, path);
311 } while (rc == ETIMEDOUT);
313 if (rc) {
314 free_netbuf(args->addr);
315 return (rc);
318 ASSERT(args->knconf->knc_protofmly != NULL);
319 ASSERT(args->knconf->knc_proto != NULL);
321 switch (version) {
322 case NFS_VERSION:
323 rc = mountnfs(args->addr, args->hostname, path,
324 (fhandle_t *)args->fh, &proto);
325 break;
326 case NFS_V3:
327 rc = mountnfs3(args->addr, args->hostname, path,
328 (nfs_fh3 *)args->fh, &proto);
329 break;
330 case NFS_V4:
331 ((struct sockaddr_in *)args->addr->buf)->sin_port =
332 htons(NFS_PORT);
333 if (ping_prog(args->addr, NFS_PROGRAM, NFS_V4, IPPROTO_TCP,
334 &stat)) {
335 proto = IPPROTO_TCP;
336 rc = 0;
337 } else {
338 switch (stat) {
339 case RPC_PROGVERSMISMATCH:
340 case RPC_XPRTFAILED:
342 * Common failures if v4 unsupported or no TCP
344 rc = EPROTONOSUPPORT;
345 break;
346 default:
347 rc = ENXIO;
350 if (nfs4_no_diskless_root_support)
351 rc = EPROTONOSUPPORT;
352 break;
353 default:
354 rc = EPROTONOSUPPORT;
355 break;
358 if (rc)
359 goto errout;
361 switch (proto) {
362 case IPPROTO_TCP:
363 dl_cf = &dl_tcp_netconf;
364 break;
365 case IPPROTO_UDP:
366 default:
367 dl_cf = &dl_udp_netconf;
368 break;
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);
382 errout:
383 if (dldebug) {
384 if (rc)
385 nfs_perror(rc, "mount_root: mount %s:%s failed: %m\n",
386 args->hostname, path);
387 else
388 printf("mount_root: leaving\n");
391 return (rc);
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.
399 static int
400 mountnfs(struct netbuf *sa, char *server,
401 char *path, fhandle_t *fh, int *proto)
403 struct fhstatus fhs;
404 enum clnt_stat stat;
406 if (dldebug)
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.
416 do {
417 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
418 (rpcvers_t)MOUNTVERS, (rpcprot_t)IPPROTO_UDP);
420 if (stat == RPC_TIMEDOUT) {
421 cmn_err(CE_WARN,
422 "mountnfs: %s:%s portmap not responding",
423 server, path);
424 } else if (stat != RPC_SUCCESS) {
425 cmn_err(CE_WARN,
426 "mountnfs: pmap_kgetport RPC error %d (%s).",
427 stat, clnt_sperrno(stat));
428 return (ENXIO); /* XXX */
430 } while (stat == RPC_TIMEDOUT);
433 * The correct port number has been
434 * put into `sa' by pmap_kgetport().
436 do {
437 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
438 (rpcvers_t)MOUNTVERS, (rpcproc_t)MOUNTPROC_MNT,
439 xdr_bp_path_t, (char *)&path,
440 myxdr_fhstatus, (char *)&fhs,
441 DEFAULT_TIMEO, DEFAULT_RETRIES);
442 if (stat == RPC_TIMEDOUT) {
443 cmn_err(CE_WARN,
444 "mountnfs: %s:%s mount server not responding",
445 server, path);
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);
457 *fh = fhs.fhs_fh;
458 if (fhs.fhs_status != 0) {
459 if (dldebug)
460 printf("mountnfs: fhs_status %d\n", fhs.fhs_status);
461 return (ENXIO); /* XXX */
464 *proto = IPPROTO_UDP;
466 if (ping_prog(sa, NFS_PROGRAM, NFS_VERSION, IPPROTO_TCP, NULL))
467 *proto = IPPROTO_TCP;
469 if (dldebug)
470 printf("mountnfs: leaving\n");
471 return (0);
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.
479 static int
480 mountnfs3(struct netbuf *sa, char *server, char *path, nfs_fh3 *fh, int *proto)
482 struct mountres3 mountres3;
483 enum clnt_stat stat;
484 int ret = 0;
486 if (dldebug)
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.
496 do {
497 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
498 (rpcvers_t)MOUNTVERS3, (rpcprot_t)IPPROTO_UDP);
500 if (stat == RPC_PROGVERSMISMATCH) {
501 if (dldebug)
502 printf("mountnfs3: program/version mismatch\n");
503 return (EPROTONOSUPPORT); /* XXX */
504 } else if (stat == RPC_TIMEDOUT) {
505 cmn_err(CE_WARN,
506 "mountnfs3: %s:%s portmap not responding",
507 server, path);
508 } else if (stat != RPC_SUCCESS) {
509 cmn_err(CE_WARN,
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().
523 do {
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) {
530 cmn_err(CE_WARN,
531 "mountnfs3: %s:%s mount server not responding",
532 server, path);
534 } while (stat == RPC_TIMEDOUT);
536 if (stat == RPC_PROGVERSMISMATCH) {
537 if (dldebug)
538 printf("mountnfs3: program/version mismatch\n");
539 ret = EPROTONOSUPPORT;
540 goto out;
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 */
546 goto out;
549 if (mountres3.fhs_status != MNT_OK) {
550 if (dldebug)
551 printf("mountnfs3: fhs_status %d\n",
552 mountres3.fhs_status);
553 ret = ENXIO; /* XXX */
554 goto out;
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);
569 out:
570 xdr_free(myxdr_mountres3, (caddr_t)&mountres3);
572 if (dldebug)
573 printf("mountnfs3: leaving\n");
574 return (ret);
577 static int
578 ping_prog(struct netbuf *call_addr, uint_t prog, uint_t vers, int proto,
579 enum clnt_stat *statp)
581 struct knetconfig *knconf;
582 enum clnt_stat stat;
583 int retries = DEFAULT_RETRIES;
585 switch (proto) {
586 case IPPROTO_TCP:
587 knconf = &dl_tcp_netconf;
588 break;
589 case IPPROTO_UDP:
590 knconf = &dl_udp_netconf;
591 break;
592 default:
593 return (0);
596 do {
597 stat = mycallrpc(knconf, call_addr, prog, vers, NULLPROC,
598 xdr_void, NULL, xdr_void, NULL,
599 DEFAULT_TIMEO, DEFAULT_RETRIES);
601 if (dldebug)
602 printf("ping_prog: %d return %d (%s)\n", proto, stat,
603 clnt_sperrno(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--);
612 if (statp != NULL)
613 *statp = stat;
615 if (stat != RPC_SUCCESS)
616 return (0);
617 return (1);
620 static struct netbuf bootparam_addr;
623 * Returns after filling in the following global variables:
624 * bootparam_addr,
625 * utsname.nodename,
626 * srpc_domain.
628 static int
629 whoami(void)
631 TIUSER *tiptr;
632 struct netbuf sa;
633 struct netbuf req;
634 struct bp_whoami_arg arg;
635 struct bp_whoami_res res;
636 struct timeval tv;
637 enum clnt_stat stat;
638 int rc;
639 size_t namelen;
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);
653 return (rc);
656 /* explicitly use the limited broadcast address */
657 init_netbuf(&sa);
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.
666 init_netbuf(&req);
667 if (rc = ifioctl(tiptr, SIOCGIFADDR, &req)) {
668 nfs_perror(rc,
669 "whoami: couldn't get my IP address: %m.\n");
670 free_netbuf(&sa);
671 free_netbuf(&req);
672 (void) t_kclose(tiptr, 0);
673 return (rc);
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));
683 free_netbuf(&req);
685 init_netbuf(&bootparam_addr);
688 * Initial retransmission interval
690 tv.tv_sec = DEFAULT_TIMEO;
691 tv.tv_usec = 0;
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;
701 do {
703 * pmap_rmt_call will first try the SunOS portmapper
704 * and if no reply is received will then try the SVR4
705 * rpcbind.
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) {
715 cmn_err(CE_WARN,
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;
725 tv.tv_usec = 0;
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 */
733 rc = ENXIO;
734 cmn_err(CE_WARN,
735 "whoami: bootparam RPC failed: error %d (%s).",
736 stat, clnt_sperrno(stat));
737 goto done;
740 namelen = strlen(res.client_name);
741 if (namelen > sizeof (utsname.nodename)) {
742 printf("whoami: hostname too long");
743 rc = ENAMETOOLONG;
744 goto done;
746 if (namelen != 0) {
747 bcopy(res.client_name, &utsname.nodename, namelen);
748 cmn_err(CE_CONT, "?hostname: %s\n", utsname.nodename);
749 } else {
750 printf("whoami: no host name\n");
751 rc = ENXIO;
752 goto done;
755 namelen = strlen(res.domain_name);
756 if (namelen != 0) {
757 if (namelen > SYS_NMLN) {
758 printf("whoami: domainname too long");
759 rc = ENAMETOOLONG;
760 goto done;
762 bcopy(res.domain_name, &srpc_domain, namelen);
763 cmn_err(CE_CONT, "?domainname: %s\n", srpc_domain);
764 } else {
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)) {
789 nfs_perror(rc,
790 "whoami: couldn't add route: %m.\n");
791 goto done;
794 } else {
795 printf("whoami: unknown gateway addr family %d\n",
796 res.router_address.address_type);
798 done:
799 kmem_free(res.client_name, MAX_MACHINE_NAME + 1);
800 kmem_free(res.domain_name, MAX_MACHINE_NAME + 1);
801 free_netbuf(&sa);
802 (void) t_kclose(tiptr, 0);
803 return (rc);
807 * Returns:
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.
814 static int
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;
820 enum clnt_stat stat;
821 int root = FALSE;
822 static int using_cache = FALSE;
823 struct in_addr ipaddr;
824 int timeo = DEFAULT_TIMEO;
825 int retries = DEFAULT_RETRIES;
827 if (dldebug)
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) {
841 using_cache = TRUE;
842 return (0);
844 root = TRUE;
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) {
855 return (ENXIO);
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.
868 if (!root) {
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,
884 timeo, retries);
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) {
895 if (root)
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')
902 return (EINVAL);
905 * If the fileid is "root", we must get back a server name, for
906 * other parameters a server name is not required
908 if (!root) {
909 if (dldebug)
910 printf("getfile: leaving: non-root\n");
911 return (0);
914 if (*server_name == '\0')
915 return (EINVAL);
917 switch (res.server_address.address_type) {
918 case IP_ADDR_TYPE:
920 * server_address is where we will get our root
921 * from.
923 ((struct sockaddr_in *)server_address->buf)->sin_family =
924 AF_INET;
925 bcopy(&res.server_address.bp_address.ip_addr,
926 &ipaddr, sizeof (ipaddr));
927 if (ipaddr.s_addr == 0)
928 return (EINVAL);
930 ((struct sockaddr_in *)server_address->buf)->sin_addr.s_addr =
931 ipaddr.s_addr;
932 server_address->len = sizeof (struct sockaddr_in);
933 break;
935 default:
936 printf("getfile: unknown address type %d\n",
937 res.server_address.address_type);
938 return (EPROTONOSUPPORT);
940 if (dldebug)
941 printf("getfile: leaving\n");
942 return (0);
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.
954 dhcpinit(void)
956 int rc, i;
957 char *p;
958 struct in_addr braddr;
959 struct in_addr subnet;
960 DHCP_OPT *doptp;
961 TIUSER *tiptr;
962 struct sockaddr_in *sin;
963 static int once_only = 0;
965 if (once_only == 1) {
966 return (0);
968 once_only = 1;
970 if (dhcack == NULL) {
971 return (-1);
974 if (dldebug) {
975 printf("dhcp: dhcack %p, len %d\n", (void *)dhcack,
976 dhcacklen);
979 pl = kmem_alloc(sizeof (PKT_LIST), KM_SLEEP);
980 pl->len = dhcacklen;
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
988 * is set properly.
990 if (ifname[0])
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));
1004 pl = NULL;
1005 return (-1);
1008 /* set node name */
1009 if (pl->opts[CD_HOSTNAME] != NULL) {
1010 doptp = pl->opts[CD_HOSTNAME];
1011 i = doptp->len;
1012 if (i >= SYS_NMLN) {
1013 cmn_err(CE_WARN, "dhcp: Hostname is too long");
1014 } else {
1015 bcopy(doptp->value, utsname.nodename, i);
1016 utsname.nodename[i] = '\0';
1017 if (dldebug) {
1018 printf("hostname is %s\n",
1019 utsname.nodename);
1024 /* Set NIS domain name. */
1025 p = NULL;
1026 if (pl->opts[CD_NIS_DOMAIN] != NULL) {
1027 doptp = pl->opts[CD_NIS_DOMAIN];
1028 i = doptp->len;
1029 p = (caddr_t)doptp->value;
1031 if (p != NULL) {
1032 if (i > SYS_NMLN) {
1033 cmn_err(CE_WARN,
1034 "dhcp: NIS domainname too long.");
1035 } else {
1036 bcopy(p, srpc_domain, i);
1037 srpc_domain[i] = '\0';
1038 if (dldebug)
1039 printf("dhcp: NIS domain name is %s\n",
1040 srpc_domain);
1044 /* fetch netmask */
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");
1050 } else {
1051 bcopy(doptp->value, &subnet, sizeof (struct in_addr));
1052 if (dldebug)
1053 printf("dhcp: setting netmask to: %s\n",
1054 inet_ntoa(subnet));
1056 } else {
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));
1070 else
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;
1078 if (dldebug)
1079 printf("dhcp: broadcast address len %d\n",
1080 doptp->len);
1081 } else {
1082 bcopy(doptp->value, &braddr, sizeof (struct in_addr));
1083 if (dldebug)
1084 printf("dhcp: setting broadcast addr to: %s\n",
1085 inet_ntoa(braddr));
1087 } else {
1088 if (dldebug)
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));
1100 pl = NULL;
1101 (void) t_kclose(tiptr, 0);
1102 return (-1);
1105 /* add routes */
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;
1110 } else {
1111 int nrouters;
1112 uchar_t *tp;
1114 nrouters = doptp->len / sizeof (struct in_addr);
1115 for (tp = doptp->value, i = 0; i < nrouters;
1116 i++) {
1117 struct in_addr defr;
1118 struct rtentry rtentry;
1120 bcopy(tp, &defr,
1121 sizeof (struct in_addr));
1122 if (defr.s_addr == 0)
1123 continue;
1125 sin = (struct
1126 sockaddr_in *)&rtentry.rt_dst;
1128 bzero(sin, sizeof (*sin));
1129 sin->sin_family = AF_INET;
1131 sin = (struct
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,
1140 &rtentry)) {
1141 nfs_perror(rc,
1142 "dhcp: couldn't add route "
1143 "to %s: %m.\n",
1144 inet_ntoa(defr));
1145 continue;
1147 if (dldebug) {
1148 printf("dhcp: added route %s\n",
1149 inet_ntoa(defr));
1151 tp += sizeof (struct in_addr);
1156 (void) t_kclose(tiptr, 0);
1159 if (dldebug)
1160 printf("dhcpinit: leaving\n");
1162 return (0);
1166 * Initialize nfs mount info from properties and dhcp response.
1168 static void
1169 cacheinit(void)
1171 char *str;
1172 DHCP_OPT *doptp;
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);
1181 ddi_prop_free(str);
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",
1187 str);
1188 ddi_prop_free(str);
1189 if (dldebug)
1190 printf("server ip is %s\n",
1191 inet_ntoa(*(struct in_addr *)server_ip));
1194 if (pl == NULL)
1195 return;
1197 /* extract root path in server_path */
1198 if (server_path_c == NULL) {
1199 doptp = pl->vs[VS_NFSMNT_ROOTPATH];
1200 if (doptp == NULL)
1201 doptp = pl->opts[CD_ROOT_PATH];
1202 if (doptp != NULL) {
1203 int len, size;
1204 uint8_t c, *source;
1206 str = NULL;
1207 source = doptp->value;
1208 size = doptp->len;
1209 c = ':';
1212 * We have to consider three cases for root path:
1213 * "nfs://server_ip/path"
1214 * "server_ip:/path"
1215 * "/path"
1217 if (bcmp(source, "nfs://", 6) == 0) {
1218 source += 6;
1219 size -= 6;
1220 c = '/';
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) {
1229 if (c == ':') {
1230 str = (char *)(&source[++len]);
1231 } else {
1232 str = (char *)(&source[len++]);
1233 size++;
1235 break;
1238 if (str != NULL) {
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);
1243 ip[len - 1] = '\0';
1244 if (inet_aton((ip), server_ip) != 0) {
1245 cmn_err(CE_NOTE,
1246 "server_ipaddr %s is "
1247 "invalid", ip);
1249 kmem_free(ip, len);
1250 if (dldebug) {
1251 printf("server ip is %s\n",
1252 inet_ntoa(
1253 *(struct in_addr *)
1254 server_ip));
1257 len = size - len;
1258 } else {
1259 str = (char *)doptp->value;
1260 len = doptp->len;
1262 server_path_c = kmem_alloc(len + 1, KM_SLEEP);
1263 bcopy(str, server_path_c, len);
1264 server_path_c[len] = '\0';
1265 if (dldebug)
1266 printf("dhcp: root path %s\n", server_path_c);
1267 } else {
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';
1279 if (dldebug)
1280 printf("dhcp: root server name %s\n",
1281 server_name_c);
1282 } else {
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];
1290 if (doptp) {
1291 bcopy(doptp->value, server_ip, sizeof (server_ip));
1292 if (dldebug) {
1293 printf("dhcp: root server IP address %s\n",
1294 inet_ntoa(*(struct in_addr *)server_ip));
1296 } else {
1297 if (dldebug)
1298 cmn_err(CE_CONT,
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';
1311 if (dldebug)
1312 printf("dhcp: rootopts %s\n", rootopts);
1313 } else if (dldebug) {
1314 printf("dhcp: no rootopts or too long\n");
1315 /* not an error */
1319 /* now we are done with pl, just free it */
1320 kmem_free(pl->pkt, pl->len);
1321 kmem_free(pl, sizeof (PKT_LIST));
1322 pl = NULL;
1325 static int
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) {
1333 cacheinit();
1334 init_done = 1;
1337 /* server_path is a reliable indicator of cache availability */
1338 if (server_path_c == NULL)
1339 return (-1);
1341 (void) strncpy(rootpath, server_path_c, pathlen);
1342 if (server_name_c) {
1343 (void) strncpy(name, server_name_c, namelen);
1344 } else {
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));
1352 return (0);
1356 * Set this interface's IP address and netmask, and bring it up.
1358 static int
1359 dlifconfig(TIUSER *tiptr, struct in_addr *myIPaddr, struct in_addr *mymask,
1360 struct in_addr *mybraddr, uint_t flags)
1362 int rc;
1363 struct netbuf sbuf;
1364 struct sockaddr_in sin;
1366 if (dldebug) {
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)) {
1378 nfs_perror(rc,
1379 "dlifconfig: couldn't set interface net address: %m\n");
1380 return (rc);
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)) {
1389 nfs_perror(rc,
1390 "dlifconfig: couldn't set interface broadcast addr: %m\n");
1391 return (rc);
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)) {
1400 nfs_perror(rc,
1401 "dlifconfig: couldn't set interface net address: %m\n");
1402 return (rc);
1406 * Now turn on the interface.
1408 if (rc = setifflags(tiptr, IFF_UP | flags)) {
1409 nfs_perror(rc,
1410 "dlifconfig: couldn't enable network interface: %m\n");
1411 return (rc);
1414 if (dldebug)
1415 printf("dlifconfig: returned\n");
1416 return (0);
1419 static char *
1420 inet_ntoa(struct in_addr in)
1422 static char b[18];
1423 unsigned char *p;
1425 p = (unsigned char *)&in;
1426 (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1427 return (b);
1430 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1431 static int
1432 inet_aton(char *ipstr, uchar_t *ip)
1434 int i = 0;
1435 uchar_t val[4] = {0};
1436 char c = *ipstr;
1438 for (;;) {
1439 if (!isdigit(c))
1440 return (-1);
1441 for (;;) {
1442 if (!isdigit(c))
1443 break;
1444 val[i] = val[i] * 10 + (c - '0');
1445 c = *++ipstr;
1447 i++;
1448 if (i == 4)
1449 break;
1450 if (c != '.')
1451 return (-1);
1452 c = *++ipstr;
1454 if (c != 0)
1455 return (-1);
1456 bcopy(val, ip, 4);
1457 return (0);
1460 #define MAX_ADDR_SIZE 128
1463 * Initialize a netbuf suitable for
1464 * describing an address for the
1465 * transport defined by `tiptr'.
1467 static void
1468 init_netbuf(struct netbuf *nbuf)
1470 nbuf->buf = kmem_zalloc(MAX_ADDR_SIZE, KM_SLEEP);
1471 nbuf->maxlen = MAX_ADDR_SIZE;
1472 nbuf->len = 0;
1475 static void
1476 free_netbuf(struct netbuf *nbuf)
1478 kmem_free(nbuf->buf, nbuf->maxlen);
1479 nbuf->buf = NULL;
1480 nbuf->maxlen = 0;
1481 nbuf->len = 0;
1484 static int
1485 rtioctl(TIUSER *tiptr, int cmd, struct rtentry *rtentry)
1487 struct strioctl iocb;
1488 int rc;
1489 vnode_t *vp;
1491 iocb.ic_cmd = cmd;
1492 iocb.ic_timout = 0;
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);
1498 if (rc)
1499 nfs_perror(rc, "rtioctl: kstr_ioctl failed: %m\n");
1500 return (rc);
1504 * Send an ioctl down the stream defined
1505 * by `tiptr'.
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.
1511 static int
1512 ifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf)
1514 struct strioctl iocb;
1515 int rc;
1516 vnode_t *vp;
1517 struct ifreq ifr;
1520 * Now do the one requested.
1522 if (nbuf->len)
1523 ifr.ifr_addr = *(struct sockaddr *)nbuf->buf;
1524 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1525 iocb.ic_cmd = cmd;
1526 iocb.ic_timout = 0;
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);
1532 if (rc) {
1533 nfs_perror(rc, "ifioctl: kstr_ioctl failed: %m\n");
1534 return (rc);
1538 * Set reply length.
1540 if (nbuf->len == 0) {
1542 * GET type.
1544 nbuf->len = sizeof (struct sockaddr);
1545 *(struct sockaddr *)nbuf->buf = ifr.ifr_addr;
1548 return (0);
1551 static int
1552 setifflags(TIUSER *tiptr, uint_t value)
1554 struct ifreq ifr;
1555 int rc;
1556 struct strioctl iocb;
1558 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1559 iocb.ic_cmd = SIOCGIFFLAGS;
1560 iocb.ic_timout = 0;
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))
1564 return (rc);
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.
1581 static int
1582 revarp_myaddr(TIUSER *tiptr)
1584 int rc;
1585 dl_info_ack_t info;
1586 struct sockaddr_in sin;
1587 struct netbuf sbuf;
1588 ldi_handle_t lh;
1589 ldi_ident_t li;
1590 struct netbuf myaddr = {0, 0, NULL};
1592 if (dldebug)
1593 printf("revarp_myaddr: entered\n");
1595 if (rc = ldi_ident_from_mod(&modlinkage, &li)) {
1596 nfs_perror(rc,
1597 "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1598 return (rc);
1601 rc = ldi_open_by_name(ndev_path, FREAD|FWRITE, CRED(), &lh, li);
1602 ldi_ident_release(li);
1603 if (rc) {
1604 nfs_perror(rc,
1605 "revarp_myaddr: ldi_open_by_name failed: %m\n");
1606 return (rc);
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());
1612 return (rc);
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());
1618 return (rc);
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());
1624 return (rc);
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)) {
1639 nfs_perror(rc,
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);
1643 return (rc);
1646 /* Now turn on the interface */
1647 if (rc = setifflags(tiptr, IFF_UP)) {
1648 nfs_perror(rc,
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);
1654 return (rc);
1657 static void
1658 revarp_start(ldi_handle_t lh, struct netbuf *myaddr)
1660 struct ether_arp *ea;
1661 int rc;
1662 dl_unitdata_req_t *dl_udata;
1663 mblk_t *bp;
1664 mblk_t *mp;
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));
1678 getreply:
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]);
1684 return;
1687 if (done++ == 0)
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");
1697 return;
1699 if ((bp = allocb(sizeof (struct ether_arp), BPRI_HI)) == NULL) {
1700 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1701 return;
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(&etherbroadcastaddr, &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);
1735 mp->b_cont = bp;
1737 if ((rc = ldi_putmsg(lh, mp)) != 0) {
1738 nfs_perror(rc, "revarp_start: ldi_putmsg failed: %m\n");
1739 return;
1741 revarpinput(lh, myaddr);
1743 goto getreply;
1747 * Client side Reverse-ARP input
1748 * Server side is handled by user level server
1750 static void
1751 revarpinput(ldi_handle_t lh, struct netbuf *myaddr)
1753 struct ether_arp *ea;
1754 mblk_t *bp;
1755 mblk_t *mp;
1756 int rc;
1757 timestruc_t tv, give_up, now;
1760 * Choose the time at which we will give up, and resend our
1761 * request.
1763 gethrestime(&give_up);
1764 give_up.tv_sec += REVARP_TIMEO;
1765 wait:
1767 * Compute new timeout value.
1769 tv = give_up;
1770 gethrestime(&now);
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
1775 * okay.
1777 if (tv.tv_sec <= 0)
1778 return;
1779 rc = ldi_getmsg(lh, &mp, &tv);
1780 if (rc == ETIME) {
1781 goto out;
1782 } else if (rc != 0) {
1783 nfs_perror(rc, "revarpinput: ldi_getmsg failed: %m\n");
1784 return;
1787 if (mp->b_cont == NULL) {
1788 printf("revarpinput: b_cont == NULL\n");
1789 goto out;
1792 if (mp->b_datap->db_type != M_PROTO) {
1793 printf("revarpinput: bad header type %d\n",
1794 mp->b_datap->db_type);
1795 goto out;
1798 bp = mp->b_cont;
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));
1803 goto out;
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. */
1810 if (dldebug)
1811 printf("revarpinput: bad type %x\n",
1812 (ushort_t)ntohs(ea->arp_pro));
1813 freemsg(mp);
1814 goto wait;
1816 if ((ushort_t)ntohs(ea->arp_op) != REVARP_REPLY) {
1817 /* We could have received a broadcast arp request. */
1818 if (dldebug)
1819 printf("revarpinput: bad op %x\n",
1820 (ushort_t)ntohs(ea->arp_op));
1821 freemsg(mp);
1822 goto wait;
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);
1828 } else {
1829 /* We could have gotten a broadcast arp response. */
1830 if (dldebug)
1831 printf("revarpinput: got reply, but not my address\n");
1832 freemsg(mp);
1833 goto wait;
1835 out:
1836 freemsg(mp);
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
1843 * loadable module.
1845 static bool_t
1846 myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp)
1849 if (!xdr_int(xdrs, &fhsp->fhs_status))
1850 return (FALSE);
1851 if (fhsp->fhs_status == 0) {
1852 if (!myxdr_fhandle(xdrs, &fhsp->fhs_fh))
1853 return (FALSE);
1855 return (TRUE);
1859 * From nfs_xdr.c.
1861 * File access handle
1862 * The fhandle struct is treated a opaque data on the wire
1864 static bool_t
1865 myxdr_fhandle(XDR *xdrs, fhandle_t *fh)
1867 return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
1870 static bool_t
1871 myxdr_mountres3(XDR *xdrs, struct mountres3 *objp)
1873 if (!myxdr_mountstat3(xdrs, &objp->fhs_status))
1874 return (FALSE);
1875 switch (objp->fhs_status) {
1876 case MNT_OK:
1877 if (!myxdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
1878 return (FALSE);
1879 break;
1880 default:
1881 break;
1883 return (TRUE);
1886 static bool_t
1887 myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp)
1889 return (xdr_enum(xdrs, (enum_t *)objp));
1892 static bool_t
1893 myxdr_mountres3_ok(XDR *xdrs, struct mountres3_ok *objp)
1895 if (!myxdr_fhandle3(xdrs, &objp->fhandle))
1896 return (FALSE);
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))
1900 return (FALSE);
1901 return (TRUE);
1904 static bool_t
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)
1923 ushort_t port;
1924 int tries;
1925 enum clnt_stat stat;
1926 struct pmap pmap_parms;
1927 RPCB rpcb_parms;
1928 char *ua = NULL;
1930 port = 0;
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)
1946 break;
1947 cmn_err(CE_WARN,
1948 "pmap_kgetport: Portmapper not responding; still trying");
1951 if (stat == RPC_PROGUNAVAIL) {
1952 cmn_err(CE_WARN,
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)
1968 break;
1969 cmn_err(CE_WARN,
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);
1976 } else {
1977 /* Address unknown */
1978 stat = RPC_PROGUNAVAIL;
1983 if (stat == RPC_SUCCESS)
1984 ((struct sockaddr_in *)call_addr->buf)->sin_port = ntohs(port);
1986 return (stat);
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)
2007 CLIENT *cl;
2008 enum clnt_stat stat;
2009 rpcport_t port;
2010 int rc;
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);
2021 if (rc != 0) {
2022 nfs_perror(rc,
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");
2028 /* NOTREACHED */
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,
2044 tout, resp_addr);
2046 if (stat == RPC_SUCCESS) {
2047 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2048 htons((ushort_t)port);
2050 CLNT_DESTROY(cl);
2052 if (stat != RPC_PROGUNAVAIL)
2053 return (stat);
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);
2059 if (rc != 0) {
2060 nfs_perror(rc, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2061 return (RPC_SYSTEMERROR); /* XXX */
2064 if (cl == NULL) {
2065 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2066 /* NOTREACHED */
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,
2080 tout, resp_addr);
2082 if (stat == RPC_SUCCESS)
2083 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2084 rpc_uaddr2port(AF_INET, ua);
2085 CLNT_DESTROY(cl);
2087 return (stat);
2091 * XDR remote call arguments
2092 * written for XDR_ENCODE direction only
2094 static bool_t
2095 myxdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
2097 uint_t lenposition;
2098 uint_t argposition;
2099 uint_t position;
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))
2106 return (FALSE);
2107 argposition = XDR_GETPOS(xdrs);
2108 if (!(*(cap->xdr_args))(xdrs, cap->args_ptr))
2109 return (FALSE);
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))
2114 return (FALSE);
2115 XDR_SETPOS(xdrs, position);
2116 return (TRUE);
2118 return (FALSE);
2122 * XDR remote call results
2123 * written for XDR_DECODE direction only
2125 static bool_t
2126 myxdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
2128 caddr_t port_ptr;
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));
2136 return (FALSE);
2139 static bool_t
2140 myxdr_pmap(XDR *xdrs, struct pmap *regs)
2142 if (xdr_rpcprog(xdrs, &regs->pm_prog) &&
2143 xdr_rpcvers(xdrs, &regs->pm_vers) &&
2144 xdr_rpcprot(xdrs, &regs->pm_prot))
2145 return (xdr_rpcport(xdrs, &regs->pm_port));
2147 return (FALSE);
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)
2159 CLIENT *cl;
2160 struct timeval tv;
2161 enum clnt_stat cl_stat;
2162 int rc;
2164 rc = clnt_tli_kcreate(knconf, call_addr, prognum, versnum,
2165 0, retries, CRED(), &cl);
2166 if (rc) {
2167 nfs_perror(rc, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2168 return (RPC_SYSTEMERROR); /* XXX */
2170 tv.tv_sec = timeo;
2171 tv.tv_usec = 0;
2172 cl_stat = CLNT_CALL(cl, procnum, inproc, in, outproc, out, tv);
2173 AUTH_DESTROY(cl->cl_auth);
2174 CLNT_DESTROY(cl);
2175 return (cl_stat);
2179 * Configure the 'default' interface based on existing boot properties.
2181 static int
2182 bp_netconfig(void)
2184 char *str;
2185 struct in_addr my_ip, my_netmask, my_router, my_broadcast;
2186 struct sockaddr_in *sin;
2187 TIUSER *tiptr;
2188 int rc;
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",
2203 str);
2204 ddi_prop_free(str);
2205 if (dldebug)
2206 printf("host ip is %s\n",
2207 inet_ntoa(my_ip));
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",
2213 str);
2214 ddi_prop_free(str);
2215 if (dldebug)
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",
2223 str);
2224 ddi_prop_free(str);
2225 if (dldebug)
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));
2236 ddi_prop_free(str);
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",
2242 str);
2243 ddi_prop_free(str);
2244 if (dldebug)
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))
2257 return (-1);
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");
2273 return (rc);
2276 if ((rc = dlifconfig(tiptr, &my_ip, &my_netmask, &my_broadcast,
2277 0)) < 0) {
2278 nfs_perror(rc, "bp_netconfig: dlifconfig failed: %m.\n");
2279 (void) t_kclose(tiptr, 0);
2280 return (rc);
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) {
2299 nfs_perror(rc,
2300 "bp_netconfig: couldn't add route: %m.\n");
2301 (void) t_kclose(tiptr, 0);
2302 return (rc);
2306 (void) t_kclose(tiptr, 0);
2308 return (0);
2312 * The network device we will use to boot from is plumbed. Extract the details
2313 * from rootfs.
2315 static void
2316 init_config(void)
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) &&
2336 (whoami() != 0))
2337 cmn_err(CE_WARN,
2338 "%s: no response from interface", ifname);
2339 else if (dldebug)
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[] = {
2348 #define OPT_RO 0
2349 MNTOPT_RO,
2350 #define OPT_RW 1
2351 MNTOPT_RW,
2352 #define OPT_QUOTA 2
2353 MNTOPT_QUOTA,
2354 #define OPT_NOQUOTA 3
2355 MNTOPT_NOQUOTA,
2356 #define OPT_SOFT 4
2357 MNTOPT_SOFT,
2358 #define OPT_HARD 5
2359 MNTOPT_HARD,
2360 #define OPT_SUID 6
2361 MNTOPT_SUID,
2362 #define OPT_NOSUID 7
2363 MNTOPT_NOSUID,
2364 #define OPT_GRPID 8
2365 MNTOPT_GRPID,
2366 #define OPT_REMOUNT 9
2367 MNTOPT_REMOUNT,
2368 #define OPT_NOSUB 10
2369 MNTOPT_NOSUB,
2370 #define OPT_INTR 11
2371 MNTOPT_INTR,
2372 #define OPT_NOINTR 12
2373 MNTOPT_NOINTR,
2374 #define OPT_PORT 13
2375 MNTOPT_PORT,
2376 #define OPT_SECURE 14
2377 MNTOPT_SECURE,
2378 #define OPT_RSIZE 15
2379 MNTOPT_RSIZE,
2380 #define OPT_WSIZE 16
2381 MNTOPT_WSIZE,
2382 #define OPT_TIMEO 17
2383 MNTOPT_TIMEO,
2384 #define OPT_RETRANS 18
2385 MNTOPT_RETRANS,
2386 #define OPT_ACTIMEO 19
2387 MNTOPT_ACTIMEO,
2388 #define OPT_ACREGMIN 20
2389 MNTOPT_ACREGMIN,
2390 #define OPT_ACREGMAX 21
2391 MNTOPT_ACREGMAX,
2392 #define OPT_ACDIRMIN 22
2393 MNTOPT_ACDIRMIN,
2394 #define OPT_ACDIRMAX 23
2395 MNTOPT_ACDIRMAX,
2396 #define OPT_BG 24
2397 MNTOPT_BG,
2398 #define OPT_FG 25
2399 MNTOPT_FG,
2400 #define OPT_RETRY 26
2401 MNTOPT_RETRY,
2402 #define OPT_NOAC 27
2403 MNTOPT_NOAC,
2404 #define OPT_NOCTO 28
2405 MNTOPT_NOCTO,
2406 #define OPT_LLOCK 29
2407 MNTOPT_LLOCK,
2408 #define OPT_POSIX 30
2409 MNTOPT_POSIX,
2410 #define OPT_VERS 31
2411 MNTOPT_VERS,
2412 #define OPT_PROTO 32
2413 MNTOPT_PROTO,
2414 #define OPT_SEMISOFT 33
2415 MNTOPT_SEMISOFT,
2416 #define OPT_NOPRINT 34
2417 MNTOPT_NOPRINT,
2418 #define OPT_SEC 35
2419 MNTOPT_SEC,
2420 #define OPT_LARGEFILES 36
2421 MNTOPT_LARGEFILES,
2422 #define OPT_NOLARGEFILES 37
2423 MNTOPT_NOLARGEFILES,
2424 #define OPT_PUBLIC 38
2425 MNTOPT_PUBLIC,
2426 #define OPT_DIRECTIO 39
2427 MNTOPT_FORCEDIRECTIO,
2428 #define OPT_NODIRECTIO 40
2429 MNTOPT_NOFORCEDIRECTIO,
2430 #define OPT_XATTR 41
2431 MNTOPT_XATTR,
2432 #define OPT_NOXATTR 42
2433 MNTOPT_NOXATTR,
2434 #define OPT_DEVICES 43
2435 MNTOPT_DEVICES,
2436 #define OPT_NODEVICES 44
2437 MNTOPT_NODEVICES,
2438 #define OPT_SETUID 45
2439 MNTOPT_SETUID,
2440 #define OPT_NOSETUID 46
2441 MNTOPT_NOSETUID,
2442 #define OPT_EXEC 47
2443 MNTOPT_EXEC,
2444 #define OPT_NOEXEC 48
2445 MNTOPT_NOEXEC,
2446 NULL
2449 static int
2450 isdigit(int ch)
2452 return (ch >= '0' && ch <= '9');
2455 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2456 #define bad(val) (val == NULL || !isdigit(*val))
2458 static int
2459 atoi(const char *p)
2461 int n;
2462 int c, neg = 0;
2464 if (!isdigit(c = *p)) {
2465 while (isspace(c))
2466 c = *++p;
2467 switch (c) {
2468 case '-':
2469 neg++;
2470 /* FALLTHROUGH */
2471 case '+':
2472 c = *++p;
2474 if (!isdigit(c))
2475 return (0);
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;
2495 static int
2496 init_mountopts(struct nfs_args *args, int version, struct knetconfig **dl_cf,
2497 int *vfsflags)
2499 char servername[SYS_NMLN];
2500 static int first = 0;
2501 struct netbuf server_address;
2502 char *opts, *val;
2503 int vers;
2504 struct knetconfig *cf = *dl_cf;
2505 char rootoptsbuf[256];
2508 * Set default mount options
2510 args->flags = nfs_rootopts;
2511 args->rsize = 0;
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;
2521 *vfsflags = 0;
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.
2528 if (first == 0) {
2529 first++;
2531 init_netbuf(&server_address);
2533 if (getfile("rootopts", servername, &server_address,
2534 rootopts)) {
2535 rootopts[0] = '\0';
2536 free_netbuf(&server_address);
2537 goto sanity;
2539 free_netbuf(&server_address);
2542 if (dldebug)
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';
2550 opts = rootoptsbuf;
2551 while (*opts) {
2552 int opt;
2554 switch (opt = getsubopt(&opts, optlist, &val)) {
2556 * Options that are defaults or meaningless so ignored
2558 case OPT_QUOTA:
2559 case OPT_NOQUOTA:
2560 case OPT_SUID:
2561 case OPT_DEVICES:
2562 case OPT_SETUID:
2563 case OPT_BG:
2564 case OPT_FG:
2565 case OPT_RETRY:
2566 case OPT_POSIX:
2567 case OPT_LARGEFILES:
2568 case OPT_XATTR:
2569 case OPT_NOXATTR:
2570 case OPT_EXEC:
2571 break;
2572 case OPT_RO:
2573 *vfsflags |= MS_RDONLY;
2574 break;
2575 case OPT_RW:
2576 *vfsflags &= ~(MS_RDONLY);
2577 break;
2578 case OPT_SOFT:
2579 args->flags |= NFSMNT_SOFT;
2580 args->flags &= ~(NFSMNT_SEMISOFT);
2581 break;
2582 case OPT_SEMISOFT:
2583 args->flags |= NFSMNT_SOFT;
2584 args->flags |= NFSMNT_SEMISOFT;
2585 break;
2586 case OPT_HARD:
2587 args->flags &= ~(NFSMNT_SOFT);
2588 args->flags &= ~(NFSMNT_SEMISOFT);
2589 break;
2590 case OPT_NOSUID:
2591 case OPT_NODEVICES:
2592 case OPT_NOSETUID:
2593 case OPT_NOEXEC:
2594 cmn_err(CE_WARN,
2595 "nfs_dlboot: may not set root partition %s",
2596 optlist[opt]);
2597 break;
2598 case OPT_GRPID:
2599 args->flags |= NFSMNT_GRPID;
2600 break;
2601 case OPT_REMOUNT:
2602 cmn_err(CE_WARN,
2603 "nfs_dlboot: may not remount root partition");
2604 break;
2605 case OPT_INTR:
2606 args->flags |= NFSMNT_INT;
2607 break;
2608 case OPT_NOINTR:
2609 args->flags &= ~(NFSMNT_INT);
2610 break;
2611 case OPT_NOAC:
2612 args->flags |= NFSMNT_NOAC;
2613 break;
2614 case OPT_PORT:
2615 cmn_err(CE_WARN,
2616 "nfs_dlboot: may not change root port number");
2617 break;
2618 case OPT_SECURE:
2619 cmn_err(CE_WARN,
2620 "nfs_dlboot: root mounted auth_unix, secure ignored");
2621 break;
2622 case OPT_NOCTO:
2623 args->flags |= NFSMNT_NOCTO;
2624 break;
2625 case OPT_RSIZE:
2626 if (bad(val)) {
2627 cmn_err(CE_WARN,
2628 "nfs_dlboot: invalid option: rsize");
2629 break;
2631 args->flags |= NFSMNT_RSIZE;
2632 args->rsize = atoi(val);
2633 break;
2634 case OPT_WSIZE:
2635 if (bad(val)) {
2636 cmn_err(CE_WARN,
2637 "nfs_dlboot: invalid option: wsize");
2638 break;
2640 args->flags |= NFSMNT_WSIZE;
2641 args->wsize = atoi(val);
2642 break;
2643 case OPT_TIMEO:
2644 if (bad(val)) {
2645 cmn_err(CE_WARN,
2646 "nfs_dlboot: invalid option: timeo");
2647 break;
2649 args->flags |= NFSMNT_TIMEO;
2650 args->timeo = atoi(val);
2651 break;
2652 case OPT_RETRANS:
2653 if (bad(val)) {
2654 cmn_err(CE_WARN,
2655 "nfs_dlboot: invalid option: retrans");
2656 break;
2658 args->flags |= NFSMNT_RETRANS;
2659 args->retrans = atoi(val);
2660 break;
2661 case OPT_ACTIMEO:
2662 if (bad(val)) {
2663 cmn_err(CE_WARN,
2664 "nfs_dlboot: invalid option: actimeo");
2665 break;
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);
2673 break;
2674 case OPT_ACREGMIN:
2675 if (bad(val)) {
2676 cmn_err(CE_WARN,
2677 "nfs_dlboot: invalid option: acregmin");
2678 break;
2680 args->flags |= NFSMNT_ACREGMIN;
2681 args->acregmin = atoi(val);
2682 break;
2683 case OPT_ACREGMAX:
2684 if (bad(val)) {
2685 cmn_err(CE_WARN,
2686 "nfs_dlboot: invalid option: acregmax");
2687 break;
2689 args->flags |= NFSMNT_ACREGMAX;
2690 args->acregmax = atoi(val);
2691 break;
2692 case OPT_ACDIRMIN:
2693 if (bad(val)) {
2694 cmn_err(CE_WARN,
2695 "nfs_dlboot: invalid option: acdirmin");
2696 break;
2698 args->flags |= NFSMNT_ACDIRMIN;
2699 args->acdirmin = atoi(val);
2700 break;
2701 case OPT_ACDIRMAX:
2702 if (bad(val)) {
2703 cmn_err(CE_WARN,
2704 "nfs_dlboot: invalid option: acdirmax");
2705 break;
2707 args->flags |= NFSMNT_ACDIRMAX;
2708 args->acdirmax = atoi(val);
2709 break;
2710 case OPT_LLOCK:
2711 args->flags |= NFSMNT_LLOCK;
2712 break;
2713 case OPT_VERS:
2714 if (bad(val)) {
2715 cmn_err(CE_WARN,
2716 "nfs_dlboot: invalid option: vers");
2717 break;
2719 vers = atoi(val);
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) {
2728 cmn_err(CE_WARN,
2729 "nfs_dlboot: version %d unavailable",
2730 vers);
2731 return (EINVAL);
2733 break;
2734 case OPT_PROTO:
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
2746 * only server.
2748 if (strcmp(cf->knc_proto, val) == 0)
2749 break;
2751 * If we chose UDP, they must have requested TCP
2753 if (strcmp(cf->knc_proto, NC_TCP) != 0) {
2754 cmn_err(CE_WARN,
2755 "nfs_dlboot: TCP protocol unavailable");
2756 return (EINVAL);
2759 * They can only have requested UDP
2761 if (strcmp(val, NC_UDP) != 0) {
2762 cmn_err(CE_WARN,
2763 "nfs_dlboot: unknown protocol");
2764 return (EINVAL);
2766 *dl_cf = &dl_udp_netconf;
2767 break;
2768 case OPT_NOPRINT:
2769 args->flags |= NFSMNT_NOPRINT;
2770 break;
2771 case OPT_NOLARGEFILES:
2772 cmn_err(CE_WARN,
2773 "nfs_dlboot: NFS can't support nolargefiles");
2774 break;
2775 case OPT_SEC:
2776 cmn_err(CE_WARN,
2777 "nfs_dlboot: root mounted auth_unix, sec ignored");
2778 break;
2780 case OPT_DIRECTIO:
2781 args->flags |= NFSMNT_DIRECTIO;
2782 break;
2784 case OPT_NODIRECTIO:
2785 args->flags &= ~(NFSMNT_DIRECTIO);
2786 break;
2788 default:
2789 cmn_err(CE_WARN,
2790 "nfs_dlboot: ignoring invalid option \"%s\"", val);
2791 break;
2794 sanity:
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;
2805 else
2806 args->rsize = nfs_root_rsize;
2807 return (0);
2810 * No less than 512 bytes, otherwise it will take forever to boot
2812 if (args->rsize < 512)
2813 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;
2820 return (0);