Merge illumos-gate
[unleashed.git] / kernel / fs / nfs / nfs_dlinet.c
blobe3bbdb7f92c6c361547215941b6f8f7a1359ef00
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.
27 * Copyright (c) 2018, Joyent, Inc.
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/systm.h>
33 #include <sys/cred.h>
34 #include <sys/user.h>
35 #include <sys/file.h>
36 #include <sys/stream.h>
37 #include <sys/strsubr.h>
38 #include <sys/stropts.h>
39 #include <sys/strsun.h>
40 #include <sys/debug.h>
41 #include <sys/tiuser.h>
42 #include <sys/sockio.h>
43 #include <sys/socket.h>
44 #include <sys/t_kuser.h>
45 #include <sys/utsname.h>
46 #include <sys/systeminfo.h>
47 #include <sys/netconfig.h>
48 #include <sys/ethernet.h>
49 #include <sys/dlpi.h>
50 #include <sys/vfs.h>
51 #include <sys/sysmacros.h>
52 #include <sys/bootconf.h>
53 #include <sys/bootprops.h>
54 #include <sys/cmn_err.h>
55 #include <sys/promif.h>
56 #include <sys/mount.h>
58 #include <net/if.h>
59 #include <net/route.h>
61 #include <netinet/in.h>
62 #include <netinet/arp.h>
63 #include <netinet/dhcp.h>
64 #include <netinet/inetutil.h>
65 #include <dhcp_impl.h>
66 #include <sys/sunos_dhcp_class.h>
68 #include <rpc/types.h>
69 #include <rpc/rpc.h>
70 #include <rpc/xdr.h>
71 #include <rpc/auth.h>
72 #include <rpc/clnt.h>
73 #include <rpc/pmap_clnt.h>
74 #include <rpc/pmap_rmt.h>
75 #include <rpc/pmap_prot.h>
76 #include <rpc/bootparam.h>
77 #include <rpc/rpcb_prot.h>
79 #include <nfs/nfs.h>
80 #include <nfs/nfs4.h>
81 #include <nfs/nfs_clnt.h>
82 #include <nfs/mount.h>
83 #include <sys/mntent.h>
85 #include <sys/kstr.h>
86 #include <sys/sunddi.h>
87 #include <sys/sunldi.h>
88 #include <sys/esunddi.h>
90 #include <sys/errno.h>
91 #include <sys/modctl.h>
94 * RPC timers and retries
96 #define PMAP_RETRIES 5
97 #define DEFAULT_RETRIES 3
98 #define GETFILE_RETRIES 2
100 #define DEFAULT_TIMEO 3
101 #define WHOAMI_TIMEO 20
102 #define REVARP_TIMEO 5
103 #define GETFILE_TIMEO 1
106 * These are from the rpcgen'd version of mount.h XXX
108 #define MOUNTPROG 100005
109 #define MOUNTPROC_MNT 1
110 #define MOUNTVERS 1
111 #define MOUNTVERS_POSIX 2
112 #define MOUNTVERS3 3
114 struct fhstatus {
115 int fhs_status;
116 fhandle_t fhs_fh;
119 #define FHSIZE3 64
121 struct fhandle3 {
122 uint_t fhandle3_len;
123 char *fhandle3_val;
126 enum mountstat3 {
127 MNT_OK = 0,
128 MNT3ERR_PERM = 1,
129 MNT3ERR_NOENT = 2,
130 MNT3ERR_IO = 5,
131 MNT3ERR_ACCES = 13,
132 MNT3ERR_NOTDIR = 20,
133 MNT3ERR_INVAL = 22,
134 MNT3ERR_NAMETOOLONG = 63,
135 MNT3ERR_NOTSUPP = 10004,
136 MNT3ERR_SERVERFAULT = 10006
139 struct mountres3_ok {
140 struct fhandle3 fhandle;
141 struct {
142 uint_t auth_flavors_len;
143 int *auth_flavors_val;
144 } auth_flavors;
147 struct mountres3 {
148 enum mountstat3 fhs_status;
149 union {
150 struct mountres3_ok mountinfo;
151 } mountres3_u;
155 * DLPI address format.
157 struct dladdr {
158 uchar_t dl_phys[6];
159 ushort_t dl_sap;
162 static struct modlmisc modlmisc = {
163 &mod_miscops, "Boot diskless"
166 static struct modlinkage modlinkage = {
167 MODREV_1, (void *)&modlmisc, NULL
170 static int dldebug;
173 _init(void)
175 return (mod_install(&modlinkage));
179 _fini(void)
181 return (mod_remove(&modlinkage));
185 _info(struct modinfo *modinfop)
187 return (mod_info(&modlinkage, modinfop));
191 static enum clnt_stat pmap_rmt_call(struct knetconfig *, struct netbuf *,
192 bool_t, rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
193 caddr_t, xdrproc_t, caddr_t, struct timeval,
194 struct netbuf *);
195 static bool_t myxdr_rmtcall_args(XDR *, struct rmtcallargs *);
196 static bool_t myxdr_rmtcallres(XDR *, struct rmtcallres *);
197 static bool_t myxdr_pmap(XDR *, struct pmap *);
198 static bool_t myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp);
199 static bool_t myxdr_fhandle(XDR *xdrs, fhandle_t *fh);
200 static bool_t myxdr_mountres3(XDR *xdrs, struct mountres3 *objp);
201 static bool_t myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp);
202 static bool_t myxdr_mountres3_ok(XDR *xdrs,
203 struct mountres3_ok *objp);
204 static bool_t myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp);
205 static enum clnt_stat pmap_kgetport(struct knetconfig *, struct netbuf *,
206 rpcprog_t, rpcvers_t, rpcprot_t);
207 static enum clnt_stat mycallrpc(struct knetconfig *, struct netbuf *,
208 rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
209 char *, xdrproc_t, char *, int, int);
210 static int ifioctl(TIUSER *, int, struct netbuf *);
211 static int getfile(char *, char *, struct netbuf *, char *);
212 static int ping_prog(struct netbuf *, uint_t prog, uint_t vers,
213 int proto, enum clnt_stat *);
214 static int mountnfs(struct netbuf *, char *, char *,
215 fhandle_t *, int *);
216 static int mountnfs3(struct netbuf *, char *, char *,
217 nfs_fh3 *, int *);
218 static int init_mountopts(struct nfs_args *, int,
219 struct knetconfig **, int *);
220 static int revarp_myaddr(TIUSER *);
221 static void revarp_start(ldi_handle_t, struct netbuf *);
222 static void revarpinput(ldi_handle_t, struct netbuf *);
223 static void init_netbuf(struct netbuf *);
224 static void free_netbuf(struct netbuf *);
225 static int rtioctl(TIUSER *, int, struct rtentry *);
226 static void init_config(void);
228 static void cacheinit(void);
229 static int cacheinfo(char *, int, struct netbuf *, char *, int);
230 static int dlifconfig(TIUSER *, struct in_addr *, struct in_addr *,
231 struct in_addr *, uint_t);
232 static int setifflags(TIUSER *, uint_t);
234 static char *inet_ntoa(struct in_addr);
235 static int inet_aton(char *, uchar_t *);
236 static int isdigit(int);
239 * Should be in some common
240 * ethernet source file.
242 static struct ether_addr etherbroadcastaddr = {
243 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
246 static struct ether_addr myether;
249 * "ifname" is the interface name/unit as read from the boot
250 * arguments.
251 * "ndev" is the major device number of the network interface
252 * used to boot from.
253 * "ifunit" it the physical point of attachment for the network
254 * interface used to boot from.
256 * Both of these are initialized in "init_config()".
259 static char ifname[IFNAMSIZ];
260 static char ndev_path[MAXPATHLEN];
261 static int ifunit;
264 * XXX these should be shared
266 static struct knetconfig dl_udp_netconf = {
267 NC_TPI_CLTS, /* semantics */
268 NC_INET, /* family */
269 NC_UDP, /* protocol */
270 0, /* device */
273 static struct knetconfig dl_tcp_netconf = {
274 NC_TPI_COTS, /* semantics */
275 NC_INET, /* family */
276 NC_TCP, /* protocol */
277 0, /* device */
280 /* parameters from DHCP or bootparamd */
281 static PKT_LIST *pl = NULL;
282 static uchar_t server_ip[4];
283 static uchar_t dhcp_server_ip[4];
284 static char *server_name_c, *server_path_c;
285 static char rootopts[256];
288 * XXX Until we get the nfsmapid deadlocks all fixed, don't allow
289 * XXX a v4 root mount.
291 int nfs4_no_diskless_root_support = 1;
294 mount_root(char *name, char *path, int version, struct nfs_args *args,
295 int *vfsflags)
297 int rc;
298 int proto;
299 struct knetconfig *dl_cf;
300 static int init_done = 0;
301 enum clnt_stat stat;
303 if (dldebug)
304 printf("mount_root: name=%s\n", name);
306 if (init_done == 0) {
307 init_config();
308 init_done = 1;
311 init_netbuf(args->addr);
313 do {
314 rc = getfile(name, args->hostname, args->addr, path);
315 } while (rc == ETIMEDOUT);
317 if (rc) {
318 free_netbuf(args->addr);
319 return (rc);
322 ASSERT(args->knconf->knc_protofmly != NULL);
323 ASSERT(args->knconf->knc_proto != NULL);
325 switch (version) {
326 case NFS_VERSION:
327 rc = mountnfs(args->addr, args->hostname, path,
328 (fhandle_t *)args->fh, &proto);
329 break;
330 case NFS_V3:
331 rc = mountnfs3(args->addr, args->hostname, path,
332 (nfs_fh3 *)args->fh, &proto);
333 break;
334 case NFS_V4:
335 ((struct sockaddr_in *)args->addr->buf)->sin_port =
336 htons(NFS_PORT);
337 if (ping_prog(args->addr, NFS_PROGRAM, NFS_V4, IPPROTO_TCP,
338 &stat)) {
339 proto = IPPROTO_TCP;
340 rc = 0;
341 } else {
342 switch (stat) {
343 case RPC_PROGVERSMISMATCH:
344 case RPC_XPRTFAILED:
346 * Common failures if v4 unsupported or no TCP
348 rc = EPROTONOSUPPORT;
349 break;
350 default:
351 rc = ENXIO;
354 if (nfs4_no_diskless_root_support)
355 rc = EPROTONOSUPPORT;
356 break;
357 default:
358 rc = EPROTONOSUPPORT;
359 break;
362 if (rc)
363 goto errout;
365 switch (proto) {
366 case IPPROTO_TCP:
367 dl_cf = &dl_tcp_netconf;
368 break;
369 case IPPROTO_UDP:
370 default:
371 dl_cf = &dl_udp_netconf;
372 break;
375 rc = init_mountopts(args, version, &dl_cf, vfsflags);
378 * Copy knetconfig information from the template, note that the
379 * rdev field has been set by init_config above.
381 args->knconf->knc_semantics = dl_cf->knc_semantics;
382 args->knconf->knc_rdev = dl_cf->knc_rdev;
383 (void) strcpy(args->knconf->knc_protofmly, dl_cf->knc_protofmly);
384 (void) strcpy(args->knconf->knc_proto, dl_cf->knc_proto);
386 errout:
387 if (dldebug) {
388 if (rc)
389 nfs_perror(rc, "mount_root: mount %s:%s failed: %m\n",
390 args->hostname, path);
391 else
392 printf("mount_root: leaving\n");
395 return (rc);
399 * Call mount daemon on server `sa' to mount path.
400 * `port' is set to nfs port and fh is the fhandle
401 * returned from the server.
403 static int
404 mountnfs(struct netbuf *sa, char *server,
405 char *path, fhandle_t *fh, int *proto)
407 struct fhstatus fhs;
408 enum clnt_stat stat;
410 if (dldebug)
411 printf("mountnfs: entered\n");
414 * Get the port number for the mount program.
415 * pmap_kgetport first tries a SunOS portmapper
416 * and, if no reply is received, will try a
417 * SVR4 rpcbind. Either way, `sa' is set to
418 * the correct address.
420 do {
421 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
422 (rpcvers_t)MOUNTVERS, (rpcprot_t)IPPROTO_UDP);
424 if (stat == RPC_TIMEDOUT) {
425 cmn_err(CE_WARN,
426 "mountnfs: %s:%s portmap not responding",
427 server, path);
428 } else if (stat != RPC_SUCCESS) {
429 cmn_err(CE_WARN,
430 "mountnfs: pmap_kgetport RPC error %d (%s).",
431 stat, clnt_sperrno(stat));
432 return (ENXIO); /* XXX */
434 } while (stat == RPC_TIMEDOUT);
437 * The correct port number has been
438 * put into `sa' by pmap_kgetport().
440 do {
441 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
442 (rpcvers_t)MOUNTVERS, (rpcproc_t)MOUNTPROC_MNT,
443 xdr_bp_path_t, (char *)&path,
444 myxdr_fhstatus, (char *)&fhs,
445 DEFAULT_TIMEO, DEFAULT_RETRIES);
446 if (stat == RPC_TIMEDOUT) {
447 cmn_err(CE_WARN,
448 "mountnfs: %s:%s mount server not responding",
449 server, path);
451 } while (stat == RPC_TIMEDOUT);
453 if (stat != RPC_SUCCESS) {
454 cmn_err(CE_WARN, "mountnfs: RPC failed: error %d (%s).",
455 stat, clnt_sperrno(stat));
456 return (ENXIO); /* XXX */
459 ((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT);
461 *fh = fhs.fhs_fh;
462 if (fhs.fhs_status != 0) {
463 if (dldebug)
464 printf("mountnfs: fhs_status %d\n", fhs.fhs_status);
465 return (ENXIO); /* XXX */
468 *proto = IPPROTO_UDP;
470 if (ping_prog(sa, NFS_PROGRAM, NFS_VERSION, IPPROTO_TCP, NULL))
471 *proto = IPPROTO_TCP;
473 if (dldebug)
474 printf("mountnfs: leaving\n");
475 return (0);
479 * Call mount daemon on server `sa' to mount path.
480 * `port' is set to nfs port and fh is the fhandle
481 * returned from the server.
483 static int
484 mountnfs3(struct netbuf *sa, char *server, char *path, nfs_fh3 *fh, int *proto)
486 struct mountres3 mountres3;
487 enum clnt_stat stat;
488 int ret = 0;
490 if (dldebug)
491 printf("mountnfs3: entered\n");
494 * Get the port number for the mount program.
495 * pmap_kgetport first tries a SunOS portmapper
496 * and, if no reply is received, will try a
497 * SVR4 rpcbind. Either way, `sa' is set to
498 * the correct address.
500 do {
501 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
502 (rpcvers_t)MOUNTVERS3, (rpcprot_t)IPPROTO_UDP);
504 if (stat == RPC_PROGVERSMISMATCH) {
505 if (dldebug)
506 printf("mountnfs3: program/version mismatch\n");
507 return (EPROTONOSUPPORT); /* XXX */
508 } else if (stat == RPC_TIMEDOUT) {
509 cmn_err(CE_WARN,
510 "mountnfs3: %s:%s portmap not responding",
511 server, path);
512 } else if (stat != RPC_SUCCESS) {
513 cmn_err(CE_WARN,
514 "mountnfs3: pmap_kgetport RPC error %d (%s).",
515 stat, clnt_sperrno(stat));
516 return (ENXIO); /* XXX */
518 } while (stat == RPC_TIMEDOUT);
520 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = NULL;
521 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = NULL;
524 * The correct port number has been
525 * put into `sa' by pmap_kgetport().
527 do {
528 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
529 (rpcvers_t)MOUNTVERS3, (rpcproc_t)MOUNTPROC_MNT,
530 xdr_bp_path_t, (char *)&path,
531 myxdr_mountres3, (char *)&mountres3,
532 DEFAULT_TIMEO, DEFAULT_RETRIES);
533 if (stat == RPC_TIMEDOUT) {
534 cmn_err(CE_WARN,
535 "mountnfs3: %s:%s mount server not responding",
536 server, path);
538 } while (stat == RPC_TIMEDOUT);
540 if (stat == RPC_PROGVERSMISMATCH) {
541 if (dldebug)
542 printf("mountnfs3: program/version mismatch\n");
543 ret = EPROTONOSUPPORT;
544 goto out;
546 if (stat != RPC_SUCCESS) {
547 cmn_err(CE_WARN, "mountnfs3: RPC failed: error %d (%s).",
548 stat, clnt_sperrno(stat));
549 ret = ENXIO; /* XXX */
550 goto out;
553 if (mountres3.fhs_status != MNT_OK) {
554 if (dldebug)
555 printf("mountnfs3: fhs_status %d\n",
556 mountres3.fhs_status);
557 ret = ENXIO; /* XXX */
558 goto out;
561 ((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT);
563 *proto = IPPROTO_UDP;
565 if (ping_prog(sa, NFS_PROGRAM, NFS_V3, IPPROTO_TCP, NULL)) {
566 *proto = IPPROTO_TCP;
569 fh->fh3_length = mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
570 bcopy(mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
571 fh->fh3_u.data, fh->fh3_length);
573 out:
574 xdr_free(myxdr_mountres3, (caddr_t)&mountres3);
576 if (dldebug)
577 printf("mountnfs3: leaving\n");
578 return (ret);
581 static int
582 ping_prog(struct netbuf *call_addr, uint_t prog, uint_t vers, int proto,
583 enum clnt_stat *statp)
585 struct knetconfig *knconf;
586 enum clnt_stat stat;
587 int retries = DEFAULT_RETRIES;
589 switch (proto) {
590 case IPPROTO_TCP:
591 knconf = &dl_tcp_netconf;
592 break;
593 case IPPROTO_UDP:
594 knconf = &dl_udp_netconf;
595 break;
596 default:
597 return (0);
600 do {
601 stat = mycallrpc(knconf, call_addr, prog, vers, NULLPROC,
602 xdr_void, NULL, xdr_void, NULL,
603 DEFAULT_TIMEO, DEFAULT_RETRIES);
605 if (dldebug)
606 printf("ping_prog: %d return %d (%s)\n", proto, stat,
607 clnt_sperrno(stat));
609 * Special case for TCP, it may "timeout" because it failed
610 * to establish an initial connection but it doesn't
611 * actually retry, so we do the retry.
612 * Persistence pays in diskless.
614 } while (stat == RPC_TIMEDOUT && proto == IPPROTO_TCP && retries--);
616 if (statp != NULL)
617 *statp = stat;
619 if (stat != RPC_SUCCESS)
620 return (0);
621 return (1);
624 static struct netbuf bootparam_addr;
627 * Returns after filling in the following global variables:
628 * bootparam_addr,
629 * utsname.nodename,
630 * srpc_domain.
632 static int
633 whoami(void)
635 TIUSER *tiptr;
636 struct netbuf sa;
637 struct netbuf req;
638 struct bp_whoami_arg arg;
639 struct bp_whoami_res res;
640 struct timeval tv;
641 enum clnt_stat stat;
642 int rc;
643 size_t namelen;
644 int printed_waiting_msg;
646 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
647 FREAD|FWRITE, &tiptr, CRED())) != 0) {
648 nfs_perror(rc, "whoami: t_kopen udp failed: %m.\n");
652 * Find out our local (IP) address.
654 if (rc = revarp_myaddr(tiptr)) {
655 nfs_perror(rc, "whoami: revarp_myaddr failed: %m.\n");
656 (void) t_kclose(tiptr, 0);
657 return (rc);
660 /* explicitly use the limited broadcast address */
661 init_netbuf(&sa);
662 ((struct sockaddr_in *)sa.buf)->sin_family = AF_INET;
663 ((struct sockaddr_in *)sa.buf)->sin_addr.s_addr =
664 htonl(INADDR_BROADCAST);
665 sa.len = sizeof (struct sockaddr_in);
668 * Pick up our local (IP) address.
670 init_netbuf(&req);
671 if (rc = ifioctl(tiptr, SIOCGIFADDR, &req)) {
672 nfs_perror(rc,
673 "whoami: couldn't get my IP address: %m.\n");
674 free_netbuf(&sa);
675 free_netbuf(&req);
676 (void) t_kclose(tiptr, 0);
677 return (rc);
681 * Set up the arguments expected by bootparamd.
683 arg.client_address.address_type = IP_ADDR_TYPE;
684 bcopy(&((struct sockaddr_in *)req.buf)->sin_addr,
685 &arg.client_address.bp_address.ip_addr, sizeof (struct in_addr));
687 free_netbuf(&req);
689 init_netbuf(&bootparam_addr);
692 * Initial retransmission interval
694 tv.tv_sec = DEFAULT_TIMEO;
695 tv.tv_usec = 0;
696 res.client_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
697 res.domain_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
700 * Do a broadcast call to find a bootparam daemon that
701 * will tell us our hostname, domainname and any
702 * router that we have to use to talk to our NFS server.
704 printed_waiting_msg = 0;
705 do {
707 * pmap_rmt_call will first try the SunOS portmapper
708 * and if no reply is received will then try the SVR4
709 * rpcbind.
710 * Either way, `bootparam_addr' will be set to the
711 * correct address for the bootparamd that responds.
713 stat = pmap_rmt_call(&dl_udp_netconf, &sa, TRUE, BOOTPARAMPROG,
714 BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI,
715 xdr_bp_whoami_arg, (caddr_t)&arg,
716 xdr_bp_whoami_res, (caddr_t)&res,
717 tv, &bootparam_addr);
718 if (stat == RPC_TIMEDOUT && !printed_waiting_msg) {
719 cmn_err(CE_WARN,
720 "No bootparam server responding; still trying");
721 printed_waiting_msg = 1;
724 * Retransmission interval for second and subsequent tries.
725 * We expect first pmap_rmt_call to retransmit and backoff to
726 * at least this value.
728 tv.tv_sec = WHOAMI_TIMEO;
729 tv.tv_usec = 0;
730 } while (stat == RPC_TIMEDOUT);
732 if (printed_waiting_msg)
733 printf("Bootparam response received\n");
735 if (stat != RPC_SUCCESS) {
736 /* XXX should get real error here */
737 rc = ENXIO;
738 cmn_err(CE_WARN,
739 "whoami: bootparam RPC failed: error %d (%s).",
740 stat, clnt_sperrno(stat));
741 goto done;
744 namelen = strlen(res.client_name);
745 if (namelen > sizeof (utsname.nodename)) {
746 printf("whoami: hostname too long");
747 rc = ENAMETOOLONG;
748 goto done;
750 if (namelen != 0) {
751 bcopy(res.client_name, &utsname.nodename, namelen);
752 cmn_err(CE_CONT, "?hostname: %s\n", utsname.nodename);
753 } else {
754 printf("whoami: no host name\n");
755 rc = ENXIO;
756 goto done;
759 namelen = strlen(res.domain_name);
760 if (namelen != 0) {
761 if (namelen > SYS_NMLN) {
762 printf("whoami: domainname too long");
763 rc = ENAMETOOLONG;
764 goto done;
766 bcopy(res.domain_name, &srpc_domain, namelen);
767 cmn_err(CE_CONT, "?domainname: %s\n", srpc_domain);
768 } else {
769 printf("whoami: no domain name\n");
772 if (res.router_address.address_type == IP_ADDR_TYPE) {
773 struct rtentry rtentry;
774 struct sockaddr_in *sin;
775 struct in_addr ipaddr;
777 bcopy(&res.router_address.bp_address.ip_addr, &ipaddr,
778 sizeof (struct in_addr));
780 if (ipaddr.s_addr != 0) {
781 sin = (struct sockaddr_in *)&rtentry.rt_dst;
782 bzero(sin, sizeof (*sin));
783 sin->sin_family = AF_INET;
785 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
786 bzero(sin, sizeof (*sin));
787 sin->sin_family = AF_INET;
788 sin->sin_addr.s_addr = ipaddr.s_addr;
790 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
792 if (rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) {
793 nfs_perror(rc,
794 "whoami: couldn't add route: %m.\n");
795 goto done;
798 } else {
799 printf("whoami: unknown gateway addr family %d\n",
800 res.router_address.address_type);
802 done:
803 kmem_free(res.client_name, MAX_MACHINE_NAME + 1);
804 kmem_free(res.domain_name, MAX_MACHINE_NAME + 1);
805 free_netbuf(&sa);
806 (void) t_kclose(tiptr, 0);
807 return (rc);
811 * Returns:
812 * 1) The ascii form of our root servers name in `server_name'.
813 * 2) Actual network address of our root server in `server_address'.
814 * 3) Whatever BOOTPARAMPROC_GETFILE returns for the fileid key, in
815 * `server_path'. If fileid is "root", it is the pathname of our
816 * root on the server.
818 static int
819 getfile(char *fileid,
820 char *server_name, struct netbuf *server_address, char *server_path)
822 struct bp_getfile_arg arg;
823 struct bp_getfile_res res;
824 enum clnt_stat stat;
825 int root = FALSE;
826 static int using_cache = FALSE;
827 struct in_addr ipaddr;
828 int timeo = DEFAULT_TIMEO;
829 int retries = DEFAULT_RETRIES;
831 if (dldebug)
832 printf("getfile: entered\n");
835 * Call cacheinfo() to see whether we can satisfy this request by using
836 * the information cached in memory by the boot program's DHCP
837 * implementation or boot properties rather than consult BOOTPARAMS,
838 * but while preserving the semantics of getfile(). We know that
839 * the server name is SYS_NMLN in length, and server_path is
840 * MAXPATHLEN (pn_alloc).
842 if (strcmp(fileid, "root") == 0) {
843 if (cacheinfo(server_name, SYS_NMLN, server_address,
844 server_path, MAXPATHLEN) == 0) {
845 using_cache = TRUE;
846 return (0);
848 root = TRUE;
852 * If using cache, rootopts is already available.
854 if (strcmp(fileid, "rootopts") == 0 && using_cache == TRUE) {
855 return (rootopts[0] != 0 ? 0 : ENXIO);
858 if (bootparam_addr.len == 0) {
859 return (ENXIO);
861 arg.client_name = (caddr_t)&utsname.nodename;
862 arg.file_id = fileid;
864 bzero(&res, sizeof (res));
865 res.server_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
866 res.server_path = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
869 * If we are not looking up the root file, we are looking
870 * up a non-critical option that should timeout quickly.
872 if (!root) {
873 timeo = GETFILE_TIMEO;
874 retries = GETFILE_RETRIES;
878 * bootparam_addr was filled in by the call to
879 * whoami(), so now send an rpc message to the
880 * bootparam daemon requesting our server information.
881 * Use UDP to talk to bootparms.
883 stat = mycallrpc(&dl_udp_netconf, &bootparam_addr,
884 (rpcprog_t)BOOTPARAMPROG, (rpcvers_t)BOOTPARAMVERS,
885 (rpcproc_t)BOOTPARAMPROC_GETFILE,
886 xdr_bp_getfile_arg, (caddr_t)&arg,
887 xdr_bp_getfile_res, (caddr_t)&res,
888 timeo, retries);
890 if (stat == RPC_SUCCESS) {
891 (void) strcpy(server_name, res.server_name);
892 (void) strcpy(server_path, res.server_path);
895 kmem_free(res.server_name, MAX_MACHINE_NAME + 1);
896 kmem_free(res.server_path, MAX_MACHINE_NAME + 1);
898 if (stat != RPC_SUCCESS) {
899 if (root)
900 cmn_err(CE_WARN, "getfile: RPC failed: error %d (%s).",
901 stat, clnt_sperrno(stat));
902 return ((stat == RPC_TIMEDOUT) ? ETIMEDOUT : ENXIO); /* XXX */
905 if (*server_path == '\0')
906 return (EINVAL);
909 * If the fileid is "root", we must get back a server name, for
910 * other parameters a server name is not required
912 if (!root) {
913 if (dldebug)
914 printf("getfile: leaving: non-root\n");
915 return (0);
918 if (*server_name == '\0')
919 return (EINVAL);
921 switch (res.server_address.address_type) {
922 case IP_ADDR_TYPE:
924 * server_address is where we will get our root
925 * from.
927 ((struct sockaddr_in *)server_address->buf)->sin_family =
928 AF_INET;
929 bcopy(&res.server_address.bp_address.ip_addr,
930 &ipaddr, sizeof (ipaddr));
931 if (ipaddr.s_addr == 0)
932 return (EINVAL);
934 ((struct sockaddr_in *)server_address->buf)->sin_addr.s_addr =
935 ipaddr.s_addr;
936 server_address->len = sizeof (struct sockaddr_in);
937 break;
939 default:
940 printf("getfile: unknown address type %d\n",
941 res.server_address.address_type);
942 return (EPROTONOSUPPORT);
944 if (dldebug)
945 printf("getfile: leaving\n");
946 return (0);
950 * If the boot property "bootp-response" exists, then OBP performed a
951 * successful DHCP lease acquisition for us and left the resultant ACK packet
952 * encoded at that location.
954 * If no such property exists (or the information is incomplete or garbled),
955 * the function returns -1.
958 dhcpinit(void)
960 int rc, i;
961 char *p;
962 struct in_addr braddr;
963 struct in_addr subnet;
964 DHCP_OPT *doptp;
965 TIUSER *tiptr;
966 struct sockaddr_in *sin;
967 static int once_only = 0;
969 if (once_only == 1) {
970 return (0);
972 once_only = 1;
974 if (dhcack == NULL) {
975 return (-1);
978 if (dldebug) {
979 printf("dhcp: dhcack %p, len %d\n", (void *)dhcack,
980 dhcacklen);
983 pl = kmem_alloc(sizeof (PKT_LIST), KM_SLEEP);
984 pl->len = dhcacklen;
985 pl->pkt = kmem_alloc(pl->len, KM_SLEEP);
986 bcopy(dhcack, pl->pkt, dhcacklen);
989 * For x86, ifname is not initialized
990 * in the netinstall case and dhcack interface name is
991 * set in strplumb(). So we only copy the name if ifname
992 * is set properly.
994 if (ifname[0])
995 (void) strlcpy(dhcifname, ifname, sizeof (dhcifname));
997 /* remember the server_ip in dhcack */
998 bcopy((uchar_t *)pl->pkt + 20, dhcp_server_ip, 4);
999 bzero(pl->opts, (DHCP_LAST_OPT + 1) * sizeof (DHCP_OPT *));
1000 bzero(pl->vs, (VS_OPTION_END - VS_OPTION_START + 1) *
1001 sizeof (DHCP_OPT *));
1003 if (dhcp_options_scan(pl, B_TRUE) != 0) {
1004 /* garbled packet */
1005 cmn_err(CE_WARN, "dhcp: DHCP packet parsing failed");
1006 kmem_free(pl->pkt, pl->len);
1007 kmem_free(pl, sizeof (PKT_LIST));
1008 pl = NULL;
1009 return (-1);
1012 /* set node name */
1013 if (pl->opts[CD_HOSTNAME] != NULL) {
1014 doptp = pl->opts[CD_HOSTNAME];
1015 i = doptp->len;
1016 if (i >= SYS_NMLN) {
1017 cmn_err(CE_WARN, "dhcp: Hostname is too long");
1018 } else {
1019 bcopy(doptp->value, utsname.nodename, i);
1020 utsname.nodename[i] = '\0';
1021 if (dldebug) {
1022 printf("hostname is %s\n",
1023 utsname.nodename);
1028 /* Set NIS domain name. */
1029 p = NULL;
1030 if (pl->opts[CD_NIS_DOMAIN] != NULL) {
1031 doptp = pl->opts[CD_NIS_DOMAIN];
1032 i = doptp->len;
1033 p = (caddr_t)doptp->value;
1035 if (p != NULL) {
1036 if (i > SYS_NMLN) {
1037 cmn_err(CE_WARN,
1038 "dhcp: NIS domainname too long.");
1039 } else {
1040 bcopy(p, srpc_domain, i);
1041 srpc_domain[i] = '\0';
1042 if (dldebug)
1043 printf("dhcp: NIS domain name is %s\n",
1044 srpc_domain);
1048 /* fetch netmask */
1049 if (pl->opts[CD_SUBNETMASK] != NULL) {
1050 doptp = pl->opts[CD_SUBNETMASK];
1051 if (doptp->len != sizeof (struct in_addr)) {
1052 pl->opts[CD_SUBNETMASK] = NULL;
1053 cmn_err(CE_WARN, "dhcp: netmask option malformed");
1054 } else {
1055 bcopy(doptp->value, &subnet, sizeof (struct in_addr));
1056 if (dldebug)
1057 printf("dhcp: setting netmask to: %s\n",
1058 inet_ntoa(subnet));
1060 } else {
1061 struct in_addr myIPaddr;
1063 myIPaddr.s_addr = pl->pkt->yiaddr.s_addr;
1064 cmn_err(CE_WARN, "dhcp: no subnet mask supplied - inferring");
1065 if (IN_CLASSA(ntohl(myIPaddr.s_addr)))
1066 subnet.s_addr = htonl(IN_CLASSA_NET);
1067 else if (IN_CLASSB(ntohl(myIPaddr.s_addr)))
1068 subnet.s_addr = htonl(IN_CLASSB_NET);
1069 else if (IN_CLASSC(ntohl(myIPaddr.s_addr)))
1070 subnet.s_addr = htonl(IN_CLASSC_NET);
1071 else if (IN_CLASSD(ntohl(myIPaddr.s_addr)))
1072 cmn_err(CE_WARN, "dhcp: bad IP address (%s)",
1073 inet_ntoa(myIPaddr));
1074 else
1075 subnet.s_addr = htonl(IN_CLASSE_NET);
1077 /* and broadcast address */
1078 if (pl->opts[CD_BROADCASTADDR] != NULL) {
1079 doptp = pl->opts[CD_BROADCASTADDR];
1080 if (doptp->len != sizeof (struct in_addr)) {
1081 pl->opts[CD_BROADCASTADDR] = NULL;
1082 if (dldebug)
1083 printf("dhcp: broadcast address len %d\n",
1084 doptp->len);
1085 } else {
1086 bcopy(doptp->value, &braddr, sizeof (struct in_addr));
1087 if (dldebug)
1088 printf("dhcp: setting broadcast addr to: %s\n",
1089 inet_ntoa(braddr));
1091 } else {
1092 if (dldebug)
1093 printf("dhcp: no broadcast address supplied\n");
1094 braddr.s_addr = htonl(INADDR_BROADCAST);
1096 /* and plumb and initialize interface */
1097 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
1098 FREAD|FWRITE, &tiptr, CRED())) == 0) {
1099 if (rc = dlifconfig(tiptr, &pl->pkt->yiaddr, &subnet,
1100 &braddr, IFF_DHCPRUNNING)) {
1101 nfs_perror(rc, "dhcp: dlifconfig failed: %m\n");
1102 kmem_free(pl->pkt, pl->len);
1103 kmem_free(pl, sizeof (PKT_LIST));
1104 pl = NULL;
1105 (void) t_kclose(tiptr, 0);
1106 return (-1);
1109 /* add routes */
1110 if (pl->opts[CD_ROUTER] != NULL) {
1111 doptp = pl->opts[CD_ROUTER];
1112 if ((doptp->len % sizeof (struct in_addr)) != 0) {
1113 pl->opts[CD_ROUTER] = NULL;
1114 } else {
1115 int nrouters;
1116 uchar_t *tp;
1118 nrouters = doptp->len / sizeof (struct in_addr);
1119 for (tp = doptp->value, i = 0; i < nrouters;
1120 i++) {
1121 struct in_addr defr;
1122 struct rtentry rtentry;
1124 bcopy(tp, &defr,
1125 sizeof (struct in_addr));
1126 if (defr.s_addr == 0)
1127 continue;
1129 sin = (struct
1130 sockaddr_in *)&rtentry.rt_dst;
1132 bzero(sin, sizeof (*sin));
1133 sin->sin_family = AF_INET;
1135 sin = (struct
1136 sockaddr_in *)&rtentry.rt_gateway;
1137 bzero(sin, sizeof (*sin));
1138 sin->sin_family = AF_INET;
1139 sin->sin_addr = defr;
1141 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
1143 if (rc = rtioctl(tiptr, SIOCADDRT,
1144 &rtentry)) {
1145 nfs_perror(rc,
1146 "dhcp: couldn't add route "
1147 "to %s: %m.\n",
1148 inet_ntoa(defr));
1149 continue;
1151 if (dldebug) {
1152 printf("dhcp: added route %s\n",
1153 inet_ntoa(defr));
1155 tp += sizeof (struct in_addr);
1160 (void) t_kclose(tiptr, 0);
1163 if (dldebug)
1164 printf("dhcpinit: leaving\n");
1166 return (0);
1170 * Initialize nfs mount info from properties and dhcp response.
1172 static void
1173 cacheinit(void)
1175 char *str;
1176 DHCP_OPT *doptp;
1178 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1179 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c);
1180 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1181 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c);
1182 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1183 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) {
1184 (void) strncpy(rootopts, str, 255);
1185 ddi_prop_free(str);
1187 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1188 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) {
1189 if (inet_aton(str, server_ip) != 0)
1190 cmn_err(CE_NOTE, "server_ipaddr %s is invalid",
1191 str);
1192 ddi_prop_free(str);
1193 if (dldebug)
1194 printf("server ip is %s\n",
1195 inet_ntoa(*(struct in_addr *)server_ip));
1198 if (pl == NULL)
1199 return;
1201 /* extract root path in server_path */
1202 if (server_path_c == NULL) {
1203 doptp = pl->vs[VS_NFSMNT_ROOTPATH];
1204 if (doptp == NULL)
1205 doptp = pl->opts[CD_ROOT_PATH];
1206 if (doptp != NULL) {
1207 int len, size;
1208 uint8_t c, *source;
1210 str = NULL;
1211 source = doptp->value;
1212 size = doptp->len;
1213 c = ':';
1216 * We have to consider three cases for root path:
1217 * "nfs://server_ip/path"
1218 * "server_ip:/path"
1219 * "/path"
1221 if (bcmp(source, "nfs://", 6) == 0) {
1222 source += 6;
1223 size -= 6;
1224 c = '/';
1227 * Search for next char after ':' or first '/'.
1228 * Note, the '/' is part of the path, but we do
1229 * not need to preserve the ':'.
1231 for (len = 0; len < size; len++) {
1232 if (source[len] == c) {
1233 if (c == ':') {
1234 str = (char *)(&source[++len]);
1235 } else {
1236 str = (char *)(&source[len++]);
1237 size++;
1239 break;
1242 if (str != NULL) {
1243 /* Do not override server_ip from property. */
1244 if ((*(uint_t *)server_ip) == 0) {
1245 char *ip = kmem_alloc(len, KM_SLEEP);
1246 bcopy(source, ip, len);
1247 ip[len - 1] = '\0';
1248 if (inet_aton((ip), server_ip) != 0) {
1249 cmn_err(CE_NOTE,
1250 "server_ipaddr %s is "
1251 "invalid", ip);
1253 kmem_free(ip, len);
1254 if (dldebug) {
1255 printf("server ip is %s\n",
1256 inet_ntoa(
1257 *(struct in_addr *)
1258 server_ip));
1261 len = size - len;
1262 } else {
1263 str = (char *)doptp->value;
1264 len = doptp->len;
1266 server_path_c = kmem_alloc(len + 1, KM_SLEEP);
1267 bcopy(str, server_path_c, len);
1268 server_path_c[len] = '\0';
1269 if (dldebug)
1270 printf("dhcp: root path %s\n", server_path_c);
1271 } else {
1272 cmn_err(CE_WARN, "dhcp: root server path missing");
1276 /* set server_name */
1277 if (server_name_c == NULL) {
1278 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_NAME];
1279 if (doptp != NULL) {
1280 server_name_c = kmem_alloc(doptp->len + 1, KM_SLEEP);
1281 bcopy(doptp->value, server_name_c, doptp->len);
1282 server_name_c[doptp->len] = '\0';
1283 if (dldebug)
1284 printf("dhcp: root server name %s\n",
1285 server_name_c);
1286 } else {
1287 cmn_err(CE_WARN, "dhcp: root server name missing");
1291 /* set root server_address */
1292 if ((*(uint_t *)server_ip) == 0) {
1293 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_IP];
1294 if (doptp) {
1295 bcopy(doptp->value, server_ip, sizeof (server_ip));
1296 if (dldebug) {
1297 printf("dhcp: root server IP address %s\n",
1298 inet_ntoa(*(struct in_addr *)server_ip));
1300 } else {
1301 if (dldebug)
1302 cmn_err(CE_CONT,
1303 "dhcp: file server ip address missing,"
1304 " fallback to dhcp server as file server");
1305 bcopy(dhcp_server_ip, server_ip, sizeof (server_ip));
1309 /* set root file system mount options */
1310 if (rootopts[0] == 0) {
1311 doptp = pl->vs[VS_NFSMNT_ROOTOPTS];
1312 if (doptp != NULL && doptp->len < 255) {
1313 bcopy(doptp->value, rootopts, doptp->len);
1314 rootopts[doptp->len] = '\0';
1315 if (dldebug)
1316 printf("dhcp: rootopts %s\n", rootopts);
1317 } else if (dldebug) {
1318 printf("dhcp: no rootopts or too long\n");
1319 /* not an error */
1323 /* now we are done with pl, just free it */
1324 kmem_free(pl->pkt, pl->len);
1325 kmem_free(pl, sizeof (PKT_LIST));
1326 pl = NULL;
1329 static int
1330 cacheinfo(char *name, int namelen,
1331 struct netbuf *server_address, char *rootpath, int pathlen)
1333 static int init_done = 0;
1334 struct sockaddr_in *sin;
1336 if (init_done == 0) {
1337 cacheinit();
1338 init_done = 1;
1341 /* server_path is a reliable indicator of cache availability */
1342 if (server_path_c == NULL)
1343 return (-1);
1345 (void) strncpy(rootpath, server_path_c, pathlen);
1346 if (server_name_c) {
1347 (void) strncpy(name, server_name_c, namelen);
1348 } else {
1349 (void) strncpy(name, "unknown", namelen);
1352 sin = (struct sockaddr_in *)server_address->buf;
1353 sin->sin_family = AF_INET;
1354 server_address->len = sizeof (struct sockaddr_in);
1355 bcopy(server_ip, &sin->sin_addr, sizeof (struct in_addr));
1356 return (0);
1360 * Set this interface's IP address and netmask, and bring it up.
1362 static int
1363 dlifconfig(TIUSER *tiptr, struct in_addr *myIPaddr, struct in_addr *mymask,
1364 struct in_addr *mybraddr, uint_t flags)
1366 int rc;
1367 struct netbuf sbuf;
1368 struct sockaddr_in sin;
1370 if (dldebug) {
1371 printf("dlifconfig: entered\n");
1372 printf("dlifconfig: addr %s\n", inet_ntoa(*myIPaddr));
1373 printf("dlifconfig: mask %s\n", inet_ntoa(*mymask));
1374 printf("dlifconfig: broadcast %s\n", inet_ntoa(*mybraddr));
1377 bcopy(myIPaddr, &sin.sin_addr, sizeof (struct in_addr));
1378 sin.sin_family = AF_INET;
1379 sbuf.buf = (caddr_t)&sin;
1380 sbuf.maxlen = sbuf.len = sizeof (sin);
1381 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1382 nfs_perror(rc,
1383 "dlifconfig: couldn't set interface net address: %m\n");
1384 return (rc);
1387 if (mybraddr->s_addr != INADDR_BROADCAST) {
1388 bcopy(mybraddr, &sin.sin_addr, sizeof (struct in_addr));
1389 sin.sin_family = AF_INET;
1390 sbuf.buf = (caddr_t)&sin;
1391 sbuf.maxlen = sbuf.len = sizeof (sin);
1392 if (rc = ifioctl(tiptr, SIOCSIFBRDADDR, &sbuf)) {
1393 nfs_perror(rc,
1394 "dlifconfig: couldn't set interface broadcast addr: %m\n");
1395 return (rc);
1399 bcopy(mymask, &sin.sin_addr, sizeof (struct in_addr));
1400 sin.sin_family = AF_INET;
1401 sbuf.buf = (caddr_t)&sin;
1402 sbuf.maxlen = sbuf.len = sizeof (sin);
1403 if (rc = ifioctl(tiptr, SIOCSIFNETMASK, &sbuf)) {
1404 nfs_perror(rc,
1405 "dlifconfig: couldn't set interface net address: %m\n");
1406 return (rc);
1410 * Now turn on the interface.
1412 if (rc = setifflags(tiptr, IFF_UP | flags)) {
1413 nfs_perror(rc,
1414 "dlifconfig: couldn't enable network interface: %m\n");
1415 return (rc);
1418 if (dldebug)
1419 printf("dlifconfig: returned\n");
1420 return (0);
1423 static char *
1424 inet_ntoa(struct in_addr in)
1426 static char b[18];
1427 unsigned char *p;
1429 p = (unsigned char *)&in;
1430 (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1431 return (b);
1434 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1435 static int
1436 inet_aton(char *ipstr, uchar_t *ip)
1438 int i = 0;
1439 uchar_t val[4] = {0};
1440 char c = *ipstr;
1442 for (;;) {
1443 if (!isdigit(c))
1444 return (-1);
1445 for (;;) {
1446 if (!isdigit(c))
1447 break;
1448 val[i] = val[i] * 10 + (c - '0');
1449 c = *++ipstr;
1451 i++;
1452 if (i == 4)
1453 break;
1454 if (c != '.')
1455 return (-1);
1456 c = *++ipstr;
1458 if (c != 0)
1459 return (-1);
1460 bcopy(val, ip, 4);
1461 return (0);
1464 #define MAX_ADDR_SIZE 128
1467 * Initialize a netbuf suitable for
1468 * describing an address for the
1469 * transport defined by `tiptr'.
1471 static void
1472 init_netbuf(struct netbuf *nbuf)
1474 nbuf->buf = kmem_zalloc(MAX_ADDR_SIZE, KM_SLEEP);
1475 nbuf->maxlen = MAX_ADDR_SIZE;
1476 nbuf->len = 0;
1479 static void
1480 free_netbuf(struct netbuf *nbuf)
1482 kmem_free(nbuf->buf, nbuf->maxlen);
1483 nbuf->buf = NULL;
1484 nbuf->maxlen = 0;
1485 nbuf->len = 0;
1488 static int
1489 rtioctl(TIUSER *tiptr, int cmd, struct rtentry *rtentry)
1491 struct strioctl iocb;
1492 int rc;
1493 vnode_t *vp;
1495 iocb.ic_cmd = cmd;
1496 iocb.ic_timout = 0;
1497 iocb.ic_len = sizeof (struct rtentry);
1498 iocb.ic_dp = (caddr_t)rtentry;
1500 vp = tiptr->fp->f_vnode;
1501 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1502 if (rc)
1503 nfs_perror(rc, "rtioctl: kstr_ioctl failed: %m\n");
1504 return (rc);
1508 * Send an ioctl down the stream defined
1509 * by `tiptr'.
1511 * We isolate the ifreq dependencies in here. The
1512 * ioctl really ought to take a netbuf and be of
1513 * type TRANSPARENT - one day.
1515 static int
1516 ifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf)
1518 struct strioctl iocb;
1519 int rc;
1520 vnode_t *vp;
1521 struct ifreq ifr;
1524 * Now do the one requested.
1526 if (nbuf->len)
1527 ifr.ifr_addr = *(struct sockaddr *)nbuf->buf;
1528 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1529 iocb.ic_cmd = cmd;
1530 iocb.ic_timout = 0;
1531 iocb.ic_len = sizeof (ifr);
1532 iocb.ic_dp = (caddr_t)&ifr;
1534 vp = tiptr->fp->f_vnode;
1535 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1536 if (rc) {
1537 nfs_perror(rc, "ifioctl: kstr_ioctl failed: %m\n");
1538 return (rc);
1542 * Set reply length.
1544 if (nbuf->len == 0) {
1546 * GET type.
1548 nbuf->len = sizeof (struct sockaddr);
1549 *(struct sockaddr *)nbuf->buf = ifr.ifr_addr;
1552 return (0);
1555 static int
1556 setifflags(TIUSER *tiptr, uint_t value)
1558 struct ifreq ifr;
1559 int rc;
1560 struct strioctl iocb;
1562 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1563 iocb.ic_cmd = SIOCGIFFLAGS;
1564 iocb.ic_timout = 0;
1565 iocb.ic_len = sizeof (ifr);
1566 iocb.ic_dp = (caddr_t)&ifr;
1567 if (rc = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb))
1568 return (rc);
1570 ifr.ifr_flags |= value;
1571 iocb.ic_cmd = SIOCSIFFLAGS;
1572 return (kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb));
1576 * REVerse Address Resolution Protocol (revarp)
1577 * is used by a diskless client to find out its
1578 * IP address when all it knows is its Ethernet address.
1580 * Open the ethernet driver, attach and bind
1581 * (DL_BIND_REQ) it, and then format a broadcast RARP
1582 * message for it to send. We pick up the reply and
1583 * let the caller set the interface address using SIOCSIFADDR.
1585 static int
1586 revarp_myaddr(TIUSER *tiptr)
1588 int rc;
1589 dl_info_ack_t info;
1590 struct sockaddr_in sin;
1591 struct netbuf sbuf;
1592 ldi_handle_t lh;
1593 ldi_ident_t li;
1594 struct netbuf myaddr = {0, 0, NULL};
1596 if (dldebug)
1597 printf("revarp_myaddr: entered\n");
1599 if (rc = ldi_ident_from_mod(&modlinkage, &li)) {
1600 nfs_perror(rc,
1601 "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1602 return (rc);
1605 rc = ldi_open_by_name(ndev_path, FREAD|FWRITE, CRED(), &lh, li);
1606 ldi_ident_release(li);
1607 if (rc) {
1608 nfs_perror(rc,
1609 "revarp_myaddr: ldi_open_by_name failed: %m\n");
1610 return (rc);
1613 if (rc = dl_attach(lh, ifunit, NULL)) {
1614 nfs_perror(rc, "revarp_myaddr: dl_attach failed: %m\n");
1615 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1616 return (rc);
1619 if (rc = dl_bind(lh, ETHERTYPE_REVARP, NULL)) {
1620 nfs_perror(rc, "revarp_myaddr: dl_bind failed: %m\n");
1621 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1622 return (rc);
1625 if (rc = dl_info(lh, &info, NULL, NULL, NULL)) {
1626 nfs_perror(rc, "revarp_myaddr: dl_info failed: %m\n");
1627 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1628 return (rc);
1631 /* Initialize myaddr */
1632 myaddr.maxlen = info.dl_addr_length;
1633 myaddr.buf = kmem_alloc(myaddr.maxlen, KM_SLEEP);
1635 revarp_start(lh, &myaddr);
1637 bcopy(myaddr.buf, &sin.sin_addr, myaddr.len);
1638 sin.sin_family = AF_INET;
1640 sbuf.buf = (caddr_t)&sin;
1641 sbuf.maxlen = sbuf.len = sizeof (sin);
1642 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1643 nfs_perror(rc,
1644 "revarp_myaddr: couldn't set interface net address: %m\n");
1645 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1646 kmem_free(myaddr.buf, myaddr.maxlen);
1647 return (rc);
1650 /* Now turn on the interface */
1651 if (rc = setifflags(tiptr, IFF_UP)) {
1652 nfs_perror(rc,
1653 "revarp_myaddr: couldn't enable network interface: %m\n");
1656 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1657 kmem_free(myaddr.buf, myaddr.maxlen);
1658 return (rc);
1661 static void
1662 revarp_start(ldi_handle_t lh, struct netbuf *myaddr)
1664 struct ether_arp *ea;
1665 int rc;
1666 dl_unitdata_req_t *dl_udata;
1667 mblk_t *bp;
1668 mblk_t *mp;
1669 struct dladdr *dlsap;
1670 static int done = 0;
1671 size_t addrlen = ETHERADDRL;
1673 if (dl_phys_addr(lh, (uchar_t *)&myether, &addrlen, NULL) != 0 ||
1674 addrlen != ETHERADDRL) {
1675 /* Fallback using per-node address */
1676 (void) localetheraddr(NULL, &myether);
1677 cmn_err(CE_CONT, "?DLPI failed to get Ethernet address. Using "
1678 "system wide Ethernet address %s\n",
1679 ether_sprintf(&myether));
1682 getreply:
1683 if (myaddr->len != 0) {
1684 cmn_err(CE_CONT, "?Found my IP address: %x (%d.%d.%d.%d)\n",
1685 *(int *)myaddr->buf,
1686 (uchar_t)myaddr->buf[0], (uchar_t)myaddr->buf[1],
1687 (uchar_t)myaddr->buf[2], (uchar_t)myaddr->buf[3]);
1688 return;
1691 if (done++ == 0)
1692 cmn_err(CE_CONT, "?Requesting Internet address for %s\n",
1693 ether_sprintf(&myether));
1696 * Send another RARP request.
1698 if ((mp = allocb(sizeof (dl_unitdata_req_t) + sizeof (*dlsap),
1699 BPRI_HI)) == NULL) {
1700 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1701 return;
1703 if ((bp = allocb(sizeof (struct ether_arp), BPRI_HI)) == NULL) {
1704 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1705 return;
1709 * Format the transmit request part.
1711 mp->b_datap->db_type = M_PROTO;
1712 dl_udata = (dl_unitdata_req_t *)mp->b_wptr;
1713 mp->b_wptr += sizeof (dl_unitdata_req_t) + sizeof (*dlsap);
1714 dl_udata->dl_primitive = DL_UNITDATA_REQ;
1715 dl_udata->dl_dest_addr_length = sizeof (*dlsap);
1716 dl_udata->dl_dest_addr_offset = sizeof (*dl_udata);
1717 dl_udata->dl_priority.dl_min = 0;
1718 dl_udata->dl_priority.dl_max = 0;
1720 dlsap = (struct dladdr *)(mp->b_rptr + sizeof (*dl_udata));
1721 bcopy(&etherbroadcastaddr, &dlsap->dl_phys,
1722 sizeof (etherbroadcastaddr));
1723 dlsap->dl_sap = ETHERTYPE_REVARP;
1726 * Format the actual REVARP request.
1728 bzero(bp->b_wptr, sizeof (struct ether_arp));
1729 ea = (struct ether_arp *)bp->b_wptr;
1730 bp->b_wptr += sizeof (struct ether_arp);
1731 ea->arp_hrd = htons(ARPHRD_ETHER);
1732 ea->arp_pro = htons(ETHERTYPE_IP);
1733 ea->arp_hln = sizeof (ea->arp_sha); /* hardware address length */
1734 ea->arp_pln = sizeof (ea->arp_spa); /* protocol address length */
1735 ea->arp_op = htons(REVARP_REQUEST);
1736 ether_copy(&myether, &ea->arp_sha);
1737 ether_copy(&myether, &ea->arp_tha);
1739 mp->b_cont = bp;
1741 if ((rc = ldi_putmsg(lh, mp)) != 0) {
1742 nfs_perror(rc, "revarp_start: ldi_putmsg failed: %m\n");
1743 return;
1745 revarpinput(lh, myaddr);
1747 goto getreply;
1751 * Client side Reverse-ARP input
1752 * Server side is handled by user level server
1754 static void
1755 revarpinput(ldi_handle_t lh, struct netbuf *myaddr)
1757 struct ether_arp *ea;
1758 mblk_t *bp;
1759 mblk_t *mp;
1760 int rc;
1761 timestruc_t tv, give_up, now;
1764 * Choose the time at which we will give up, and resend our
1765 * request.
1767 gethrestime(&give_up);
1768 give_up.tv_sec += REVARP_TIMEO;
1769 wait:
1771 * Compute new timeout value.
1773 tv = give_up;
1774 gethrestime(&now);
1775 timespecsub(&tv, &now);
1777 * If we don't have at least one full second remaining, give up.
1778 * This means we might wait only just over 4.0 seconds, but that's
1779 * okay.
1781 if (tv.tv_sec <= 0)
1782 return;
1783 rc = ldi_getmsg(lh, &mp, &tv);
1784 if (rc == ETIME) {
1785 goto out;
1786 } else if (rc != 0) {
1787 nfs_perror(rc, "revarpinput: ldi_getmsg failed: %m\n");
1788 return;
1791 if (mp->b_cont == NULL) {
1792 printf("revarpinput: b_cont == NULL\n");
1793 goto out;
1796 if (mp->b_datap->db_type != M_PROTO) {
1797 printf("revarpinput: bad header type %d\n",
1798 mp->b_datap->db_type);
1799 goto out;
1802 bp = mp->b_cont;
1804 if (bp->b_wptr - bp->b_rptr < sizeof (*ea)) {
1805 printf("revarpinput: bad data len %d, expect %d\n",
1806 (int)(bp->b_wptr - bp->b_rptr), (int)sizeof (*ea));
1807 goto out;
1810 ea = (struct ether_arp *)bp->b_rptr;
1812 if ((ushort_t)ntohs(ea->arp_pro) != ETHERTYPE_IP) {
1813 /* We could have received another broadcast arp packet. */
1814 if (dldebug)
1815 printf("revarpinput: bad type %x\n",
1816 (ushort_t)ntohs(ea->arp_pro));
1817 freemsg(mp);
1818 goto wait;
1820 if ((ushort_t)ntohs(ea->arp_op) != REVARP_REPLY) {
1821 /* We could have received a broadcast arp request. */
1822 if (dldebug)
1823 printf("revarpinput: bad op %x\n",
1824 (ushort_t)ntohs(ea->arp_op));
1825 freemsg(mp);
1826 goto wait;
1829 if (!ether_cmp(&ea->arp_tha, &myether)) {
1830 bcopy(&ea->arp_tpa, myaddr->buf, sizeof (ea->arp_tpa));
1831 myaddr->len = sizeof (ea->arp_tpa);
1832 } else {
1833 /* We could have gotten a broadcast arp response. */
1834 if (dldebug)
1835 printf("revarpinput: got reply, but not my address\n");
1836 freemsg(mp);
1837 goto wait;
1839 out:
1840 freemsg(mp);
1844 * From rpcsvc/mountxdr.c in SunOS. We can't
1845 * put this into the rpc directory because
1846 * it calls xdr_fhandle() which is in a
1847 * loadable module.
1849 static bool_t
1850 myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp)
1853 if (!xdr_int(xdrs, &fhsp->fhs_status))
1854 return (FALSE);
1855 if (fhsp->fhs_status == 0) {
1856 if (!myxdr_fhandle(xdrs, &fhsp->fhs_fh))
1857 return (FALSE);
1859 return (TRUE);
1863 * From nfs_xdr.c.
1865 * File access handle
1866 * The fhandle struct is treated a opaque data on the wire
1868 static bool_t
1869 myxdr_fhandle(XDR *xdrs, fhandle_t *fh)
1871 return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
1874 static bool_t
1875 myxdr_mountres3(XDR *xdrs, struct mountres3 *objp)
1877 if (!myxdr_mountstat3(xdrs, &objp->fhs_status))
1878 return (FALSE);
1879 switch (objp->fhs_status) {
1880 case MNT_OK:
1881 if (!myxdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
1882 return (FALSE);
1883 break;
1884 default:
1885 break;
1887 return (TRUE);
1890 static bool_t
1891 myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp)
1893 return (xdr_enum(xdrs, (enum_t *)objp));
1896 static bool_t
1897 myxdr_mountres3_ok(XDR *xdrs, struct mountres3_ok *objp)
1899 if (!myxdr_fhandle3(xdrs, &objp->fhandle))
1900 return (FALSE);
1901 if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val,
1902 (uint_t *)&objp->auth_flavors.auth_flavors_len, ~0,
1903 sizeof (int), (xdrproc_t)xdr_int))
1904 return (FALSE);
1905 return (TRUE);
1908 static bool_t
1909 myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp)
1911 return (xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
1912 (uint_t *)&objp->fhandle3_len, FHSIZE3));
1916 * From SunOS pmap_clnt.c
1918 * Port mapper routines:
1919 * pmap_kgetport() - get port number.
1920 * pmap_rmt_call() - indirect call via port mapper.
1923 static enum clnt_stat
1924 pmap_kgetport(struct knetconfig *knconf, struct netbuf *call_addr,
1925 rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
1927 ushort_t port;
1928 int tries;
1929 enum clnt_stat stat;
1930 struct pmap pmap_parms;
1931 RPCB rpcb_parms;
1932 char *ua = NULL;
1934 port = 0;
1936 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
1938 pmap_parms.pm_prog = prog;
1939 pmap_parms.pm_vers = vers;
1940 pmap_parms.pm_prot = prot;
1941 pmap_parms.pm_port = 0;
1942 for (tries = 0; tries < 5; tries++) {
1943 stat = mycallrpc(knconf, call_addr,
1944 PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
1945 myxdr_pmap, (char *)&pmap_parms,
1946 xdr_u_short, (char *)&port,
1947 DEFAULT_TIMEO, DEFAULT_RETRIES);
1949 if (stat != RPC_TIMEDOUT)
1950 break;
1951 cmn_err(CE_WARN,
1952 "pmap_kgetport: Portmapper not responding; still trying");
1955 if (stat == RPC_PROGUNAVAIL) {
1956 cmn_err(CE_WARN,
1957 "pmap_kgetport: Portmapper failed - trying rpcbind");
1959 rpcb_parms.r_prog = prog;
1960 rpcb_parms.r_vers = vers;
1961 rpcb_parms.r_netid = knconf->knc_proto;
1962 rpcb_parms.r_addr = rpcb_parms.r_owner = "";
1964 for (tries = 0; tries < 5; tries++) {
1965 stat = mycallrpc(knconf, call_addr,
1966 RPCBPROG, RPCBVERS, RPCBPROC_GETADDR,
1967 xdr_rpcb, (char *)&rpcb_parms,
1968 xdr_wrapstring, (char *)&ua,
1969 DEFAULT_TIMEO, DEFAULT_RETRIES);
1971 if (stat != RPC_TIMEDOUT)
1972 break;
1973 cmn_err(CE_WARN,
1974 "pmap_kgetport: rpcbind not responding; still trying");
1977 if (stat == RPC_SUCCESS) {
1978 if ((ua != NULL) && (ua[0] != '\0')) {
1979 port = rpc_uaddr2port(AF_INET, ua);
1980 } else {
1981 /* Address unknown */
1982 stat = RPC_PROGUNAVAIL;
1987 if (stat == RPC_SUCCESS)
1988 ((struct sockaddr_in *)call_addr->buf)->sin_port = ntohs(port);
1990 return (stat);
1994 * pmapper remote-call-service interface.
1995 * This routine is used to call the pmapper remote call service
1996 * which will look up a service program in the port maps, and then
1997 * remotely call that routine with the given parameters. This allows
1998 * programs to do a lookup and call in one step. In addition to the call_addr,
1999 * the caller provides a boolean hint about the destination address (TRUE if
2000 * address is a broadcast address, FALSE otherwise).
2002 * On return, `call addr' contains the port number for the
2003 * service requested, and `resp_addr' contains its IP address.
2005 static enum clnt_stat
2006 pmap_rmt_call(struct knetconfig *knconf, struct netbuf *call_addr,
2007 bool_t bcast, rpcprog_t progn, rpcvers_t versn, rpcproc_t procn,
2008 xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
2009 struct timeval tout, struct netbuf *resp_addr)
2011 CLIENT *cl;
2012 enum clnt_stat stat;
2013 rpcport_t port;
2014 int rc;
2015 struct rmtcallargs pmap_args;
2016 struct rmtcallres pmap_res;
2017 struct rpcb_rmtcallargs rpcb_args;
2018 struct rpcb_rmtcallres rpcb_res;
2019 char ua[100]; /* XXX */
2021 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
2023 rc = clnt_tli_kcreate(knconf, call_addr, PMAPPROG, PMAPVERS,
2024 0, PMAP_RETRIES, CRED(), &cl);
2025 if (rc != 0) {
2026 nfs_perror(rc,
2027 "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2028 return (RPC_SYSTEMERROR); /* XXX */
2030 if (cl == (CLIENT *)NULL) {
2031 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2032 /* NOTREACHED */
2035 (void) CLNT_CONTROL(cl, CLSET_BCAST, (char *)&bcast);
2037 pmap_args.prog = progn;
2038 pmap_args.vers = versn;
2039 pmap_args.proc = procn;
2040 pmap_args.args_ptr = argsp;
2041 pmap_args.xdr_args = xdrargs;
2042 pmap_res.port_ptr = &port;
2043 pmap_res.results_ptr = resp;
2044 pmap_res.xdr_results = xdrres;
2045 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
2046 myxdr_rmtcall_args, (caddr_t)&pmap_args,
2047 myxdr_rmtcallres, (caddr_t)&pmap_res,
2048 tout, resp_addr);
2050 if (stat == RPC_SUCCESS) {
2051 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2052 htons((ushort_t)port);
2054 CLNT_DESTROY(cl);
2056 if (stat != RPC_PROGUNAVAIL)
2057 return (stat);
2059 cmn_err(CE_WARN, "pmap_rmt_call: Portmapper failed - trying rpcbind");
2061 rc = clnt_tli_kcreate(knconf, call_addr, RPCBPROG, RPCBVERS,
2062 0, PMAP_RETRIES, CRED(), &cl);
2063 if (rc != 0) {
2064 nfs_perror(rc, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2065 return (RPC_SYSTEMERROR); /* XXX */
2068 if (cl == NULL) {
2069 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2070 /* NOTREACHED */
2073 rpcb_args.prog = progn;
2074 rpcb_args.vers = versn;
2075 rpcb_args.proc = procn;
2076 rpcb_args.args_ptr = argsp;
2077 rpcb_args.xdr_args = xdrargs;
2078 rpcb_res.addr_ptr = ua;
2079 rpcb_res.results_ptr = resp;
2080 rpcb_res.xdr_results = xdrres;
2081 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
2082 xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_args,
2083 xdr_rpcb_rmtcallres, (caddr_t)&rpcb_res,
2084 tout, resp_addr);
2086 if (stat == RPC_SUCCESS)
2087 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2088 rpc_uaddr2port(AF_INET, ua);
2089 CLNT_DESTROY(cl);
2091 return (stat);
2095 * XDR remote call arguments
2096 * written for XDR_ENCODE direction only
2098 static bool_t
2099 myxdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
2101 uint_t lenposition;
2102 uint_t argposition;
2103 uint_t position;
2105 if (xdr_rpcprog(xdrs, &(cap->prog)) &&
2106 xdr_rpcvers(xdrs, &(cap->vers)) &&
2107 xdr_rpcproc(xdrs, &(cap->proc))) {
2108 lenposition = XDR_GETPOS(xdrs);
2109 if (!xdr_u_int(xdrs, &cap->arglen))
2110 return (FALSE);
2111 argposition = XDR_GETPOS(xdrs);
2112 if (!(*(cap->xdr_args))(xdrs, cap->args_ptr))
2113 return (FALSE);
2114 position = XDR_GETPOS(xdrs);
2115 cap->arglen = (uint_t)position - (uint_t)argposition;
2116 XDR_SETPOS(xdrs, lenposition);
2117 if (!xdr_u_int(xdrs, &cap->arglen))
2118 return (FALSE);
2119 XDR_SETPOS(xdrs, position);
2120 return (TRUE);
2122 return (FALSE);
2126 * XDR remote call results
2127 * written for XDR_DECODE direction only
2129 static bool_t
2130 myxdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
2132 caddr_t port_ptr;
2134 port_ptr = (caddr_t)crp->port_ptr;
2135 if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) &&
2136 xdr_u_int(xdrs, &crp->resultslen)) {
2137 crp->port_ptr = (rpcport_t *)port_ptr;
2138 return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
2140 return (FALSE);
2143 static bool_t
2144 myxdr_pmap(XDR *xdrs, struct pmap *regs)
2146 if (xdr_rpcprog(xdrs, &regs->pm_prog) &&
2147 xdr_rpcvers(xdrs, &regs->pm_vers) &&
2148 xdr_rpcprot(xdrs, &regs->pm_prot))
2149 return (xdr_rpcport(xdrs, &regs->pm_port));
2151 return (FALSE);
2155 * From SunOS callrpc.c
2157 static enum clnt_stat
2158 mycallrpc(struct knetconfig *knconf, struct netbuf *call_addr,
2159 rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
2160 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out,
2161 int timeo, int retries)
2163 CLIENT *cl;
2164 struct timeval tv;
2165 enum clnt_stat cl_stat;
2166 int rc;
2168 rc = clnt_tli_kcreate(knconf, call_addr, prognum, versnum,
2169 0, retries, CRED(), &cl);
2170 if (rc) {
2171 nfs_perror(rc, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2172 return (RPC_SYSTEMERROR); /* XXX */
2174 tv.tv_sec = timeo;
2175 tv.tv_usec = 0;
2176 cl_stat = CLNT_CALL(cl, procnum, inproc, in, outproc, out, tv);
2177 AUTH_DESTROY(cl->cl_auth);
2178 CLNT_DESTROY(cl);
2179 return (cl_stat);
2183 * Configure the 'default' interface based on existing boot properties.
2185 static int
2186 bp_netconfig(void)
2188 char *str;
2189 struct in_addr my_ip, my_netmask, my_router, my_broadcast;
2190 struct sockaddr_in *sin;
2191 TIUSER *tiptr;
2192 int rc;
2193 struct rtentry rtentry;
2195 my_ip.s_addr = my_netmask.s_addr = my_router.s_addr = 0;
2198 * No way of getting this right now. Collude with dlifconfig()
2199 * to let the protocol stack choose.
2201 my_broadcast.s_addr = INADDR_BROADCAST;
2203 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2204 DDI_PROP_DONTPASS, BP_HOST_IP, &str) == DDI_SUCCESS) {
2205 if (inet_aton(str, (uchar_t *)&my_ip) != 0)
2206 cmn_err(CE_NOTE, "host-ip %s is invalid\n",
2207 str);
2208 ddi_prop_free(str);
2209 if (dldebug)
2210 printf("host ip is %s\n",
2211 inet_ntoa(my_ip));
2213 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2214 DDI_PROP_DONTPASS, BP_SUBNET_MASK, &str) == DDI_SUCCESS) {
2215 if (inet_aton(str, (uchar_t *)&my_netmask) != 0)
2216 cmn_err(CE_NOTE, "subnet-mask %s is invalid\n",
2217 str);
2218 ddi_prop_free(str);
2219 if (dldebug)
2220 printf("subnet mask is %s\n",
2221 inet_ntoa(my_netmask));
2223 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2224 DDI_PROP_DONTPASS, BP_ROUTER_IP, &str) == DDI_SUCCESS) {
2225 if (inet_aton(str, (uchar_t *)&my_router) != 0)
2226 cmn_err(CE_NOTE, "router-ip %s is invalid\n",
2227 str);
2228 ddi_prop_free(str);
2229 if (dldebug)
2230 printf("router ip is %s\n",
2231 inet_ntoa(my_router));
2233 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2234 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c);
2235 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2236 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c);
2237 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2238 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) {
2239 (void) strlcpy(rootopts, str, sizeof (rootopts));
2240 ddi_prop_free(str);
2242 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2243 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) {
2244 if (inet_aton(str, server_ip) != 0)
2245 cmn_err(CE_NOTE, "server-ip %s is invalid\n",
2246 str);
2247 ddi_prop_free(str);
2248 if (dldebug)
2249 printf("server ip is %s\n",
2250 inet_ntoa(*(struct in_addr *)server_ip));
2254 * We need all of these to configure based on properties.
2256 if ((my_ip.s_addr == 0) ||
2257 (my_netmask.s_addr == 0) ||
2258 (server_path_c == NULL) ||
2259 (server_name_c == NULL) ||
2260 (*(uint_t *)server_ip == 0))
2261 return (-1);
2263 cmn_err(CE_CONT, "?IP address: %s\n", inet_ntoa(my_ip));
2264 cmn_err(CE_CONT, "?IP netmask: %s\n", inet_ntoa(my_netmask));
2265 if (my_router.s_addr != 0)
2266 cmn_err(CE_CONT, "?IP router: %s\n", inet_ntoa(my_router));
2267 cmn_err(CE_CONT, "?NFS server: %s (%s)\n", server_name_c,
2268 inet_ntoa(*(struct in_addr *)server_ip));
2269 cmn_err(CE_CONT, "?NFS path: %s\n", server_path_c);
2272 * Configure the interface.
2274 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
2275 FREAD|FWRITE, &tiptr, CRED())) != 0) {
2276 nfs_perror(rc, "bp_netconfig: t_kopen udp failed: %m.\n");
2277 return (rc);
2280 if ((rc = dlifconfig(tiptr, &my_ip, &my_netmask, &my_broadcast,
2281 0)) < 0) {
2282 nfs_perror(rc, "bp_netconfig: dlifconfig failed: %m.\n");
2283 (void) t_kclose(tiptr, 0);
2284 return (rc);
2287 if (my_router.s_addr != 0) {
2289 * Add a default route.
2291 sin = (struct sockaddr_in *)&rtentry.rt_dst;
2292 bzero(sin, sizeof (*sin));
2293 sin->sin_family = AF_INET;
2295 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
2296 bzero(sin, sizeof (*sin));
2297 sin->sin_family = AF_INET;
2298 sin->sin_addr = my_router;
2300 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
2302 if ((rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) != 0) {
2303 nfs_perror(rc,
2304 "bp_netconfig: couldn't add route: %m.\n");
2305 (void) t_kclose(tiptr, 0);
2306 return (rc);
2310 (void) t_kclose(tiptr, 0);
2312 return (0);
2316 * The network device we will use to boot from is plumbed. Extract the details
2317 * from rootfs.
2319 static void
2320 init_config(void)
2322 (void) strlcpy(ndev_path, rootfs.bo_devname, sizeof (ndev_path));
2323 (void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname));
2324 ifunit = rootfs.bo_ppa;
2327 * Assumes only one linkage array element.
2329 dl_udp_netconf.knc_rdev =
2330 makedevice(clone_major, ddi_name_to_major("udp"));
2331 dl_tcp_netconf.knc_rdev =
2332 makedevice(clone_major, ddi_name_to_major("tcp"));
2335 * Now we bringup the interface.
2336 * Try cached dhcp response first. If it fails, do rarp.
2338 if ((bp_netconfig() != 0) &&
2339 (dhcpinit() != 0) &&
2340 (whoami() != 0))
2341 cmn_err(CE_WARN,
2342 "%s: no response from interface", ifname);
2343 else if (dldebug)
2344 printf("init_config: ifname %s is up\n", ifname);
2348 * These options are duplicated in cmd/fs.d/nfs/mount/mount.c
2349 * Changes must be made to both lists.
2351 static char *optlist[] = {
2352 #define OPT_RO 0
2353 MNTOPT_RO,
2354 #define OPT_RW 1
2355 MNTOPT_RW,
2356 #define OPT_QUOTA 2
2357 MNTOPT_QUOTA,
2358 #define OPT_NOQUOTA 3
2359 MNTOPT_NOQUOTA,
2360 #define OPT_SOFT 4
2361 MNTOPT_SOFT,
2362 #define OPT_HARD 5
2363 MNTOPT_HARD,
2364 #define OPT_SUID 6
2365 MNTOPT_SUID,
2366 #define OPT_NOSUID 7
2367 MNTOPT_NOSUID,
2368 #define OPT_GRPID 8
2369 MNTOPT_GRPID,
2370 #define OPT_REMOUNT 9
2371 MNTOPT_REMOUNT,
2372 #define OPT_NOSUB 10
2373 MNTOPT_NOSUB,
2374 #define OPT_INTR 11
2375 MNTOPT_INTR,
2376 #define OPT_NOINTR 12
2377 MNTOPT_NOINTR,
2378 #define OPT_PORT 13
2379 MNTOPT_PORT,
2380 #define OPT_SECURE 14
2381 MNTOPT_SECURE,
2382 #define OPT_RSIZE 15
2383 MNTOPT_RSIZE,
2384 #define OPT_WSIZE 16
2385 MNTOPT_WSIZE,
2386 #define OPT_TIMEO 17
2387 MNTOPT_TIMEO,
2388 #define OPT_RETRANS 18
2389 MNTOPT_RETRANS,
2390 #define OPT_ACTIMEO 19
2391 MNTOPT_ACTIMEO,
2392 #define OPT_ACREGMIN 20
2393 MNTOPT_ACREGMIN,
2394 #define OPT_ACREGMAX 21
2395 MNTOPT_ACREGMAX,
2396 #define OPT_ACDIRMIN 22
2397 MNTOPT_ACDIRMIN,
2398 #define OPT_ACDIRMAX 23
2399 MNTOPT_ACDIRMAX,
2400 #define OPT_BG 24
2401 MNTOPT_BG,
2402 #define OPT_FG 25
2403 MNTOPT_FG,
2404 #define OPT_RETRY 26
2405 MNTOPT_RETRY,
2406 #define OPT_NOAC 27
2407 MNTOPT_NOAC,
2408 #define OPT_NOCTO 28
2409 MNTOPT_NOCTO,
2410 #define OPT_LLOCK 29
2411 MNTOPT_LLOCK,
2412 #define OPT_POSIX 30
2413 MNTOPT_POSIX,
2414 #define OPT_VERS 31
2415 MNTOPT_VERS,
2416 #define OPT_PROTO 32
2417 MNTOPT_PROTO,
2418 #define OPT_SEMISOFT 33
2419 MNTOPT_SEMISOFT,
2420 #define OPT_NOPRINT 34
2421 MNTOPT_NOPRINT,
2422 #define OPT_SEC 35
2423 MNTOPT_SEC,
2424 #define OPT_LARGEFILES 36
2425 MNTOPT_LARGEFILES,
2426 #define OPT_NOLARGEFILES 37
2427 MNTOPT_NOLARGEFILES,
2428 #define OPT_PUBLIC 38
2429 MNTOPT_PUBLIC,
2430 #define OPT_DIRECTIO 39
2431 MNTOPT_FORCEDIRECTIO,
2432 #define OPT_NODIRECTIO 40
2433 MNTOPT_NOFORCEDIRECTIO,
2434 #define OPT_XATTR 41
2435 MNTOPT_XATTR,
2436 #define OPT_NOXATTR 42
2437 MNTOPT_NOXATTR,
2438 #define OPT_DEVICES 43
2439 MNTOPT_DEVICES,
2440 #define OPT_NODEVICES 44
2441 MNTOPT_NODEVICES,
2442 #define OPT_SETUID 45
2443 MNTOPT_SETUID,
2444 #define OPT_NOSETUID 46
2445 MNTOPT_NOSETUID,
2446 #define OPT_EXEC 47
2447 MNTOPT_EXEC,
2448 #define OPT_NOEXEC 48
2449 MNTOPT_NOEXEC,
2450 NULL
2453 static int
2454 isdigit(int ch)
2456 return (ch >= '0' && ch <= '9');
2459 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2460 #define bad(val) (val == NULL || !isdigit(*val))
2462 static int
2463 atoi(const char *p)
2465 int n;
2466 int c, neg = 0;
2468 if (!isdigit(c = *p)) {
2469 while (isspace(c))
2470 c = *++p;
2471 switch (c) {
2472 case '-':
2473 neg++;
2474 /* FALLTHROUGH */
2475 case '+':
2476 c = *++p;
2478 if (!isdigit(c))
2479 return (0);
2481 for (n = '0' - c; isdigit(c = *++p); ) {
2482 n *= 10; /* two steps to avoid unnecessary overflow */
2483 n += '0' - c; /* accum neg to avoid surprises at MAX */
2485 return (neg ? n : -n);
2489 * Default root read tsize XXX
2491 int nfs_root_rsize = 8 * 1024; /* conservative for dumb NICs */
2492 int nfs4_root_rsize = 32 * 1024; /* only runs on TCP be aggressive */
2495 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2497 int nfs_rootopts = NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT;
2499 static int
2500 init_mountopts(struct nfs_args *args, int version, struct knetconfig **dl_cf,
2501 int *vfsflags)
2503 char servername[SYS_NMLN];
2504 static int first = 0;
2505 struct netbuf server_address;
2506 char *opts, *val;
2507 int vers;
2508 struct knetconfig *cf = *dl_cf;
2509 char rootoptsbuf[256];
2512 * Set default mount options
2514 args->flags = nfs_rootopts;
2515 args->rsize = 0;
2516 args->flags |= NFSMNT_ACREGMIN;
2517 args->acregmin = ACMINMAX;
2518 args->flags |= NFSMNT_ACREGMAX;
2519 args->acregmax = ACMAXMAX;
2520 args->flags |= NFSMNT_ACDIRMIN;
2521 args->acdirmin = ACMINMAX;
2522 args->flags |= NFSMNT_ACDIRMAX;
2523 args->acdirmax = ACMAXMAX;
2525 *vfsflags = 0;
2528 * Only look up the rootopts the first time, we store this in
2529 * a static buffer but we are guaranteed to be single threaded
2530 * and not reentrant.
2532 if (first == 0) {
2533 first++;
2535 init_netbuf(&server_address);
2537 if (getfile("rootopts", servername, &server_address,
2538 rootopts)) {
2539 rootopts[0] = '\0';
2540 free_netbuf(&server_address);
2541 goto sanity;
2543 free_netbuf(&server_address);
2546 if (dldebug)
2547 printf("rootopts = %s\n", rootopts);
2550 * We have to preserve rootopts for second time.
2552 (void) strncpy(rootoptsbuf, rootopts, sizeof (rootoptsbuf));
2553 rootoptsbuf[sizeof (rootoptsbuf) - 1] = '\0';
2554 opts = rootoptsbuf;
2555 while (*opts) {
2556 int opt;
2558 switch (opt = getsubopt(&opts, optlist, &val)) {
2560 * Options that are defaults or meaningless so ignored
2562 case OPT_QUOTA:
2563 case OPT_NOQUOTA:
2564 case OPT_SUID:
2565 case OPT_DEVICES:
2566 case OPT_SETUID:
2567 case OPT_BG:
2568 case OPT_FG:
2569 case OPT_RETRY:
2570 case OPT_POSIX:
2571 case OPT_LARGEFILES:
2572 case OPT_XATTR:
2573 case OPT_NOXATTR:
2574 case OPT_EXEC:
2575 break;
2576 case OPT_RO:
2577 *vfsflags |= MS_RDONLY;
2578 break;
2579 case OPT_RW:
2580 *vfsflags &= ~(MS_RDONLY);
2581 break;
2582 case OPT_SOFT:
2583 args->flags |= NFSMNT_SOFT;
2584 args->flags &= ~(NFSMNT_SEMISOFT);
2585 break;
2586 case OPT_SEMISOFT:
2587 args->flags |= NFSMNT_SOFT;
2588 args->flags |= NFSMNT_SEMISOFT;
2589 break;
2590 case OPT_HARD:
2591 args->flags &= ~(NFSMNT_SOFT);
2592 args->flags &= ~(NFSMNT_SEMISOFT);
2593 break;
2594 case OPT_NOSUID:
2595 case OPT_NODEVICES:
2596 case OPT_NOSETUID:
2597 case OPT_NOEXEC:
2598 cmn_err(CE_WARN,
2599 "nfs_dlboot: may not set root partition %s",
2600 optlist[opt]);
2601 break;
2602 case OPT_GRPID:
2603 args->flags |= NFSMNT_GRPID;
2604 break;
2605 case OPT_REMOUNT:
2606 cmn_err(CE_WARN,
2607 "nfs_dlboot: may not remount root partition");
2608 break;
2609 case OPT_INTR:
2610 args->flags |= NFSMNT_INT;
2611 break;
2612 case OPT_NOINTR:
2613 args->flags &= ~(NFSMNT_INT);
2614 break;
2615 case OPT_NOAC:
2616 args->flags |= NFSMNT_NOAC;
2617 break;
2618 case OPT_PORT:
2619 cmn_err(CE_WARN,
2620 "nfs_dlboot: may not change root port number");
2621 break;
2622 case OPT_SECURE:
2623 cmn_err(CE_WARN,
2624 "nfs_dlboot: root mounted auth_unix, secure ignored");
2625 break;
2626 case OPT_NOCTO:
2627 args->flags |= NFSMNT_NOCTO;
2628 break;
2629 case OPT_RSIZE:
2630 if (bad(val)) {
2631 cmn_err(CE_WARN,
2632 "nfs_dlboot: invalid option: rsize");
2633 break;
2635 args->flags |= NFSMNT_RSIZE;
2636 args->rsize = atoi(val);
2637 break;
2638 case OPT_WSIZE:
2639 if (bad(val)) {
2640 cmn_err(CE_WARN,
2641 "nfs_dlboot: invalid option: wsize");
2642 break;
2644 args->flags |= NFSMNT_WSIZE;
2645 args->wsize = atoi(val);
2646 break;
2647 case OPT_TIMEO:
2648 if (bad(val)) {
2649 cmn_err(CE_WARN,
2650 "nfs_dlboot: invalid option: timeo");
2651 break;
2653 args->flags |= NFSMNT_TIMEO;
2654 args->timeo = atoi(val);
2655 break;
2656 case OPT_RETRANS:
2657 if (bad(val)) {
2658 cmn_err(CE_WARN,
2659 "nfs_dlboot: invalid option: retrans");
2660 break;
2662 args->flags |= NFSMNT_RETRANS;
2663 args->retrans = atoi(val);
2664 break;
2665 case OPT_ACTIMEO:
2666 if (bad(val)) {
2667 cmn_err(CE_WARN,
2668 "nfs_dlboot: invalid option: actimeo");
2669 break;
2671 args->flags |= NFSMNT_ACDIRMAX;
2672 args->flags |= NFSMNT_ACREGMAX;
2673 args->flags |= NFSMNT_ACDIRMIN;
2674 args->flags |= NFSMNT_ACREGMIN;
2675 args->acdirmin = args->acregmin = args->acdirmax =
2676 args->acregmax = atoi(val);
2677 break;
2678 case OPT_ACREGMIN:
2679 if (bad(val)) {
2680 cmn_err(CE_WARN,
2681 "nfs_dlboot: invalid option: acregmin");
2682 break;
2684 args->flags |= NFSMNT_ACREGMIN;
2685 args->acregmin = atoi(val);
2686 break;
2687 case OPT_ACREGMAX:
2688 if (bad(val)) {
2689 cmn_err(CE_WARN,
2690 "nfs_dlboot: invalid option: acregmax");
2691 break;
2693 args->flags |= NFSMNT_ACREGMAX;
2694 args->acregmax = atoi(val);
2695 break;
2696 case OPT_ACDIRMIN:
2697 if (bad(val)) {
2698 cmn_err(CE_WARN,
2699 "nfs_dlboot: invalid option: acdirmin");
2700 break;
2702 args->flags |= NFSMNT_ACDIRMIN;
2703 args->acdirmin = atoi(val);
2704 break;
2705 case OPT_ACDIRMAX:
2706 if (bad(val)) {
2707 cmn_err(CE_WARN,
2708 "nfs_dlboot: invalid option: acdirmax");
2709 break;
2711 args->flags |= NFSMNT_ACDIRMAX;
2712 args->acdirmax = atoi(val);
2713 break;
2714 case OPT_LLOCK:
2715 args->flags |= NFSMNT_LLOCK;
2716 break;
2717 case OPT_VERS:
2718 if (bad(val)) {
2719 cmn_err(CE_WARN,
2720 "nfs_dlboot: invalid option: vers");
2721 break;
2723 vers = atoi(val);
2725 * If the requested version is less than what we
2726 * chose, pretend the chosen version doesn't exist
2728 if (vers < version) {
2729 return (EPROTONOSUPPORT);
2731 if (vers > version) {
2732 cmn_err(CE_WARN,
2733 "nfs_dlboot: version %d unavailable",
2734 vers);
2735 return (EINVAL);
2737 break;
2738 case OPT_PROTO:
2740 * NFSv4 can only run over TCP, if they requested
2741 * UDP pretend v4 doesn't exist, they might not have
2742 * specified a version allowing a fallback to v2 or v3.
2744 if (version == NFS_V4 && strcmp(val, NC_UDP) == 0)
2745 return (EPROTONOSUPPORT);
2747 * TCP is always chosen over UDP, so if the
2748 * requested is the same as the chosen either
2749 * they chose TCP when available or UDP on a UDP
2750 * only server.
2752 if (strcmp(cf->knc_proto, val) == 0)
2753 break;
2755 * If we chose UDP, they must have requested TCP
2757 if (strcmp(cf->knc_proto, NC_TCP) != 0) {
2758 cmn_err(CE_WARN,
2759 "nfs_dlboot: TCP protocol unavailable");
2760 return (EINVAL);
2763 * They can only have requested UDP
2765 if (strcmp(val, NC_UDP) != 0) {
2766 cmn_err(CE_WARN,
2767 "nfs_dlboot: unknown protocol");
2768 return (EINVAL);
2770 *dl_cf = &dl_udp_netconf;
2771 break;
2772 case OPT_NOPRINT:
2773 args->flags |= NFSMNT_NOPRINT;
2774 break;
2775 case OPT_NOLARGEFILES:
2776 cmn_err(CE_WARN,
2777 "nfs_dlboot: NFS can't support nolargefiles");
2778 break;
2779 case OPT_SEC:
2780 cmn_err(CE_WARN,
2781 "nfs_dlboot: root mounted auth_unix, sec ignored");
2782 break;
2784 case OPT_DIRECTIO:
2785 args->flags |= NFSMNT_DIRECTIO;
2786 break;
2788 case OPT_NODIRECTIO:
2789 args->flags &= ~(NFSMNT_DIRECTIO);
2790 break;
2792 default:
2793 cmn_err(CE_WARN,
2794 "nfs_dlboot: ignoring invalid option \"%s\"", val);
2795 break;
2798 sanity:
2800 * Set some sane limits on read size
2802 if (!(args->flags & NFSMNT_RSIZE) || args->rsize == 0) {
2804 * Establish defaults
2806 args->flags |= NFSMNT_RSIZE;
2807 if (version == NFS_V4)
2808 args->rsize = nfs4_root_rsize;
2809 else
2810 args->rsize = nfs_root_rsize;
2811 return (0);
2814 * No less than 512 bytes, otherwise it will take forever to boot
2816 if (args->rsize < 512)
2817 args->rsize = 512;
2819 * If we are running over UDP, we cannot exceed 64KB, trim
2820 * to 56KB to allow room for headers.
2822 if (*dl_cf == &dl_udp_netconf && args->rsize > (56 * 1024))
2823 args->rsize = 56 * 1024;
2824 return (0);