xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/ndd.c (revision bbf21555)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54045d941Ssowmini  * Common Development and Distribution License (the "License").
64045d941Ssowmini  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
228887b57dSGirish Moodalbail  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
248887b57dSGirish Moodalbail /* Copyright (c) 1990 Mentat Inc. */
257c478bd9Sstevel@tonic-gate 
268887b57dSGirish Moodalbail #include <assert.h>
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <errno.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <stdarg.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <unistd.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <stropts.h>
356e91bba0SGirish Moodalbail #include <inet/tunables.h>
367c478bd9Sstevel@tonic-gate #include <inet/nd.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
386e91bba0SGirish Moodalbail #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
404045d941Ssowmini #include <libdllink.h>
414045d941Ssowmini #include <libintl.h>
426e91bba0SGirish Moodalbail #include <libipadm.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static boolean_t do_getset(int fd, int cmd, char *buf, int buf_len);
457c478bd9Sstevel@tonic-gate static int	get_value(char *msg, char *buf, int buf_len);
467c478bd9Sstevel@tonic-gate static void	name_print(char *buf);
477c478bd9Sstevel@tonic-gate static void	getset_interactive(int fd);
48a924b63fSVasumathi Sundaram - Sun Microsystems static int	open_device(void);
497c478bd9Sstevel@tonic-gate static char	*errmsg(int err);
507c478bd9Sstevel@tonic-gate static void	fatal(char *fmt, ...);
517c478bd9Sstevel@tonic-gate static void	printe(boolean_t print_errno, char *fmt, ...);
527c478bd9Sstevel@tonic-gate 
536e91bba0SGirish Moodalbail static char	modpath[128];	/* path to module */
546e91bba0SGirish Moodalbail static char	gbuf[65536];	/* need large buffer to retrieve all names */
557c478bd9Sstevel@tonic-gate static char	usage_str[] =	"usage: ndd -set device_name name value\n"
567c478bd9Sstevel@tonic-gate 				"       ndd [-get] device_name name [name ...]";
577c478bd9Sstevel@tonic-gate 
586e91bba0SGirish Moodalbail /*
596e91bba0SGirish Moodalbail  * Maps old ndd_name to the new ipadm_name. Any ndd property that is moved to
606e91bba0SGirish Moodalbail  * libipadm should have an entry here to ensure backward compatibility
616e91bba0SGirish Moodalbail  */
626e91bba0SGirish Moodalbail typedef struct ndd2ipadm_map {
636e91bba0SGirish Moodalbail 	char	*ndd_name;
646e91bba0SGirish Moodalbail 	char	*ipadm_name;
656e91bba0SGirish Moodalbail 	uint_t	ipadm_proto;
666e91bba0SGirish Moodalbail 	uint_t	ipadm_flags;
676e91bba0SGirish Moodalbail 	uint_t	ndd_perm;
686e91bba0SGirish Moodalbail } ndd2ipadm_map_t;
696e91bba0SGirish Moodalbail 
706e91bba0SGirish Moodalbail static ndd2ipadm_map_t map[] = {
716e91bba0SGirish Moodalbail 	{ "ip_def_ttl",			"ttl",		MOD_PROTO_IPV4, 0, 0 },
726e91bba0SGirish Moodalbail 	{ "ip6_def_hops",		"hoplimit",	MOD_PROTO_IPV6, 0, 0 },
736e91bba0SGirish Moodalbail 	{ "ip_forwarding",		"forwarding",	MOD_PROTO_IPV4, 0, 0 },
746e91bba0SGirish Moodalbail 	{ "ip6_forwarding",		"forwarding",	MOD_PROTO_IPV6, 0, 0 },
756e91bba0SGirish Moodalbail 	{ "icmp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_RAWIP, 0, 0 },
766e91bba0SGirish Moodalbail 	{ "icmp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_RAWIP, 0, 0 },
776e91bba0SGirish Moodalbail 	{ "tcp_ecn_permitted",		"ecn",		MOD_PROTO_TCP, 0, 0 },
786e91bba0SGirish Moodalbail 	{ "tcp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_TCP,
796e91bba0SGirish Moodalbail 	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
806e91bba0SGirish Moodalbail 	{ "tcp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_TCP,
816e91bba0SGirish Moodalbail 	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
826e91bba0SGirish Moodalbail 	{ "tcp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_TCP,
836e91bba0SGirish Moodalbail 	    0, MOD_PROP_PERM_READ },
846e91bba0SGirish Moodalbail 	{ "tcp_largest_anon_port",	"largest_anon_port",	MOD_PROTO_TCP,
856e91bba0SGirish Moodalbail 	    0, 0 },
866e91bba0SGirish Moodalbail 	{ "tcp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_TCP, 0, 0 },
876e91bba0SGirish Moodalbail 	{ "tcp_sack_permitted",		"sack",		MOD_PROTO_TCP, 0, 0 },
886e91bba0SGirish Moodalbail 	{ "tcp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_TCP, 0, 0 },
896e91bba0SGirish Moodalbail 	{ "tcp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_TCP,
906e91bba0SGirish Moodalbail 	    0, 0 },
916e91bba0SGirish Moodalbail 	{ "tcp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_TCP,
926e91bba0SGirish Moodalbail 	    0, 0 },
936e91bba0SGirish Moodalbail 	{ "udp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_UDP,
946e91bba0SGirish Moodalbail 	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
956e91bba0SGirish Moodalbail 	{ "udp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_UDP,
966e91bba0SGirish Moodalbail 	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
976e91bba0SGirish Moodalbail 	{ "udp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_UDP,
986e91bba0SGirish Moodalbail 	    0, MOD_PROP_PERM_READ },
996e91bba0SGirish Moodalbail 	{ "udp_largest_anon_port",	"largest_anon_port",    MOD_PROTO_UDP,
1006e91bba0SGirish Moodalbail 	    0, 0 },
1016e91bba0SGirish Moodalbail 	{ "udp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_UDP, 0, 0 },
1026e91bba0SGirish Moodalbail 	{ "udp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_UDP, 0, 0 },
1036e91bba0SGirish Moodalbail 	{ "udp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_UDP,
1046e91bba0SGirish Moodalbail 	    0, 0 },
1056e91bba0SGirish Moodalbail 	{ "udp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_UDP,
1066e91bba0SGirish Moodalbail 	    0, 0 },
1076e91bba0SGirish Moodalbail 	{ "sctp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_SCTP,
1086e91bba0SGirish Moodalbail 	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
1096e91bba0SGirish Moodalbail 	{ "sctp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_SCTP,
1106e91bba0SGirish Moodalbail 	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
1116e91bba0SGirish Moodalbail 	{ "sctp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_SCTP,
1126e91bba0SGirish Moodalbail 	    0, MOD_PROP_PERM_READ },
1136e91bba0SGirish Moodalbail 	{ "sctp_largest_anon_port",	"largest_anon_port",	MOD_PROTO_SCTP,
1146e91bba0SGirish Moodalbail 	    0, 0 },
1156e91bba0SGirish Moodalbail 	{ "sctp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_SCTP, 0, 0 },
1166e91bba0SGirish Moodalbail 	{ "sctp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_SCTP, 0, 0 },
1176e91bba0SGirish Moodalbail 	{ "sctp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_SCTP,
1186e91bba0SGirish Moodalbail 	    0, 0 },
1196e91bba0SGirish Moodalbail 	{ "sctp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_SCTP,
1206e91bba0SGirish Moodalbail 	    0, 0 },
1216e91bba0SGirish Moodalbail 	{ NULL, NULL, 0, 0, 0 }
1226e91bba0SGirish Moodalbail };
1236e91bba0SGirish Moodalbail 
1246e91bba0SGirish Moodalbail static uint_t
ndd_str2proto(const char * protostr)1256e91bba0SGirish Moodalbail ndd_str2proto(const char *protostr)
1266e91bba0SGirish Moodalbail {
1276e91bba0SGirish Moodalbail 	if (strcmp(protostr, "tcp") == 0 ||
1286e91bba0SGirish Moodalbail 	    strcmp(protostr, "tcp6") == 0) {
1296e91bba0SGirish Moodalbail 		return (MOD_PROTO_TCP);
1306e91bba0SGirish Moodalbail 	} else if (strcmp(protostr, "udp") == 0 ||
1316e91bba0SGirish Moodalbail 	    strcmp(protostr, "udp6") == 0) {
1326e91bba0SGirish Moodalbail 		return (MOD_PROTO_UDP);
1336e91bba0SGirish Moodalbail 	} else if (strcmp(protostr, "ip") == 0 ||
1346e91bba0SGirish Moodalbail 	    strcmp(protostr, "ip6") == 0 ||
1356e91bba0SGirish Moodalbail 	    strcmp(protostr, "arp") == 0) {
1366e91bba0SGirish Moodalbail 		return (MOD_PROTO_IP);
1376e91bba0SGirish Moodalbail 	} else if (strcmp(protostr, "icmp") == 0 ||
1386e91bba0SGirish Moodalbail 	    strcmp(protostr, "icmp6") == 0) {
1396e91bba0SGirish Moodalbail 		return (MOD_PROTO_RAWIP);
1406e91bba0SGirish Moodalbail 	} else if (strcmp(protostr, "sctp") == 0 ||
1416e91bba0SGirish Moodalbail 	    strcmp(protostr, "sctp6") == 0) {
1426e91bba0SGirish Moodalbail 		return (MOD_PROTO_SCTP);
1436e91bba0SGirish Moodalbail 	}
1446e91bba0SGirish Moodalbail 	return (MOD_PROTO_NONE);
1456e91bba0SGirish Moodalbail }
1466e91bba0SGirish Moodalbail 
1476e91bba0SGirish Moodalbail static char *
ndd_perm2str(uint_t perm)1486e91bba0SGirish Moodalbail ndd_perm2str(uint_t perm)
1496e91bba0SGirish Moodalbail {
1506e91bba0SGirish Moodalbail 	switch (perm) {
1516e91bba0SGirish Moodalbail 	case MOD_PROP_PERM_READ:
1526e91bba0SGirish Moodalbail 		return ("read only");
1536e91bba0SGirish Moodalbail 	case MOD_PROP_PERM_WRITE:
1546e91bba0SGirish Moodalbail 		return ("write only");
1556e91bba0SGirish Moodalbail 	case MOD_PROP_PERM_RW:
1566e91bba0SGirish Moodalbail 		return ("read and write");
1576e91bba0SGirish Moodalbail 	}
1586e91bba0SGirish Moodalbail 
1596e91bba0SGirish Moodalbail 	return (NULL);
1606e91bba0SGirish Moodalbail }
1616e91bba0SGirish Moodalbail 
1626e91bba0SGirish Moodalbail /*
1638887b57dSGirish Moodalbail  * Print all the protocol properties for the given protocol name. The kernel
1648887b57dSGirish Moodalbail  * returns all the properties for the given protocol therefore we have to
1658887b57dSGirish Moodalbail  * apply some filters before we print them.
1668887b57dSGirish Moodalbail  *
1678887b57dSGirish Moodalbail  *	- convert any new ipadm name to old ndd name using the table.
1688887b57dSGirish Moodalbail  *	  For example: `sack' --> `tcp_sack_permitted'.
1698887b57dSGirish Moodalbail  *
1708887b57dSGirish Moodalbail  *	- replace leading underscores with protocol name.
1718887b57dSGirish Moodalbail  *	  For example: `_strong_iss' --> `tcp_strong_iss'
1728887b57dSGirish Moodalbail  *
173*bbf21555SRichard Lowe  *	- don't print new public properties that are supported only by ipadm(8)
174*bbf21555SRichard Lowe  *	  For example: `hostmodel' should be supported only from ipadm(8).
1758887b57dSGirish Moodalbail  *	  Such properties are identified by not having leading '_' and not
1768887b57dSGirish Moodalbail  *	  being present in the mapping table.
1776e91bba0SGirish Moodalbail  */
1786e91bba0SGirish Moodalbail static void
print_ipadm2ndd(char * oldbuf,uint_t obufsize)1796e91bba0SGirish Moodalbail print_ipadm2ndd(char *oldbuf, uint_t obufsize)
1806e91bba0SGirish Moodalbail {
1816e91bba0SGirish Moodalbail 	ndd2ipadm_map_t	*nimap;
1826e91bba0SGirish Moodalbail 	char		*pname, *rwtag, *protostr;
1836e91bba0SGirish Moodalbail 	uint_t		proto, perm;
1846e91bba0SGirish Moodalbail 	boolean_t	matched;
1856e91bba0SGirish Moodalbail 
1866e91bba0SGirish Moodalbail 	pname = oldbuf;
1876e91bba0SGirish Moodalbail 	while (pname[0] && pname < (oldbuf + obufsize - 1)) {
1886e91bba0SGirish Moodalbail 		for (protostr = pname; !isspace(*protostr); protostr++)
1896e91bba0SGirish Moodalbail 			;
1906e91bba0SGirish Moodalbail 		*protostr++ = '\0';
1916e91bba0SGirish Moodalbail 		/* protostr now points to protocol */
1926e91bba0SGirish Moodalbail 
1936e91bba0SGirish Moodalbail 		for (rwtag = protostr; !isspace(*rwtag); rwtag++)
1946e91bba0SGirish Moodalbail 			;
1956e91bba0SGirish Moodalbail 		*rwtag++ = '\0';
1966e91bba0SGirish Moodalbail 		/* rwtag now points to permissions */
1976e91bba0SGirish Moodalbail 
1986e91bba0SGirish Moodalbail 		proto = atoi(protostr);
1996e91bba0SGirish Moodalbail 		perm = atoi(rwtag);
2006e91bba0SGirish Moodalbail 		matched = B_FALSE;
2016e91bba0SGirish Moodalbail 		for (nimap = map; nimap->ndd_name != NULL; nimap++) {
2026e91bba0SGirish Moodalbail 			if (strcmp(pname, nimap->ipadm_name) != 0 ||
2036e91bba0SGirish Moodalbail 			    !(nimap->ipadm_proto & proto))
2046e91bba0SGirish Moodalbail 				continue;
2056e91bba0SGirish Moodalbail 
2066e91bba0SGirish Moodalbail 			matched = B_TRUE;
2076e91bba0SGirish Moodalbail 			if (nimap->ndd_perm != 0)
2086e91bba0SGirish Moodalbail 				perm = nimap->ndd_perm;
2096e91bba0SGirish Moodalbail 			(void) printf("%-30s (%s)\n", nimap->ndd_name,
2106e91bba0SGirish Moodalbail 			    ndd_perm2str(perm));
2116e91bba0SGirish Moodalbail 		}
2128887b57dSGirish Moodalbail 		/*
2138887b57dSGirish Moodalbail 		 * print only if it's a private property. We should
214*bbf21555SRichard Lowe 		 * not be printing any new public property in ndd(8)
2158887b57dSGirish Moodalbail 		 * output.
2168887b57dSGirish Moodalbail 		 */
2178887b57dSGirish Moodalbail 		if (!matched && pname[0] == '_') {
2188887b57dSGirish Moodalbail 			char	tmpstr[512];
2198887b57dSGirish Moodalbail 			int	err;
2208887b57dSGirish Moodalbail 
2218887b57dSGirish Moodalbail 			err = ipadm_new2legacy_propname(pname, tmpstr,
2228887b57dSGirish Moodalbail 			    sizeof (tmpstr), proto);
2238887b57dSGirish Moodalbail 			assert(err != -1);
2248887b57dSGirish Moodalbail 
2258887b57dSGirish Moodalbail 			(void) printf("%-30s (%s)\n", tmpstr,
2266e91bba0SGirish Moodalbail 			    ndd_perm2str(perm));
2278887b57dSGirish Moodalbail 		}
2286e91bba0SGirish Moodalbail 		for (pname = rwtag; *pname++; )
2296e91bba0SGirish Moodalbail 			;
2306e91bba0SGirish Moodalbail 	}
2316e91bba0SGirish Moodalbail }
2326e91bba0SGirish Moodalbail 
2336e91bba0SGirish Moodalbail /*
2346e91bba0SGirish Moodalbail  * get/set the value for a given property by calling into libipadm. The
2356e91bba0SGirish Moodalbail  * IPH_LEGACY flag is used by libipadm for special handling. For some
2366e91bba0SGirish Moodalbail  * properties, libipadm.so displays strings (for e.g., on/off,
237*bbf21555SRichard Lowe  * never/passive/active, et al) instead of numerals. However ndd(8) always
2386e91bba0SGirish Moodalbail  * printed numberals. This flag will help in avoiding printing strings.
2396e91bba0SGirish Moodalbail  */
2406e91bba0SGirish Moodalbail static boolean_t
do_ipadm_getset(int cmd,char * buf,int buflen)2416e91bba0SGirish Moodalbail do_ipadm_getset(int cmd, char *buf, int buflen)
2426e91bba0SGirish Moodalbail {
2436e91bba0SGirish Moodalbail 	ndd2ipadm_map_t	*nimap;
2446e91bba0SGirish Moodalbail 	ipadm_handle_t	iph = NULL;
2456e91bba0SGirish Moodalbail 	ipadm_status_t	status;
2466e91bba0SGirish Moodalbail 	char		*mod;
2476e91bba0SGirish Moodalbail 	uint_t		proto, perm = 0, flags = 0;
2488887b57dSGirish Moodalbail 	char		*pname, *pvalp, nname[512];
2496e91bba0SGirish Moodalbail 	int		i;
2506e91bba0SGirish Moodalbail 
2516e91bba0SGirish Moodalbail 	if ((mod = strrchr(modpath, '/')) == NULL)
2526e91bba0SGirish Moodalbail 		mod = modpath;
2536e91bba0SGirish Moodalbail 	else
2546e91bba0SGirish Moodalbail 		++mod;
2556e91bba0SGirish Moodalbail 	if ((proto = ndd_str2proto(mod)) == MOD_PROTO_NONE)
2566e91bba0SGirish Moodalbail 		return (B_FALSE);
2576e91bba0SGirish Moodalbail 
2586e91bba0SGirish Moodalbail 	if ((status = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS)
2596e91bba0SGirish Moodalbail 		goto fail;
2606e91bba0SGirish Moodalbail 
2616e91bba0SGirish Moodalbail 	pname = buf;
2626e91bba0SGirish Moodalbail 	for (nimap = map; nimap->ndd_name != NULL; nimap++) {
2638887b57dSGirish Moodalbail 		if (strcmp(pname, nimap->ndd_name) == 0) {
2648887b57dSGirish Moodalbail 			pname = nimap->ipadm_name;
2658887b57dSGirish Moodalbail 			proto = nimap->ipadm_proto;
2668887b57dSGirish Moodalbail 			flags = nimap->ipadm_flags;
2678887b57dSGirish Moodalbail 			perm = nimap->ndd_perm;
2686e91bba0SGirish Moodalbail 			break;
2698887b57dSGirish Moodalbail 		}
2706e91bba0SGirish Moodalbail 	}
2718887b57dSGirish Moodalbail 
2728887b57dSGirish Moodalbail 	if (nimap->ndd_name == NULL && strcmp(pname, "?") != 0) {
273*bbf21555SRichard Lowe 		/* do not allow set/get of public properties from ndd(8) */
2748887b57dSGirish Moodalbail 		if (ipadm_legacy2new_propname(pname, nname, sizeof (nname),
2758887b57dSGirish Moodalbail 		    &proto) != 0) {
2768887b57dSGirish Moodalbail 			status = IPADM_PROP_UNKNOWN;
2778887b57dSGirish Moodalbail 			goto fail;
2788887b57dSGirish Moodalbail 		} else {
2798887b57dSGirish Moodalbail 			pname = nname;
2808887b57dSGirish Moodalbail 		}
2816e91bba0SGirish Moodalbail 	}
2828887b57dSGirish Moodalbail 
2836e91bba0SGirish Moodalbail 	if (cmd == ND_GET) {
2846e91bba0SGirish Moodalbail 		char		propval[MAXPROPVALLEN], allprop[64536];
2856e91bba0SGirish Moodalbail 		uint_t		pvalsz;
2866e91bba0SGirish Moodalbail 		sa_family_t	af = AF_UNSPEC;
2876e91bba0SGirish Moodalbail 		int		err;
2886e91bba0SGirish Moodalbail 
2896e91bba0SGirish Moodalbail 		if (perm == MOD_PROP_PERM_WRITE)
2906e91bba0SGirish Moodalbail 			fatal("operation failed: Permission denied");
2916e91bba0SGirish Moodalbail 
2926e91bba0SGirish Moodalbail 		if (strcmp(pname, "?") == 0) {
2936e91bba0SGirish Moodalbail 			pvalp = allprop;
2946e91bba0SGirish Moodalbail 			pvalsz = sizeof (allprop);
2956e91bba0SGirish Moodalbail 		} else {
2966e91bba0SGirish Moodalbail 			pvalp = propval;
2976e91bba0SGirish Moodalbail 			pvalsz = sizeof (propval);
2986e91bba0SGirish Moodalbail 		}
2996e91bba0SGirish Moodalbail 
3006e91bba0SGirish Moodalbail 		status = ipadm_get_prop(iph, pname, pvalp, &pvalsz, proto,
3016e91bba0SGirish Moodalbail 		    IPADM_OPT_ACTIVE);
3026e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
3036e91bba0SGirish Moodalbail 			goto fail;
3046e91bba0SGirish Moodalbail 
3056e91bba0SGirish Moodalbail 		if (strcmp(pname, "?") == 0) {
3066e91bba0SGirish Moodalbail 			(void) print_ipadm2ndd(pvalp, pvalsz);
3076e91bba0SGirish Moodalbail 		} else {
3086e91bba0SGirish Moodalbail 			char *tmp = pvalp;
3096e91bba0SGirish Moodalbail 
3106e91bba0SGirish Moodalbail 			/*
3116e91bba0SGirish Moodalbail 			 * For backward compatibility if there are multiple
3126e91bba0SGirish Moodalbail 			 * values print each value in it's own line.
3136e91bba0SGirish Moodalbail 			 */
3146e91bba0SGirish Moodalbail 			while (*tmp != '\0') {
3156e91bba0SGirish Moodalbail 				if (*tmp == ',')
3166e91bba0SGirish Moodalbail 					*tmp = '\n';
3176e91bba0SGirish Moodalbail 				tmp++;
3186e91bba0SGirish Moodalbail 			}
3196e91bba0SGirish Moodalbail 			(void) printf("%s\n", pvalp);
3206e91bba0SGirish Moodalbail 		}
3216e91bba0SGirish Moodalbail 		(void) fflush(stdout);
3226e91bba0SGirish Moodalbail 	} else {
3236e91bba0SGirish Moodalbail 		if (perm == MOD_PROP_PERM_READ)
3246e91bba0SGirish Moodalbail 			fatal("operation failed: Permission denied");
3256e91bba0SGirish Moodalbail 
3266e91bba0SGirish Moodalbail 		/* walk past the property name to find the property value */
3276e91bba0SGirish Moodalbail 		for (i = 0; buf[i] != '\0'; i++)
3286e91bba0SGirish Moodalbail 			;
3296e91bba0SGirish Moodalbail 
3306e91bba0SGirish Moodalbail 		pvalp = &buf[++i];
3316e91bba0SGirish Moodalbail 		status = ipadm_set_prop(iph, pname, pvalp, proto,
3326e91bba0SGirish Moodalbail 		    flags|IPADM_OPT_ACTIVE);
3336e91bba0SGirish Moodalbail 	}
3346e91bba0SGirish Moodalbail fail:
3356e91bba0SGirish Moodalbail 	ipadm_close(iph);
3366e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
3376e91bba0SGirish Moodalbail 		fatal("operation failed: %s", ipadm_status2str(status));
3386e91bba0SGirish Moodalbail 	return (B_TRUE);
3396e91bba0SGirish Moodalbail }
3406e91bba0SGirish Moodalbail 
341149b7eb2SSowmini Varadhan /*
342149b7eb2SSowmini Varadhan  * gldv3_warning() catches the case of /sbin/ndd abuse to administer
343149b7eb2SSowmini Varadhan  * ethernet/MII props. Note that /sbin/ndd has not been abused
344149b7eb2SSowmini Varadhan  * for administration of other datalink types, which makes it permissible
345149b7eb2SSowmini Varadhan  * to test for support of the flowctrl property.
346149b7eb2SSowmini Varadhan  */
3474045d941Ssowmini static void
gldv3_warning(char * module)348a924b63fSVasumathi Sundaram - Sun Microsystems gldv3_warning(char *module)
3494045d941Ssowmini {
3504045d941Ssowmini 	datalink_id_t	linkid;
3514045d941Ssowmini 	dladm_status_t	status;
3524045d941Ssowmini 	char		buf[DLADM_PROP_VAL_MAX], *cp;
353149b7eb2SSowmini Varadhan 	uint_t		cnt = 1;
3544045d941Ssowmini 	char		*link;
355a924b63fSVasumathi Sundaram - Sun Microsystems 	dladm_handle_t	handle;
3564045d941Ssowmini 
3574045d941Ssowmini 	link = strrchr(module, '/');
3584045d941Ssowmini 	if (link == NULL)
3594045d941Ssowmini 		return;
360a924b63fSVasumathi Sundaram - Sun Microsystems 
361a924b63fSVasumathi Sundaram - Sun Microsystems 	if (dladm_open(&handle) != DLADM_STATUS_OK)
3624045d941Ssowmini 		return;
363a924b63fSVasumathi Sundaram - Sun Microsystems 
364a924b63fSVasumathi Sundaram - Sun Microsystems 	status = dladm_name2info(handle, ++link, &linkid, NULL, NULL, NULL);
365a924b63fSVasumathi Sundaram - Sun Microsystems 	if (status == DLADM_STATUS_OK) {
366a924b63fSVasumathi Sundaram - Sun Microsystems 		cp = buf;
367a924b63fSVasumathi Sundaram - Sun Microsystems 		status = dladm_get_linkprop(handle, linkid,
368a924b63fSVasumathi Sundaram - Sun Microsystems 		    DLADM_PROP_VAL_CURRENT, "flowctrl", &cp, &cnt);
369a924b63fSVasumathi Sundaram - Sun Microsystems 		if (status == DLADM_STATUS_OK) {
370a924b63fSVasumathi Sundaram - Sun Microsystems 			(void) fprintf(stderr, gettext(
371a924b63fSVasumathi Sundaram - Sun Microsystems 			    "WARNING: The ndd commands for datalink "
372a924b63fSVasumathi Sundaram - Sun Microsystems 			    "administration are obsolete and may be "
373a924b63fSVasumathi Sundaram - Sun Microsystems 			    "removed in a future release of Solaris. "
374*bbf21555SRichard Lowe 			    "Use dladm(8) to manage datalink tunables.\n"));
375a924b63fSVasumathi Sundaram - Sun Microsystems 		}
376a924b63fSVasumathi Sundaram - Sun Microsystems 	}
377a924b63fSVasumathi Sundaram - Sun Microsystems 	dladm_close(handle);
3784045d941Ssowmini }
3794045d941Ssowmini 
3807c478bd9Sstevel@tonic-gate /* ARGSUSED */
3817c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)3827c478bd9Sstevel@tonic-gate main(int argc, char **argv)
3837c478bd9Sstevel@tonic-gate {
3846e91bba0SGirish Moodalbail 	char	*cp, *value, *mod;
3857c478bd9Sstevel@tonic-gate 	int	cmd;
3866e91bba0SGirish Moodalbail 	int	fd = 0;
3874045d941Ssowmini 
3887c478bd9Sstevel@tonic-gate 	if (!(cp = *++argv)) {
389a924b63fSVasumathi Sundaram - Sun Microsystems 		while ((fd = open_device()) != -1) {
3907c478bd9Sstevel@tonic-gate 			getset_interactive(fd);
3917c478bd9Sstevel@tonic-gate 			(void) close(fd);
3927c478bd9Sstevel@tonic-gate 		}
3937c478bd9Sstevel@tonic-gate 		return (EXIT_SUCCESS);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	cmd = ND_GET;
3977c478bd9Sstevel@tonic-gate 	if (cp[0] == '-') {
3987c478bd9Sstevel@tonic-gate 		if (strncmp(&cp[1], "set", 3) == 0)
3997c478bd9Sstevel@tonic-gate 			cmd = ND_SET;
4007c478bd9Sstevel@tonic-gate 		else if (strncmp(&cp[1], "get", 3) != 0)
4017c478bd9Sstevel@tonic-gate 			fatal(usage_str);
4027c478bd9Sstevel@tonic-gate 		if (!(cp = *++argv))
4037c478bd9Sstevel@tonic-gate 			fatal(usage_str);
4047c478bd9Sstevel@tonic-gate 	}
4056e91bba0SGirish Moodalbail 
406a924b63fSVasumathi Sundaram - Sun Microsystems 	gldv3_warning(cp);
4074ac67f02SAnurag S. Maskey 
4086e91bba0SGirish Moodalbail 	mod = strrchr(cp, '/');
4096e91bba0SGirish Moodalbail 	if (mod != NULL)
4106e91bba0SGirish Moodalbail 		mod++;
4116e91bba0SGirish Moodalbail 	else
4126e91bba0SGirish Moodalbail 		mod = cp;
4137c478bd9Sstevel@tonic-gate 
4146e91bba0SGirish Moodalbail 	if (ndd_str2proto(mod) == MOD_PROTO_NONE) {
4156e91bba0SGirish Moodalbail 		if ((fd = open(cp, O_RDWR)) == -1)
4166e91bba0SGirish Moodalbail 			fatal("open of %s failed: %s", cp, errmsg(errno));
4176e91bba0SGirish Moodalbail 		if (!isastream(fd))
4186e91bba0SGirish Moodalbail 			fatal("%s is not a streams device", cp);
4196e91bba0SGirish Moodalbail 	}
4207c478bd9Sstevel@tonic-gate 
4216e91bba0SGirish Moodalbail 	(void) strlcpy(modpath, cp, sizeof (modpath));
4227c478bd9Sstevel@tonic-gate 	if (!(cp = *++argv)) {
4237c478bd9Sstevel@tonic-gate 		getset_interactive(fd);
4247c478bd9Sstevel@tonic-gate 		(void) close(fd);
4257c478bd9Sstevel@tonic-gate 		return (EXIT_SUCCESS);
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	if (cmd == ND_SET) {
4297c478bd9Sstevel@tonic-gate 		if (!(value = *++argv))
4307c478bd9Sstevel@tonic-gate 			fatal(usage_str);
4317c478bd9Sstevel@tonic-gate 		(void) snprintf(gbuf, sizeof (gbuf), "%s%c%s%c", cp, '\0',
4327c478bd9Sstevel@tonic-gate 		    value, '\0');
4337c478bd9Sstevel@tonic-gate 		if (!do_getset(fd, cmd, gbuf, sizeof (gbuf)))
4347c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
4357c478bd9Sstevel@tonic-gate 	} else {
4367c478bd9Sstevel@tonic-gate 		do {
4377c478bd9Sstevel@tonic-gate 			(void) memset(gbuf, '\0', sizeof (gbuf));
4387c478bd9Sstevel@tonic-gate 			(void) strlcpy(gbuf, cp, sizeof (gbuf));
4397c478bd9Sstevel@tonic-gate 			if (!do_getset(fd, cmd, gbuf, sizeof (gbuf)))
4407c478bd9Sstevel@tonic-gate 				return (EXIT_FAILURE);
4417c478bd9Sstevel@tonic-gate 			if (cp = *++argv)
4427c478bd9Sstevel@tonic-gate 				(void) putchar('\n');
4437c478bd9Sstevel@tonic-gate 		} while (cp);
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	(void) close(fd);
4477c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate static void
name_print(char * buf)4517c478bd9Sstevel@tonic-gate name_print(char *buf)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	char *cp, *rwtag;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	for (cp = buf; cp[0]; ) {
4567c478bd9Sstevel@tonic-gate 		for (rwtag = cp; !isspace(*rwtag); rwtag++)
4577c478bd9Sstevel@tonic-gate 			;
4587c478bd9Sstevel@tonic-gate 		*rwtag++ = '\0';
4597c478bd9Sstevel@tonic-gate 		while (isspace(*rwtag))
4607c478bd9Sstevel@tonic-gate 			rwtag++;
4617c478bd9Sstevel@tonic-gate 		(void) printf("%-30s%s\n", cp, rwtag);
4627c478bd9Sstevel@tonic-gate 		for (cp = rwtag; *cp++; )
4637c478bd9Sstevel@tonic-gate 			;
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate  * This function is vile, but it's better here than in the kernel.
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate static boolean_t
is_obsolete(const char * param)4717c478bd9Sstevel@tonic-gate is_obsolete(const char *param)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	if (strcmp(param, "ip_enable_group_ifs") == 0 ||
4747c478bd9Sstevel@tonic-gate 	    strcmp(param, "ifgrp_status") == 0) {
4757c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "The \"%s\" tunable has been superseded "
4767c478bd9Sstevel@tonic-gate 		    "by IP Multipathing.\nPlease see the IP Network "
4777c478bd9Sstevel@tonic-gate 		    "Multipathing Administration Guide for details.\n", param);
4787c478bd9Sstevel@tonic-gate 		return (B_TRUE);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 	return (B_FALSE);
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate static boolean_t
do_getset(int fd,int cmd,char * buf,int buf_len)4847c478bd9Sstevel@tonic-gate do_getset(int fd, int cmd, char *buf, int buf_len)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate 	char	*cp;
4877c478bd9Sstevel@tonic-gate 	struct strioctl	stri;
4887c478bd9Sstevel@tonic-gate 	boolean_t	is_name_get;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (is_obsolete(buf))
4917c478bd9Sstevel@tonic-gate 		return (B_TRUE);
4927c478bd9Sstevel@tonic-gate 
4936e91bba0SGirish Moodalbail 	/*
4946e91bba0SGirish Moodalbail 	 * See if libipadm can handle this request, i.e., properties on
4956e91bba0SGirish Moodalbail 	 * following modules arp, ip, ipv4, ipv6, tcp, udp and sctp
4966e91bba0SGirish Moodalbail 	 */
4976e91bba0SGirish Moodalbail 	if (do_ipadm_getset(cmd, buf, buf_len))
4986e91bba0SGirish Moodalbail 		return (B_TRUE);
4996e91bba0SGirish Moodalbail 
5007c478bd9Sstevel@tonic-gate 	stri.ic_cmd = cmd;
5017c478bd9Sstevel@tonic-gate 	stri.ic_timout = 0;
5027c478bd9Sstevel@tonic-gate 	stri.ic_len = buf_len;
5037c478bd9Sstevel@tonic-gate 	stri.ic_dp = buf;
5047c478bd9Sstevel@tonic-gate 	is_name_get = stri.ic_cmd == ND_GET && buf[0] == '?' && buf[1] == '\0';
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &stri) == -1) {
5077c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
5087c478bd9Sstevel@tonic-gate 			(void) printf("name is non-existent for this module\n"
5097c478bd9Sstevel@tonic-gate 			    "for a list of valid names, use name '?'\n");
5107c478bd9Sstevel@tonic-gate 		else
5117c478bd9Sstevel@tonic-gate 			(void) printf("operation failed: %s\n", errmsg(errno));
5127c478bd9Sstevel@tonic-gate 		return (B_FALSE);
5137c478bd9Sstevel@tonic-gate 	}
5147c478bd9Sstevel@tonic-gate 	if (is_name_get)
5157c478bd9Sstevel@tonic-gate 		name_print(buf);
5167c478bd9Sstevel@tonic-gate 	else if (stri.ic_cmd == ND_GET) {
5177c478bd9Sstevel@tonic-gate 		for (cp = buf; *cp != '\0'; cp += strlen(cp) + 1)
5187c478bd9Sstevel@tonic-gate 			(void) puts(cp);
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
5217c478bd9Sstevel@tonic-gate 	return (B_TRUE);
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate static int
get_value(char * msg,char * buf,int buf_len)5257c478bd9Sstevel@tonic-gate get_value(char *msg, char *buf, int buf_len)
5267c478bd9Sstevel@tonic-gate {
5277c478bd9Sstevel@tonic-gate 	int	len;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	(void) printf("%s", msg);
5307c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	buf[buf_len-1] = '\0';
5337c478bd9Sstevel@tonic-gate 	if (fgets(buf, buf_len-1, stdin) == NULL)
5347c478bd9Sstevel@tonic-gate 		exit(EXIT_SUCCESS);
5357c478bd9Sstevel@tonic-gate 	len = strlen(buf);
5367c478bd9Sstevel@tonic-gate 	if (buf[len-1] == '\n')
5377c478bd9Sstevel@tonic-gate 		buf[len - 1] = '\0';
5387c478bd9Sstevel@tonic-gate 	else
5397c478bd9Sstevel@tonic-gate 		len++;
5407c478bd9Sstevel@tonic-gate 	return (len);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate static void
getset_interactive(int fd)5447c478bd9Sstevel@tonic-gate getset_interactive(int fd)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	int	cmd;
5477c478bd9Sstevel@tonic-gate 	char	*cp;
5487c478bd9Sstevel@tonic-gate 	int	len, buf_len;
5497c478bd9Sstevel@tonic-gate 	char	len_buf[10];
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	for (;;) {
5527c478bd9Sstevel@tonic-gate 		(void) memset(gbuf, '\0', sizeof (gbuf));
5537c478bd9Sstevel@tonic-gate 		len = get_value("name to get/set ? ", gbuf, sizeof (gbuf));
5547c478bd9Sstevel@tonic-gate 		if (len == 1 || (gbuf[0] == 'q' && gbuf[1] == '\0'))
5557c478bd9Sstevel@tonic-gate 			return;
5567c478bd9Sstevel@tonic-gate 		for (cp = gbuf; cp < &gbuf[len]; cp++) {
5577c478bd9Sstevel@tonic-gate 			if (isspace(*cp))
5587c478bd9Sstevel@tonic-gate 				*cp = '\0';
5597c478bd9Sstevel@tonic-gate 		}
5607c478bd9Sstevel@tonic-gate 		cmd = ND_GET;
5617c478bd9Sstevel@tonic-gate 		if (gbuf[0] != '?' &&
5627c478bd9Sstevel@tonic-gate 		    get_value("value ? ", &gbuf[len], sizeof (gbuf) - len) > 1)
5637c478bd9Sstevel@tonic-gate 			cmd = ND_SET;
5647c478bd9Sstevel@tonic-gate 		if (cmd == ND_GET && gbuf[0] != '?' &&
5657c478bd9Sstevel@tonic-gate 		    get_value("length ? ", len_buf, sizeof (len_buf)) > 1) {
5667c478bd9Sstevel@tonic-gate 			if (!isdigit(len_buf[0])) {
5677c478bd9Sstevel@tonic-gate 				(void) printf("invalid length\n");
5687c478bd9Sstevel@tonic-gate 				continue;
5697c478bd9Sstevel@tonic-gate 			}
5707c478bd9Sstevel@tonic-gate 			buf_len = atoi(len_buf);
5717c478bd9Sstevel@tonic-gate 		} else
5727c478bd9Sstevel@tonic-gate 			buf_len = sizeof (gbuf);
5737c478bd9Sstevel@tonic-gate 		(void) do_getset(fd, cmd, gbuf, buf_len);
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate static void
printe(boolean_t print_errno,char * fmt,...)5787c478bd9Sstevel@tonic-gate printe(boolean_t print_errno, char *fmt, ...)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	va_list	ap;
5817c478bd9Sstevel@tonic-gate 	int error = errno;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
5847c478bd9Sstevel@tonic-gate 	(void) printf("*ERROR* ");
5857c478bd9Sstevel@tonic-gate 	(void) vprintf(fmt, ap);
5867c478bd9Sstevel@tonic-gate 	va_end(ap);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	if (print_errno)
5897c478bd9Sstevel@tonic-gate 		(void) printf(": %s\n", errmsg(error));
5907c478bd9Sstevel@tonic-gate 	else
5917c478bd9Sstevel@tonic-gate 		(void) printf("\n");
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate static int
open_device()595a924b63fSVasumathi Sundaram - Sun Microsystems open_device()
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	int	fd, len;
5986e91bba0SGirish Moodalbail 	char	*mod;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	for (;;) {
6016e91bba0SGirish Moodalbail 		len = get_value("module to query ? ", modpath,
6026e91bba0SGirish Moodalbail 		    sizeof (modpath));
6037c478bd9Sstevel@tonic-gate 		if (len <= 1 ||
6046e91bba0SGirish Moodalbail 		    (len == 2 && (modpath[0] == 'q' || modpath[0] == 'Q')))
6057c478bd9Sstevel@tonic-gate 			return (-1);
6067c478bd9Sstevel@tonic-gate 
6076e91bba0SGirish Moodalbail 		mod = strrchr(modpath, '/');
6086e91bba0SGirish Moodalbail 		if (mod != NULL)
6096e91bba0SGirish Moodalbail 			mod++;
6106e91bba0SGirish Moodalbail 		else
6116e91bba0SGirish Moodalbail 			mod = modpath;
6126e91bba0SGirish Moodalbail 		if (ndd_str2proto(mod) == MOD_PROTO_NONE) {
6136e91bba0SGirish Moodalbail 			if ((fd = open(modpath, O_RDWR)) == -1) {
6146e91bba0SGirish Moodalbail 				printe(B_TRUE, "open of %s failed", modpath);
6156e91bba0SGirish Moodalbail 				continue;
6166e91bba0SGirish Moodalbail 			}
6176e91bba0SGirish Moodalbail 		} else {
6186e91bba0SGirish Moodalbail 			return (0);
6197c478bd9Sstevel@tonic-gate 		}
6207c478bd9Sstevel@tonic-gate 
6216e91bba0SGirish Moodalbail 		gldv3_warning(modpath);
6224045d941Ssowmini 
6237c478bd9Sstevel@tonic-gate 		if (isastream(fd))
6247c478bd9Sstevel@tonic-gate 			return (fd);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 		(void) close(fd);
6276e91bba0SGirish Moodalbail 		printe(B_FALSE, "%s is not a streams device", modpath);
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate static void
fatal(char * fmt,...)6327c478bd9Sstevel@tonic-gate fatal(char *fmt, ...)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 	va_list	ap;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
6377c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
6387c478bd9Sstevel@tonic-gate 	va_end(ap);
6397c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate static char *
errmsg(int error)6457c478bd9Sstevel@tonic-gate errmsg(int error)
6467c478bd9Sstevel@tonic-gate {
6477c478bd9Sstevel@tonic-gate 	char *msg = strerror(error);
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	return (msg != NULL ? msg : "unknown error");
6507c478bd9Sstevel@tonic-gate }
651