xref: /illumos-gate/usr/src/uts/common/inet/tunables.c (revision f1e9465b)
16e91bba0SGirish Moodalbail /*
26e91bba0SGirish Moodalbail  * CDDL HEADER START
36e91bba0SGirish Moodalbail  *
46e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
56e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
66e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
76e91bba0SGirish Moodalbail  *
86e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
106e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
116e91bba0SGirish Moodalbail  * and limitations under the License.
126e91bba0SGirish Moodalbail  *
136e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
146e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
166e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
176e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
186e91bba0SGirish Moodalbail  *
196e91bba0SGirish Moodalbail  * CDDL HEADER END
206e91bba0SGirish Moodalbail  */
216e91bba0SGirish Moodalbail /*
22*f1e9465bSSowmini Varadhan  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23*f1e9465bSSowmini Varadhan  * Copyright (c) 1990 Mentat Inc.
246e91bba0SGirish Moodalbail  */
256e91bba0SGirish Moodalbail 
266e91bba0SGirish Moodalbail #include <inet/tunables.h>
276e91bba0SGirish Moodalbail #include <sys/md5.h>
286e91bba0SGirish Moodalbail #include <inet/common.h>
296e91bba0SGirish Moodalbail #include <inet/ip.h>
306e91bba0SGirish Moodalbail #include <inet/ip6.h>
316e91bba0SGirish Moodalbail #include <netinet/icmp6.h>
326e91bba0SGirish Moodalbail #include <inet/ip_stack.h>
336e91bba0SGirish Moodalbail #include <inet/rawip_impl.h>
346e91bba0SGirish Moodalbail #include <inet/tcp_stack.h>
356e91bba0SGirish Moodalbail #include <inet/tcp_impl.h>
366e91bba0SGirish Moodalbail #include <inet/udp_impl.h>
376e91bba0SGirish Moodalbail #include <inet/sctp/sctp_stack.h>
386e91bba0SGirish Moodalbail #include <inet/sctp/sctp_impl.h>
396e91bba0SGirish Moodalbail #include <inet/tunables.h>
406e91bba0SGirish Moodalbail 
416e91bba0SGirish Moodalbail static int
426e91bba0SGirish Moodalbail prop_perm2const(mod_prop_info_t *pinfo)
436e91bba0SGirish Moodalbail {
446e91bba0SGirish Moodalbail 	if (pinfo->mpi_setf == NULL)
456e91bba0SGirish Moodalbail 		return (MOD_PROP_PERM_READ);
466e91bba0SGirish Moodalbail 	if (pinfo->mpi_getf == NULL)
476e91bba0SGirish Moodalbail 		return (MOD_PROP_PERM_WRITE);
486e91bba0SGirish Moodalbail 	return (MOD_PROP_PERM_RW);
496e91bba0SGirish Moodalbail }
506e91bba0SGirish Moodalbail 
516e91bba0SGirish Moodalbail /*
526e91bba0SGirish Moodalbail  * Modifies the value of the property to default value or to the `pval'
536e91bba0SGirish Moodalbail  * specified by the user.
546e91bba0SGirish Moodalbail  */
556e91bba0SGirish Moodalbail /* ARGSUSED */
566e91bba0SGirish Moodalbail int
576e91bba0SGirish Moodalbail mod_set_boolean(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
586e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
596e91bba0SGirish Moodalbail {
606e91bba0SGirish Moodalbail 	char 		*end;
616e91bba0SGirish Moodalbail 	unsigned long 	new_value;
626e91bba0SGirish Moodalbail 
636e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
646e91bba0SGirish Moodalbail 		pinfo->prop_cur_bval = pinfo->prop_def_bval;
656e91bba0SGirish Moodalbail 		return (0);
666e91bba0SGirish Moodalbail 	}
676e91bba0SGirish Moodalbail 
686e91bba0SGirish Moodalbail 	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
696e91bba0SGirish Moodalbail 		return (EINVAL);
706e91bba0SGirish Moodalbail 	if (new_value != B_TRUE && new_value != B_FALSE)
716e91bba0SGirish Moodalbail 		return (EINVAL);
726e91bba0SGirish Moodalbail 	pinfo->prop_cur_bval = new_value;
736e91bba0SGirish Moodalbail 	return (0);
746e91bba0SGirish Moodalbail }
756e91bba0SGirish Moodalbail 
766e91bba0SGirish Moodalbail /*
776e91bba0SGirish Moodalbail  * Retrieves property permission, default value, current value or possible
786e91bba0SGirish Moodalbail  * values for those properties whose value type is boolean_t.
796e91bba0SGirish Moodalbail  */
806e91bba0SGirish Moodalbail /* ARGSUSED */
816e91bba0SGirish Moodalbail int
826e91bba0SGirish Moodalbail mod_get_boolean(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
836e91bba0SGirish Moodalbail     void *pval, uint_t psize, uint_t flags)
846e91bba0SGirish Moodalbail {
856e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
866e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
876e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
886e91bba0SGirish Moodalbail 	size_t		nbytes;
896e91bba0SGirish Moodalbail 
906e91bba0SGirish Moodalbail 	bzero(pval, psize);
916e91bba0SGirish Moodalbail 	if (get_perm)
926e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
936e91bba0SGirish Moodalbail 	else if (get_range)
946e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE);
956e91bba0SGirish Moodalbail 	else if (get_def)
966e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval);
976e91bba0SGirish Moodalbail 	else
986e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval);
996e91bba0SGirish Moodalbail 	if (nbytes >= psize)
1006e91bba0SGirish Moodalbail 		return (ENOBUFS);
1016e91bba0SGirish Moodalbail 	return (0);
1026e91bba0SGirish Moodalbail }
1036e91bba0SGirish Moodalbail 
1046e91bba0SGirish Moodalbail int
105*f1e9465bSSowmini Varadhan mod_uint32_value(const void *pval, mod_prop_info_t *pinfo, uint_t flags,
106*f1e9465bSSowmini Varadhan     ulong_t *new_value)
1076e91bba0SGirish Moodalbail {
1086e91bba0SGirish Moodalbail 	char 		*end;
1096e91bba0SGirish Moodalbail 
1106e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
111*f1e9465bSSowmini Varadhan 		*new_value = pinfo->prop_def_uval;
1126e91bba0SGirish Moodalbail 		return (0);
1136e91bba0SGirish Moodalbail 	}
1146e91bba0SGirish Moodalbail 
115*f1e9465bSSowmini Varadhan 	if (ddi_strtoul(pval, &end, 10, (ulong_t *)new_value) != 0 ||
116*f1e9465bSSowmini Varadhan 	    *end != '\0')
1176e91bba0SGirish Moodalbail 		return (EINVAL);
118*f1e9465bSSowmini Varadhan 	if (*new_value < pinfo->prop_min_uval ||
119*f1e9465bSSowmini Varadhan 	    *new_value > pinfo->prop_max_uval) {
1206e91bba0SGirish Moodalbail 		return (ERANGE);
1216e91bba0SGirish Moodalbail 	}
122*f1e9465bSSowmini Varadhan 	return (0);
123*f1e9465bSSowmini Varadhan }
124*f1e9465bSSowmini Varadhan 
125*f1e9465bSSowmini Varadhan /*
126*f1e9465bSSowmini Varadhan  * Modifies the value of the property to default value or to the `pval'
127*f1e9465bSSowmini Varadhan  * specified by the user.
128*f1e9465bSSowmini Varadhan  */
129*f1e9465bSSowmini Varadhan /* ARGSUSED */
130*f1e9465bSSowmini Varadhan int
131*f1e9465bSSowmini Varadhan mod_set_uint32(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
132*f1e9465bSSowmini Varadhan     const char *ifname, const void *pval, uint_t flags)
133*f1e9465bSSowmini Varadhan {
134*f1e9465bSSowmini Varadhan 	unsigned long	new_value;
135*f1e9465bSSowmini Varadhan 	int		err;
136*f1e9465bSSowmini Varadhan 
137*f1e9465bSSowmini Varadhan 	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
138*f1e9465bSSowmini Varadhan 		return (err);
1396e91bba0SGirish Moodalbail 	pinfo->prop_cur_uval = (uint32_t)new_value;
1406e91bba0SGirish Moodalbail 	return (0);
1416e91bba0SGirish Moodalbail }
1426e91bba0SGirish Moodalbail 
1436e91bba0SGirish Moodalbail /*
1446e91bba0SGirish Moodalbail  * Rounds up the value to make it multiple of 8.
1456e91bba0SGirish Moodalbail  */
1466e91bba0SGirish Moodalbail /* ARGSUSED */
1476e91bba0SGirish Moodalbail int
1486e91bba0SGirish Moodalbail mod_set_aligned(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
1496e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
1506e91bba0SGirish Moodalbail {
1516e91bba0SGirish Moodalbail 	int	err;
1526e91bba0SGirish Moodalbail 
1536e91bba0SGirish Moodalbail 	if ((err = mod_set_uint32(cbarg, cr, pinfo, ifname, pval, flags)) != 0)
1546e91bba0SGirish Moodalbail 		return (err);
1556e91bba0SGirish Moodalbail 
1566e91bba0SGirish Moodalbail 	/* if required, align the value to multiple of 8 */
1576e91bba0SGirish Moodalbail 	if (pinfo->prop_cur_uval & 0x7) {
1586e91bba0SGirish Moodalbail 		pinfo->prop_cur_uval &= ~0x7;
1596e91bba0SGirish Moodalbail 		pinfo->prop_cur_uval += 0x8;
1606e91bba0SGirish Moodalbail 	}
1616e91bba0SGirish Moodalbail 
1626e91bba0SGirish Moodalbail 	return (0);
1636e91bba0SGirish Moodalbail }
1646e91bba0SGirish Moodalbail 
1656e91bba0SGirish Moodalbail /*
1666e91bba0SGirish Moodalbail  * Retrieves property permission, default value, current value or possible
1676e91bba0SGirish Moodalbail  * values for those properties whose value type is uint32_t.
1686e91bba0SGirish Moodalbail  */
1696e91bba0SGirish Moodalbail /* ARGSUSED */
1706e91bba0SGirish Moodalbail int
1716e91bba0SGirish Moodalbail mod_get_uint32(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
1726e91bba0SGirish Moodalbail     void *pval, uint_t psize, uint_t flags)
1736e91bba0SGirish Moodalbail {
1746e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
1756e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
1766e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
1776e91bba0SGirish Moodalbail 	size_t		nbytes;
1786e91bba0SGirish Moodalbail 
1796e91bba0SGirish Moodalbail 	bzero(pval, psize);
1806e91bba0SGirish Moodalbail 	if (get_perm)
1816e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
1826e91bba0SGirish Moodalbail 	else if (get_range)
1836e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u-%u",
1846e91bba0SGirish Moodalbail 		    pinfo->prop_min_uval, pinfo->prop_max_uval);
1856e91bba0SGirish Moodalbail 	else if (get_def)
1866e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
1876e91bba0SGirish Moodalbail 	else
1886e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval);
1896e91bba0SGirish Moodalbail 	if (nbytes >= psize)
1906e91bba0SGirish Moodalbail 		return (ENOBUFS);
1916e91bba0SGirish Moodalbail 	return (0);
1926e91bba0SGirish Moodalbail }
1936e91bba0SGirish Moodalbail 
1946e91bba0SGirish Moodalbail /*
1956e91bba0SGirish Moodalbail  * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
1966e91bba0SGirish Moodalbail  * backward compatibility with /sbin/ndd.
1976e91bba0SGirish Moodalbail  */
1986e91bba0SGirish Moodalbail /* ARGSUSED */
1996e91bba0SGirish Moodalbail int
2006e91bba0SGirish Moodalbail mod_get_allprop(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
2016e91bba0SGirish Moodalbail     void *val, uint_t psize, uint_t flags)
2026e91bba0SGirish Moodalbail {
2036e91bba0SGirish Moodalbail 	char		*pval = val;
2046e91bba0SGirish Moodalbail 	mod_prop_info_t	*ptbl, *prop;
2056e91bba0SGirish Moodalbail 	ip_stack_t	*ipst;
2066e91bba0SGirish Moodalbail 	tcp_stack_t	*tcps;
2076e91bba0SGirish Moodalbail 	sctp_stack_t	*sctps;
2086e91bba0SGirish Moodalbail 	udp_stack_t	*us;
2096e91bba0SGirish Moodalbail 	icmp_stack_t	*is;
2106e91bba0SGirish Moodalbail 	uint_t		size;
2116e91bba0SGirish Moodalbail 	size_t		nbytes = 0, tbytes = 0;
2126e91bba0SGirish Moodalbail 
2136e91bba0SGirish Moodalbail 	bzero(pval, psize);
2146e91bba0SGirish Moodalbail 	size = psize;
2156e91bba0SGirish Moodalbail 
2166e91bba0SGirish Moodalbail 	switch (pinfo->mpi_proto) {
2176e91bba0SGirish Moodalbail 	case MOD_PROTO_IP:
2186e91bba0SGirish Moodalbail 	case MOD_PROTO_IPV4:
2196e91bba0SGirish Moodalbail 	case MOD_PROTO_IPV6:
2206e91bba0SGirish Moodalbail 		ipst = (ip_stack_t *)cbarg;
2216e91bba0SGirish Moodalbail 		ptbl = ipst->ips_propinfo_tbl;
2226e91bba0SGirish Moodalbail 		break;
2236e91bba0SGirish Moodalbail 	case MOD_PROTO_RAWIP:
2246e91bba0SGirish Moodalbail 		is = (icmp_stack_t *)cbarg;
2256e91bba0SGirish Moodalbail 		ptbl = is->is_propinfo_tbl;
2266e91bba0SGirish Moodalbail 		break;
2276e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
2286e91bba0SGirish Moodalbail 		tcps = (tcp_stack_t *)cbarg;
2296e91bba0SGirish Moodalbail 		ptbl = tcps->tcps_propinfo_tbl;
2306e91bba0SGirish Moodalbail 		break;
2316e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
2326e91bba0SGirish Moodalbail 		us = (udp_stack_t *)cbarg;
2336e91bba0SGirish Moodalbail 		ptbl = us->us_propinfo_tbl;
2346e91bba0SGirish Moodalbail 		break;
2356e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
2366e91bba0SGirish Moodalbail 		sctps = (sctp_stack_t *)cbarg;
2376e91bba0SGirish Moodalbail 		ptbl = sctps->sctps_propinfo_tbl;
2386e91bba0SGirish Moodalbail 		break;
2396e91bba0SGirish Moodalbail 	default:
2406e91bba0SGirish Moodalbail 		return (EINVAL);
2416e91bba0SGirish Moodalbail 	}
2426e91bba0SGirish Moodalbail 
2436e91bba0SGirish Moodalbail 	for (prop = ptbl; prop->mpi_name != NULL; prop++) {
2446e91bba0SGirish Moodalbail 		if (prop->mpi_name[0] == '\0' ||
2456e91bba0SGirish Moodalbail 		    strcmp(prop->mpi_name, "mtu") == 0 ||
2466e91bba0SGirish Moodalbail 		    strcmp(prop->mpi_name, "?") == 0)
2476e91bba0SGirish Moodalbail 			continue;
2486e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name,
2496e91bba0SGirish Moodalbail 		    prop->mpi_proto, prop_perm2const(prop));
2506e91bba0SGirish Moodalbail 		size -= nbytes + 1;
2516e91bba0SGirish Moodalbail 		pval += nbytes + 1;
2526e91bba0SGirish Moodalbail 		tbytes += nbytes + 1;
2536e91bba0SGirish Moodalbail 		if (tbytes >= psize) {
2546e91bba0SGirish Moodalbail 			/* Buffer overflow, stop copying information */
2556e91bba0SGirish Moodalbail 			return (ENOBUFS);
2566e91bba0SGirish Moodalbail 		}
2576e91bba0SGirish Moodalbail 	}
2586e91bba0SGirish Moodalbail 	return (0);
2596e91bba0SGirish Moodalbail }
2606e91bba0SGirish Moodalbail 
2616e91bba0SGirish Moodalbail /*
2626e91bba0SGirish Moodalbail  * Hold a lock while changing *_epriv_ports to prevent multiple
2636e91bba0SGirish Moodalbail  * threads from changing it at the same time.
2646e91bba0SGirish Moodalbail  */
2656e91bba0SGirish Moodalbail /* ARGSUSED */
2666e91bba0SGirish Moodalbail int
2676e91bba0SGirish Moodalbail mod_set_extra_privports(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
2686e91bba0SGirish Moodalbail     const char *ifname, const void* val, uint_t flags)
2696e91bba0SGirish Moodalbail {
2706e91bba0SGirish Moodalbail 	uint_t		proto = pinfo->mpi_proto;
2716e91bba0SGirish Moodalbail 	tcp_stack_t	*tcps;
2726e91bba0SGirish Moodalbail 	sctp_stack_t	*sctps;
2736e91bba0SGirish Moodalbail 	udp_stack_t	*us;
2746e91bba0SGirish Moodalbail 	unsigned long	new_value;
2756e91bba0SGirish Moodalbail 	char		*end;
2766e91bba0SGirish Moodalbail 	kmutex_t	*lock;
2776e91bba0SGirish Moodalbail 	uint_t		i, nports;
2786e91bba0SGirish Moodalbail 	in_port_t	*ports;
2796e91bba0SGirish Moodalbail 	boolean_t	def = (flags & MOD_PROP_DEFAULT);
2806e91bba0SGirish Moodalbail 	const char	*pval = val;
2816e91bba0SGirish Moodalbail 
2826e91bba0SGirish Moodalbail 	if (!def) {
2836e91bba0SGirish Moodalbail 		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
2846e91bba0SGirish Moodalbail 		    *end != '\0') {
2856e91bba0SGirish Moodalbail 			return (EINVAL);
2866e91bba0SGirish Moodalbail 		}
2876e91bba0SGirish Moodalbail 
2886e91bba0SGirish Moodalbail 		if (new_value < pinfo->prop_min_uval ||
2896e91bba0SGirish Moodalbail 		    new_value > pinfo->prop_max_uval) {
2906e91bba0SGirish Moodalbail 			return (ERANGE);
2916e91bba0SGirish Moodalbail 		}
2926e91bba0SGirish Moodalbail 	}
2936e91bba0SGirish Moodalbail 
2946e91bba0SGirish Moodalbail 	switch (proto) {
2956e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
2966e91bba0SGirish Moodalbail 		tcps = (tcp_stack_t *)cbarg;
2976e91bba0SGirish Moodalbail 		lock = &tcps->tcps_epriv_port_lock;
2986e91bba0SGirish Moodalbail 		ports = tcps->tcps_g_epriv_ports;
2996e91bba0SGirish Moodalbail 		nports = tcps->tcps_g_num_epriv_ports;
3006e91bba0SGirish Moodalbail 		break;
3016e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
3026e91bba0SGirish Moodalbail 		us = (udp_stack_t *)cbarg;
3036e91bba0SGirish Moodalbail 		lock = &us->us_epriv_port_lock;
3046e91bba0SGirish Moodalbail 		ports = us->us_epriv_ports;
3056e91bba0SGirish Moodalbail 		nports = us->us_num_epriv_ports;
3066e91bba0SGirish Moodalbail 		break;
3076e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
3086e91bba0SGirish Moodalbail 		sctps = (sctp_stack_t *)cbarg;
3096e91bba0SGirish Moodalbail 		lock = &sctps->sctps_epriv_port_lock;
3106e91bba0SGirish Moodalbail 		ports = sctps->sctps_g_epriv_ports;
3116e91bba0SGirish Moodalbail 		nports = sctps->sctps_g_num_epriv_ports;
3126e91bba0SGirish Moodalbail 		break;
3136e91bba0SGirish Moodalbail 	default:
3146e91bba0SGirish Moodalbail 		return (ENOTSUP);
3156e91bba0SGirish Moodalbail 	}
3166e91bba0SGirish Moodalbail 
3176e91bba0SGirish Moodalbail 	mutex_enter(lock);
3186e91bba0SGirish Moodalbail 
3196e91bba0SGirish Moodalbail 	/* if MOD_PROP_DEFAULT is set then reset the ports list to default */
3206e91bba0SGirish Moodalbail 	if (def) {
3216e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++)
3226e91bba0SGirish Moodalbail 			ports[i] = 0;
3236e91bba0SGirish Moodalbail 		ports[0] = ULP_DEF_EPRIV_PORT1;
3246e91bba0SGirish Moodalbail 		ports[1] = ULP_DEF_EPRIV_PORT2;
3256e91bba0SGirish Moodalbail 		mutex_exit(lock);
3266e91bba0SGirish Moodalbail 		return (0);
3276e91bba0SGirish Moodalbail 	}
3286e91bba0SGirish Moodalbail 
3296e91bba0SGirish Moodalbail 	/* Check if the value is already in the list */
3306e91bba0SGirish Moodalbail 	for (i = 0; i < nports; i++) {
3316e91bba0SGirish Moodalbail 		if (new_value == ports[i])
3326e91bba0SGirish Moodalbail 			break;
3336e91bba0SGirish Moodalbail 	}
3346e91bba0SGirish Moodalbail 
3356e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_REMOVE) {
3366e91bba0SGirish Moodalbail 		if (i == nports) {
3376e91bba0SGirish Moodalbail 			mutex_exit(lock);
3386e91bba0SGirish Moodalbail 			return (ESRCH);
3396e91bba0SGirish Moodalbail 		}
3406e91bba0SGirish Moodalbail 		/* Clear the value */
3416e91bba0SGirish Moodalbail 		ports[i] = 0;
3426e91bba0SGirish Moodalbail 	} else if (flags & MOD_PROP_APPEND) {
3436e91bba0SGirish Moodalbail 		if (i != nports) {
3446e91bba0SGirish Moodalbail 			mutex_exit(lock);
3456e91bba0SGirish Moodalbail 			return (EEXIST);
3466e91bba0SGirish Moodalbail 		}
3476e91bba0SGirish Moodalbail 
3486e91bba0SGirish Moodalbail 		/* Find an empty slot */
3496e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++) {
3506e91bba0SGirish Moodalbail 			if (ports[i] == 0)
3516e91bba0SGirish Moodalbail 				break;
3526e91bba0SGirish Moodalbail 		}
3536e91bba0SGirish Moodalbail 		if (i == nports) {
3546e91bba0SGirish Moodalbail 			mutex_exit(lock);
3556e91bba0SGirish Moodalbail 			return (EOVERFLOW);
3566e91bba0SGirish Moodalbail 		}
3576e91bba0SGirish Moodalbail 		/* Set the new value */
3586e91bba0SGirish Moodalbail 		ports[i] = (in_port_t)new_value;
3596e91bba0SGirish Moodalbail 	} else {
3606e91bba0SGirish Moodalbail 		/*
3616e91bba0SGirish Moodalbail 		 * If the user used 'assignment' modifier.
3626e91bba0SGirish Moodalbail 		 * For eg:
3636e91bba0SGirish Moodalbail 		 * 	# ipadm set-prop -p extra_priv_ports=3001 tcp
3646e91bba0SGirish Moodalbail 		 *
3656e91bba0SGirish Moodalbail 		 * We clear all the ports and then just add 3001.
3666e91bba0SGirish Moodalbail 		 */
3676e91bba0SGirish Moodalbail 		ASSERT(flags == MOD_PROP_ACTIVE);
3686e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++)
3696e91bba0SGirish Moodalbail 			ports[i] = 0;
3706e91bba0SGirish Moodalbail 		ports[0] = (in_port_t)new_value;
3716e91bba0SGirish Moodalbail 	}
3726e91bba0SGirish Moodalbail 
3736e91bba0SGirish Moodalbail 	mutex_exit(lock);
3746e91bba0SGirish Moodalbail 	return (0);
3756e91bba0SGirish Moodalbail }
3766e91bba0SGirish Moodalbail 
3776e91bba0SGirish Moodalbail /*
3786e91bba0SGirish Moodalbail  * Note: No locks are held when inspecting *_epriv_ports
3796e91bba0SGirish Moodalbail  * but instead the code relies on:
3806e91bba0SGirish Moodalbail  * - the fact that the address of the array and its size never changes
3816e91bba0SGirish Moodalbail  * - the atomic assignment of the elements of the array
3826e91bba0SGirish Moodalbail  */
3836e91bba0SGirish Moodalbail /* ARGSUSED */
3846e91bba0SGirish Moodalbail int
3856e91bba0SGirish Moodalbail mod_get_extra_privports(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
3866e91bba0SGirish Moodalbail     void *val, uint_t psize, uint_t flags)
3876e91bba0SGirish Moodalbail {
3886e91bba0SGirish Moodalbail 	uint_t		proto = pinfo->mpi_proto;
3896e91bba0SGirish Moodalbail 	tcp_stack_t	*tcps;
3906e91bba0SGirish Moodalbail 	sctp_stack_t	*sctps;
3916e91bba0SGirish Moodalbail 	udp_stack_t	*us;
3926e91bba0SGirish Moodalbail 	uint_t		i, nports, size;
3936e91bba0SGirish Moodalbail 	in_port_t	*ports;
3946e91bba0SGirish Moodalbail 	char		*pval = val;
3956e91bba0SGirish Moodalbail 	size_t		nbytes = 0, tbytes = 0;
3966e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
3976e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
3986e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
3996e91bba0SGirish Moodalbail 
4006e91bba0SGirish Moodalbail 	bzero(pval, psize);
4016e91bba0SGirish Moodalbail 	size = psize;
4026e91bba0SGirish Moodalbail 
4036e91bba0SGirish Moodalbail 	if (get_def) {
4046e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1,
4056e91bba0SGirish Moodalbail 		    ULP_DEF_EPRIV_PORT2);
4066e91bba0SGirish Moodalbail 		goto ret;
4076e91bba0SGirish Moodalbail 	} else if (get_perm) {
4086e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
4096e91bba0SGirish Moodalbail 		goto ret;
4106e91bba0SGirish Moodalbail 	}
4116e91bba0SGirish Moodalbail 
4126e91bba0SGirish Moodalbail 	switch (proto) {
4136e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
4146e91bba0SGirish Moodalbail 		tcps = (tcp_stack_t *)cbarg;
4156e91bba0SGirish Moodalbail 		ports = tcps->tcps_g_epriv_ports;
4166e91bba0SGirish Moodalbail 		nports = tcps->tcps_g_num_epriv_ports;
4176e91bba0SGirish Moodalbail 		break;
4186e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
4196e91bba0SGirish Moodalbail 		us = (udp_stack_t *)cbarg;
4206e91bba0SGirish Moodalbail 		ports = us->us_epriv_ports;
4216e91bba0SGirish Moodalbail 		nports = us->us_num_epriv_ports;
4226e91bba0SGirish Moodalbail 		break;
4236e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
4246e91bba0SGirish Moodalbail 		sctps = (sctp_stack_t *)cbarg;
4256e91bba0SGirish Moodalbail 		ports = sctps->sctps_g_epriv_ports;
4266e91bba0SGirish Moodalbail 		nports = sctps->sctps_g_num_epriv_ports;
4276e91bba0SGirish Moodalbail 		break;
4286e91bba0SGirish Moodalbail 	default:
4296e91bba0SGirish Moodalbail 		return (ENOTSUP);
4306e91bba0SGirish Moodalbail 	}
4316e91bba0SGirish Moodalbail 
4326e91bba0SGirish Moodalbail 	if (get_range) {
4336e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
4346e91bba0SGirish Moodalbail 		    pinfo->prop_max_uval);
4356e91bba0SGirish Moodalbail 		goto ret;
4366e91bba0SGirish Moodalbail 	}
4376e91bba0SGirish Moodalbail 
4386e91bba0SGirish Moodalbail 	for (i = 0; i < nports; i++) {
4396e91bba0SGirish Moodalbail 		if (ports[i] != 0) {
4406e91bba0SGirish Moodalbail 			if (psize == size)
4416e91bba0SGirish Moodalbail 				nbytes = snprintf(pval, size, "%u", ports[i]);
4426e91bba0SGirish Moodalbail 			else
4436e91bba0SGirish Moodalbail 				nbytes = snprintf(pval, size, ",%u", ports[i]);
4446e91bba0SGirish Moodalbail 			size -= nbytes;
4456e91bba0SGirish Moodalbail 			pval += nbytes;
4466e91bba0SGirish Moodalbail 			tbytes += nbytes;
4476e91bba0SGirish Moodalbail 			if (tbytes >= psize)
4486e91bba0SGirish Moodalbail 				return (ENOBUFS);
4496e91bba0SGirish Moodalbail 		}
4506e91bba0SGirish Moodalbail 	}
4516e91bba0SGirish Moodalbail 	return (0);
4526e91bba0SGirish Moodalbail ret:
4536e91bba0SGirish Moodalbail 	if (tbytes >= psize)
4546e91bba0SGirish Moodalbail 		return (ENOBUFS);
4556e91bba0SGirish Moodalbail 	return (0);
4566e91bba0SGirish Moodalbail }
457