xref: /illumos-gate/usr/src/uts/common/inet/tunables.c (revision 299625c6)
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 /*
22f1e9465bSSowmini Varadhan  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23f1e9465bSSowmini Varadhan  * Copyright (c) 1990 Mentat Inc.
24*299625c6SSebastien Roy  * Copyright (c) 2013 by Delphix. All rights reserved.
256e91bba0SGirish Moodalbail  */
266e91bba0SGirish Moodalbail 
276e91bba0SGirish Moodalbail #include <inet/tunables.h>
286e91bba0SGirish Moodalbail #include <sys/md5.h>
296e91bba0SGirish Moodalbail #include <inet/common.h>
306e91bba0SGirish Moodalbail #include <inet/ip.h>
316e91bba0SGirish Moodalbail #include <inet/ip6.h>
326e91bba0SGirish Moodalbail #include <netinet/icmp6.h>
336e91bba0SGirish Moodalbail #include <inet/ip_stack.h>
346e91bba0SGirish Moodalbail #include <inet/rawip_impl.h>
356e91bba0SGirish Moodalbail #include <inet/tcp_stack.h>
366e91bba0SGirish Moodalbail #include <inet/tcp_impl.h>
376e91bba0SGirish Moodalbail #include <inet/udp_impl.h>
386e91bba0SGirish Moodalbail #include <inet/sctp/sctp_stack.h>
396e91bba0SGirish Moodalbail #include <inet/sctp/sctp_impl.h>
406e91bba0SGirish Moodalbail #include <inet/tunables.h>
416e91bba0SGirish Moodalbail 
42*299625c6SSebastien Roy mod_prop_info_t *
mod_prop_lookup(mod_prop_info_t ptbl[],const char * prop_name,uint_t proto)43*299625c6SSebastien Roy mod_prop_lookup(mod_prop_info_t ptbl[], const char *prop_name, uint_t proto)
44*299625c6SSebastien Roy {
45*299625c6SSebastien Roy 	mod_prop_info_t *pinfo;
46*299625c6SSebastien Roy 
47*299625c6SSebastien Roy 	/*
48*299625c6SSebastien Roy 	 * Walk the ptbl array looking for a property that has the requested
49*299625c6SSebastien Roy 	 * name and protocol number.  Note that we assume that all protocol
50*299625c6SSebastien Roy 	 * tables are terminated by an entry with a NULL property name.
51*299625c6SSebastien Roy 	 */
52*299625c6SSebastien Roy 	for (pinfo = ptbl; pinfo->mpi_name != NULL; pinfo++) {
53*299625c6SSebastien Roy 		if (strcmp(pinfo->mpi_name, prop_name) == 0 &&
54*299625c6SSebastien Roy 		    pinfo->mpi_proto == proto)
55*299625c6SSebastien Roy 			return (pinfo);
56*299625c6SSebastien Roy 	}
57*299625c6SSebastien Roy 	return (NULL);
58*299625c6SSebastien Roy }
59*299625c6SSebastien Roy 
606e91bba0SGirish Moodalbail static int
prop_perm2const(mod_prop_info_t * pinfo)616e91bba0SGirish Moodalbail prop_perm2const(mod_prop_info_t *pinfo)
626e91bba0SGirish Moodalbail {
636e91bba0SGirish Moodalbail 	if (pinfo->mpi_setf == NULL)
646e91bba0SGirish Moodalbail 		return (MOD_PROP_PERM_READ);
656e91bba0SGirish Moodalbail 	if (pinfo->mpi_getf == NULL)
666e91bba0SGirish Moodalbail 		return (MOD_PROP_PERM_WRITE);
676e91bba0SGirish Moodalbail 	return (MOD_PROP_PERM_RW);
686e91bba0SGirish Moodalbail }
696e91bba0SGirish Moodalbail 
706e91bba0SGirish Moodalbail /*
716e91bba0SGirish Moodalbail  * Modifies the value of the property to default value or to the `pval'
726e91bba0SGirish Moodalbail  * specified by the user.
736e91bba0SGirish Moodalbail  */
746e91bba0SGirish Moodalbail /* ARGSUSED */
756e91bba0SGirish Moodalbail int
mod_set_boolean(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)76*299625c6SSebastien Roy mod_set_boolean(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
776e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
786e91bba0SGirish Moodalbail {
79*299625c6SSebastien Roy 	char		*end;
80*299625c6SSebastien Roy 	unsigned long	new_value;
816e91bba0SGirish Moodalbail 
826e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
836e91bba0SGirish Moodalbail 		pinfo->prop_cur_bval = pinfo->prop_def_bval;
846e91bba0SGirish Moodalbail 		return (0);
856e91bba0SGirish Moodalbail 	}
866e91bba0SGirish Moodalbail 
876e91bba0SGirish Moodalbail 	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
886e91bba0SGirish Moodalbail 		return (EINVAL);
896e91bba0SGirish Moodalbail 	if (new_value != B_TRUE && new_value != B_FALSE)
906e91bba0SGirish Moodalbail 		return (EINVAL);
916e91bba0SGirish Moodalbail 	pinfo->prop_cur_bval = new_value;
926e91bba0SGirish Moodalbail 	return (0);
936e91bba0SGirish Moodalbail }
946e91bba0SGirish Moodalbail 
956e91bba0SGirish Moodalbail /*
966e91bba0SGirish Moodalbail  * Retrieves property permission, default value, current value or possible
976e91bba0SGirish Moodalbail  * values for those properties whose value type is boolean_t.
986e91bba0SGirish Moodalbail  */
996e91bba0SGirish Moodalbail /* ARGSUSED */
1006e91bba0SGirish Moodalbail int
mod_get_boolean(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)101*299625c6SSebastien Roy mod_get_boolean(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
1026e91bba0SGirish Moodalbail     void *pval, uint_t psize, uint_t flags)
1036e91bba0SGirish Moodalbail {
1046e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
1056e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
1066e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
1076e91bba0SGirish Moodalbail 	size_t		nbytes;
1086e91bba0SGirish Moodalbail 
1096e91bba0SGirish Moodalbail 	bzero(pval, psize);
1106e91bba0SGirish Moodalbail 	if (get_perm)
1116e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
1126e91bba0SGirish Moodalbail 	else if (get_range)
1136e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE);
1146e91bba0SGirish Moodalbail 	else if (get_def)
1156e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval);
1166e91bba0SGirish Moodalbail 	else
1176e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval);
1186e91bba0SGirish Moodalbail 	if (nbytes >= psize)
1196e91bba0SGirish Moodalbail 		return (ENOBUFS);
1206e91bba0SGirish Moodalbail 	return (0);
1216e91bba0SGirish Moodalbail }
1226e91bba0SGirish Moodalbail 
1236e91bba0SGirish Moodalbail int
mod_uint32_value(const void * pval,mod_prop_info_t * pinfo,uint_t flags,ulong_t * new_value)124f1e9465bSSowmini Varadhan mod_uint32_value(const void *pval, mod_prop_info_t *pinfo, uint_t flags,
125f1e9465bSSowmini Varadhan     ulong_t *new_value)
1266e91bba0SGirish Moodalbail {
1276e91bba0SGirish Moodalbail 	char 		*end;
1286e91bba0SGirish Moodalbail 
1296e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
130f1e9465bSSowmini Varadhan 		*new_value = pinfo->prop_def_uval;
1316e91bba0SGirish Moodalbail 		return (0);
1326e91bba0SGirish Moodalbail 	}
1336e91bba0SGirish Moodalbail 
134f1e9465bSSowmini Varadhan 	if (ddi_strtoul(pval, &end, 10, (ulong_t *)new_value) != 0 ||
135f1e9465bSSowmini Varadhan 	    *end != '\0')
1366e91bba0SGirish Moodalbail 		return (EINVAL);
137f1e9465bSSowmini Varadhan 	if (*new_value < pinfo->prop_min_uval ||
138f1e9465bSSowmini Varadhan 	    *new_value > pinfo->prop_max_uval) {
1396e91bba0SGirish Moodalbail 		return (ERANGE);
1406e91bba0SGirish Moodalbail 	}
141f1e9465bSSowmini Varadhan 	return (0);
142f1e9465bSSowmini Varadhan }
143f1e9465bSSowmini Varadhan 
144f1e9465bSSowmini Varadhan /*
145f1e9465bSSowmini Varadhan  * Modifies the value of the property to default value or to the `pval'
146f1e9465bSSowmini Varadhan  * specified by the user.
147f1e9465bSSowmini Varadhan  */
148f1e9465bSSowmini Varadhan /* ARGSUSED */
149f1e9465bSSowmini Varadhan int
mod_set_uint32(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)150*299625c6SSebastien Roy mod_set_uint32(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
151f1e9465bSSowmini Varadhan     const char *ifname, const void *pval, uint_t flags)
152f1e9465bSSowmini Varadhan {
153f1e9465bSSowmini Varadhan 	unsigned long	new_value;
154f1e9465bSSowmini Varadhan 	int		err;
155f1e9465bSSowmini Varadhan 
156f1e9465bSSowmini Varadhan 	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
157f1e9465bSSowmini Varadhan 		return (err);
1586e91bba0SGirish Moodalbail 	pinfo->prop_cur_uval = (uint32_t)new_value;
1596e91bba0SGirish Moodalbail 	return (0);
1606e91bba0SGirish Moodalbail }
1616e91bba0SGirish Moodalbail 
1626e91bba0SGirish Moodalbail /*
1636e91bba0SGirish Moodalbail  * Rounds up the value to make it multiple of 8.
1646e91bba0SGirish Moodalbail  */
1656e91bba0SGirish Moodalbail /* ARGSUSED */
1666e91bba0SGirish Moodalbail int
mod_set_aligned(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)167*299625c6SSebastien Roy mod_set_aligned(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
1686e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
1696e91bba0SGirish Moodalbail {
1706e91bba0SGirish Moodalbail 	int	err;
1716e91bba0SGirish Moodalbail 
172*299625c6SSebastien Roy 	if ((err = mod_set_uint32(stack, cr, pinfo, ifname, pval, flags)) != 0)
1736e91bba0SGirish Moodalbail 		return (err);
1746e91bba0SGirish Moodalbail 
1756e91bba0SGirish Moodalbail 	/* if required, align the value to multiple of 8 */
1766e91bba0SGirish Moodalbail 	if (pinfo->prop_cur_uval & 0x7) {
1776e91bba0SGirish Moodalbail 		pinfo->prop_cur_uval &= ~0x7;
1786e91bba0SGirish Moodalbail 		pinfo->prop_cur_uval += 0x8;
1796e91bba0SGirish Moodalbail 	}
1806e91bba0SGirish Moodalbail 
1816e91bba0SGirish Moodalbail 	return (0);
1826e91bba0SGirish Moodalbail }
1836e91bba0SGirish Moodalbail 
1846e91bba0SGirish Moodalbail /*
1856e91bba0SGirish Moodalbail  * Retrieves property permission, default value, current value or possible
1866e91bba0SGirish Moodalbail  * values for those properties whose value type is uint32_t.
1876e91bba0SGirish Moodalbail  */
1886e91bba0SGirish Moodalbail /* ARGSUSED */
1896e91bba0SGirish Moodalbail int
mod_get_uint32(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)190*299625c6SSebastien Roy mod_get_uint32(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
1916e91bba0SGirish Moodalbail     void *pval, uint_t psize, uint_t flags)
1926e91bba0SGirish Moodalbail {
1936e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
1946e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
1956e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
1966e91bba0SGirish Moodalbail 	size_t		nbytes;
1976e91bba0SGirish Moodalbail 
1986e91bba0SGirish Moodalbail 	bzero(pval, psize);
1996e91bba0SGirish Moodalbail 	if (get_perm)
2006e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
2016e91bba0SGirish Moodalbail 	else if (get_range)
2026e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u-%u",
2036e91bba0SGirish Moodalbail 		    pinfo->prop_min_uval, pinfo->prop_max_uval);
2046e91bba0SGirish Moodalbail 	else if (get_def)
2056e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
2066e91bba0SGirish Moodalbail 	else
2076e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval);
2086e91bba0SGirish Moodalbail 	if (nbytes >= psize)
2096e91bba0SGirish Moodalbail 		return (ENOBUFS);
2106e91bba0SGirish Moodalbail 	return (0);
2116e91bba0SGirish Moodalbail }
2126e91bba0SGirish Moodalbail 
213*299625c6SSebastien Roy /*
214*299625c6SSebastien Roy  * The range of the buffer size properties has a static lower bound configured
215*299625c6SSebastien Roy  * in the property info structure of the property itself, and a dynamic upper
216*299625c6SSebastien Roy  * bound.  The upper bound is the current value of the "max_buf" property
217*299625c6SSebastien Roy  * in the appropriate protocol property table.
218*299625c6SSebastien Roy  */
219*299625c6SSebastien Roy static void
mod_get_buf_prop_range(mod_prop_info_t ptbl[],mod_prop_info_t * pinfo,uint32_t * min,uint32_t * max)220*299625c6SSebastien Roy mod_get_buf_prop_range(mod_prop_info_t ptbl[], mod_prop_info_t *pinfo,
221*299625c6SSebastien Roy     uint32_t *min, uint32_t *max)
222*299625c6SSebastien Roy {
223*299625c6SSebastien Roy 	mod_prop_info_t *maxbuf_pinfo = mod_prop_lookup(ptbl, "max_buf",
224*299625c6SSebastien Roy 	    pinfo->mpi_proto);
225*299625c6SSebastien Roy 
226*299625c6SSebastien Roy 	*min = pinfo->prop_min_uval;
227*299625c6SSebastien Roy 	*max = maxbuf_pinfo->prop_cur_uval;
228*299625c6SSebastien Roy }
229*299625c6SSebastien Roy 
230*299625c6SSebastien Roy /*
231*299625c6SSebastien Roy  * Modifies the value of the buffer size property to its default value or to
232*299625c6SSebastien Roy  * the value specified by the user.  This is similar to mod_set_uint32() except
233*299625c6SSebastien Roy  * that the value has a dynamically bounded range (see mod_get_buf_prop_range()
234*299625c6SSebastien Roy  * for details).
235*299625c6SSebastien Roy  */
236*299625c6SSebastien Roy /* ARGSUSED */
237*299625c6SSebastien Roy int
mod_set_buf_prop(mod_prop_info_t ptbl[],netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)238*299625c6SSebastien Roy mod_set_buf_prop(mod_prop_info_t ptbl[], netstack_t *stack, cred_t *cr,
239*299625c6SSebastien Roy     mod_prop_info_t *pinfo, const char *ifname, const void *pval, uint_t flags)
240*299625c6SSebastien Roy {
241*299625c6SSebastien Roy 	unsigned long	new_value;
242*299625c6SSebastien Roy 	char		*end;
243*299625c6SSebastien Roy 	uint32_t	min, max;
244*299625c6SSebastien Roy 
245*299625c6SSebastien Roy 	if (flags & MOD_PROP_DEFAULT) {
246*299625c6SSebastien Roy 		pinfo->prop_cur_uval = pinfo->prop_def_uval;
247*299625c6SSebastien Roy 		return (0);
248*299625c6SSebastien Roy 	}
249*299625c6SSebastien Roy 
250*299625c6SSebastien Roy 	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
251*299625c6SSebastien Roy 		return (EINVAL);
252*299625c6SSebastien Roy 
253*299625c6SSebastien Roy 	mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
254*299625c6SSebastien Roy 	if (new_value < min || new_value > max)
255*299625c6SSebastien Roy 		return (ERANGE);
256*299625c6SSebastien Roy 
257*299625c6SSebastien Roy 	pinfo->prop_cur_uval = new_value;
258*299625c6SSebastien Roy 	return (0);
259*299625c6SSebastien Roy }
260*299625c6SSebastien Roy 
261*299625c6SSebastien Roy /*
262*299625c6SSebastien Roy  * Retrieves property permissions, default value, current value, or possible
263*299625c6SSebastien Roy  * values for buffer size properties.  While these properties have integer
264*299625c6SSebastien Roy  * values, they have a dynamic range (see mod_get_buf_prop_range() for
265*299625c6SSebastien Roy  * details).  As such, they need to be handled differently.
266*299625c6SSebastien Roy  */
267*299625c6SSebastien Roy int
mod_get_buf_prop(mod_prop_info_t ptbl[],netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)268*299625c6SSebastien Roy mod_get_buf_prop(mod_prop_info_t ptbl[], netstack_t *stack,
269*299625c6SSebastien Roy     mod_prop_info_t *pinfo, const char *ifname, void *pval, uint_t psize,
270*299625c6SSebastien Roy     uint_t flags)
271*299625c6SSebastien Roy {
272*299625c6SSebastien Roy 	size_t nbytes;
273*299625c6SSebastien Roy 	uint32_t min, max;
274*299625c6SSebastien Roy 
275*299625c6SSebastien Roy 	if (flags & MOD_PROP_POSSIBLE) {
276*299625c6SSebastien Roy 		mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
277*299625c6SSebastien Roy 		nbytes = snprintf(pval, psize, "%u-%u", min, max);
278*299625c6SSebastien Roy 		return (nbytes < psize ? 0 : ENOBUFS);
279*299625c6SSebastien Roy 	}
280*299625c6SSebastien Roy 	return (mod_get_uint32(stack, pinfo, ifname, pval, psize, flags));
281*299625c6SSebastien Roy }
282*299625c6SSebastien Roy 
2836e91bba0SGirish Moodalbail /*
2846e91bba0SGirish Moodalbail  * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
2856e91bba0SGirish Moodalbail  * backward compatibility with /sbin/ndd.
2866e91bba0SGirish Moodalbail  */
2876e91bba0SGirish Moodalbail /* ARGSUSED */
2886e91bba0SGirish Moodalbail int
mod_get_allprop(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * val,uint_t psize,uint_t flags)289*299625c6SSebastien Roy mod_get_allprop(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
2906e91bba0SGirish Moodalbail     void *val, uint_t psize, uint_t flags)
2916e91bba0SGirish Moodalbail {
2926e91bba0SGirish Moodalbail 	char		*pval = val;
2936e91bba0SGirish Moodalbail 	mod_prop_info_t	*ptbl, *prop;
2946e91bba0SGirish Moodalbail 	uint_t		size;
2956e91bba0SGirish Moodalbail 	size_t		nbytes = 0, tbytes = 0;
2966e91bba0SGirish Moodalbail 
2976e91bba0SGirish Moodalbail 	bzero(pval, psize);
2986e91bba0SGirish Moodalbail 	size = psize;
2996e91bba0SGirish Moodalbail 
3006e91bba0SGirish Moodalbail 	switch (pinfo->mpi_proto) {
3016e91bba0SGirish Moodalbail 	case MOD_PROTO_IP:
3026e91bba0SGirish Moodalbail 	case MOD_PROTO_IPV4:
3036e91bba0SGirish Moodalbail 	case MOD_PROTO_IPV6:
304*299625c6SSebastien Roy 		ptbl = stack->netstack_ip->ips_propinfo_tbl;
3056e91bba0SGirish Moodalbail 		break;
3066e91bba0SGirish Moodalbail 	case MOD_PROTO_RAWIP:
307*299625c6SSebastien Roy 		ptbl = stack->netstack_icmp->is_propinfo_tbl;
3086e91bba0SGirish Moodalbail 		break;
3096e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
310*299625c6SSebastien Roy 		ptbl = stack->netstack_tcp->tcps_propinfo_tbl;
3116e91bba0SGirish Moodalbail 		break;
3126e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
313*299625c6SSebastien Roy 		ptbl = stack->netstack_udp->us_propinfo_tbl;
3146e91bba0SGirish Moodalbail 		break;
3156e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
316*299625c6SSebastien Roy 		ptbl = stack->netstack_sctp->sctps_propinfo_tbl;
3176e91bba0SGirish Moodalbail 		break;
3186e91bba0SGirish Moodalbail 	default:
3196e91bba0SGirish Moodalbail 		return (EINVAL);
3206e91bba0SGirish Moodalbail 	}
3216e91bba0SGirish Moodalbail 
3226e91bba0SGirish Moodalbail 	for (prop = ptbl; prop->mpi_name != NULL; prop++) {
3236e91bba0SGirish Moodalbail 		if (prop->mpi_name[0] == '\0' ||
3248887b57dSGirish Moodalbail 		    strcmp(prop->mpi_name, "?") == 0) {
3256e91bba0SGirish Moodalbail 			continue;
3268887b57dSGirish Moodalbail 		}
3276e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name,
3286e91bba0SGirish Moodalbail 		    prop->mpi_proto, prop_perm2const(prop));
3296e91bba0SGirish Moodalbail 		size -= nbytes + 1;
3306e91bba0SGirish Moodalbail 		pval += nbytes + 1;
3316e91bba0SGirish Moodalbail 		tbytes += nbytes + 1;
3326e91bba0SGirish Moodalbail 		if (tbytes >= psize) {
3336e91bba0SGirish Moodalbail 			/* Buffer overflow, stop copying information */
3346e91bba0SGirish Moodalbail 			return (ENOBUFS);
3356e91bba0SGirish Moodalbail 		}
3366e91bba0SGirish Moodalbail 	}
3376e91bba0SGirish Moodalbail 	return (0);
3386e91bba0SGirish Moodalbail }
3396e91bba0SGirish Moodalbail 
3406e91bba0SGirish Moodalbail /*
3416e91bba0SGirish Moodalbail  * Hold a lock while changing *_epriv_ports to prevent multiple
3426e91bba0SGirish Moodalbail  * threads from changing it at the same time.
3436e91bba0SGirish Moodalbail  */
3446e91bba0SGirish Moodalbail /* ARGSUSED */
3456e91bba0SGirish Moodalbail int
mod_set_extra_privports(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * val,uint_t flags)346*299625c6SSebastien Roy mod_set_extra_privports(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
3476e91bba0SGirish Moodalbail     const char *ifname, const void* val, uint_t flags)
3486e91bba0SGirish Moodalbail {
3496e91bba0SGirish Moodalbail 	uint_t		proto = pinfo->mpi_proto;
3506e91bba0SGirish Moodalbail 	tcp_stack_t	*tcps;
3516e91bba0SGirish Moodalbail 	sctp_stack_t	*sctps;
3526e91bba0SGirish Moodalbail 	udp_stack_t	*us;
3536e91bba0SGirish Moodalbail 	unsigned long	new_value;
3546e91bba0SGirish Moodalbail 	char		*end;
3556e91bba0SGirish Moodalbail 	kmutex_t	*lock;
3566e91bba0SGirish Moodalbail 	uint_t		i, nports;
3576e91bba0SGirish Moodalbail 	in_port_t	*ports;
3586e91bba0SGirish Moodalbail 	boolean_t	def = (flags & MOD_PROP_DEFAULT);
3596e91bba0SGirish Moodalbail 	const char	*pval = val;
3606e91bba0SGirish Moodalbail 
3616e91bba0SGirish Moodalbail 	if (!def) {
3626e91bba0SGirish Moodalbail 		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
3636e91bba0SGirish Moodalbail 		    *end != '\0') {
3646e91bba0SGirish Moodalbail 			return (EINVAL);
3656e91bba0SGirish Moodalbail 		}
3666e91bba0SGirish Moodalbail 
3676e91bba0SGirish Moodalbail 		if (new_value < pinfo->prop_min_uval ||
3686e91bba0SGirish Moodalbail 		    new_value > pinfo->prop_max_uval) {
3696e91bba0SGirish Moodalbail 			return (ERANGE);
3706e91bba0SGirish Moodalbail 		}
3716e91bba0SGirish Moodalbail 	}
3726e91bba0SGirish Moodalbail 
3736e91bba0SGirish Moodalbail 	switch (proto) {
3746e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
375*299625c6SSebastien Roy 		tcps = stack->netstack_tcp;
3766e91bba0SGirish Moodalbail 		lock = &tcps->tcps_epriv_port_lock;
3776e91bba0SGirish Moodalbail 		ports = tcps->tcps_g_epriv_ports;
3786e91bba0SGirish Moodalbail 		nports = tcps->tcps_g_num_epriv_ports;
3796e91bba0SGirish Moodalbail 		break;
3806e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
381*299625c6SSebastien Roy 		us = stack->netstack_udp;
3826e91bba0SGirish Moodalbail 		lock = &us->us_epriv_port_lock;
3836e91bba0SGirish Moodalbail 		ports = us->us_epriv_ports;
3846e91bba0SGirish Moodalbail 		nports = us->us_num_epriv_ports;
3856e91bba0SGirish Moodalbail 		break;
3866e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
387*299625c6SSebastien Roy 		sctps = stack->netstack_sctp;
3886e91bba0SGirish Moodalbail 		lock = &sctps->sctps_epriv_port_lock;
3896e91bba0SGirish Moodalbail 		ports = sctps->sctps_g_epriv_ports;
3906e91bba0SGirish Moodalbail 		nports = sctps->sctps_g_num_epriv_ports;
3916e91bba0SGirish Moodalbail 		break;
3926e91bba0SGirish Moodalbail 	default:
3936e91bba0SGirish Moodalbail 		return (ENOTSUP);
3946e91bba0SGirish Moodalbail 	}
3956e91bba0SGirish Moodalbail 
3966e91bba0SGirish Moodalbail 	mutex_enter(lock);
3976e91bba0SGirish Moodalbail 
3986e91bba0SGirish Moodalbail 	/* if MOD_PROP_DEFAULT is set then reset the ports list to default */
3996e91bba0SGirish Moodalbail 	if (def) {
4006e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++)
4016e91bba0SGirish Moodalbail 			ports[i] = 0;
4026e91bba0SGirish Moodalbail 		ports[0] = ULP_DEF_EPRIV_PORT1;
4036e91bba0SGirish Moodalbail 		ports[1] = ULP_DEF_EPRIV_PORT2;
4046e91bba0SGirish Moodalbail 		mutex_exit(lock);
4056e91bba0SGirish Moodalbail 		return (0);
4066e91bba0SGirish Moodalbail 	}
4076e91bba0SGirish Moodalbail 
4086e91bba0SGirish Moodalbail 	/* Check if the value is already in the list */
4096e91bba0SGirish Moodalbail 	for (i = 0; i < nports; i++) {
4106e91bba0SGirish Moodalbail 		if (new_value == ports[i])
4116e91bba0SGirish Moodalbail 			break;
4126e91bba0SGirish Moodalbail 	}
4136e91bba0SGirish Moodalbail 
4146e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_REMOVE) {
4156e91bba0SGirish Moodalbail 		if (i == nports) {
4166e91bba0SGirish Moodalbail 			mutex_exit(lock);
4176e91bba0SGirish Moodalbail 			return (ESRCH);
4186e91bba0SGirish Moodalbail 		}
4196e91bba0SGirish Moodalbail 		/* Clear the value */
4206e91bba0SGirish Moodalbail 		ports[i] = 0;
4216e91bba0SGirish Moodalbail 	} else if (flags & MOD_PROP_APPEND) {
4226e91bba0SGirish Moodalbail 		if (i != nports) {
4236e91bba0SGirish Moodalbail 			mutex_exit(lock);
4246e91bba0SGirish Moodalbail 			return (EEXIST);
4256e91bba0SGirish Moodalbail 		}
4266e91bba0SGirish Moodalbail 
4276e91bba0SGirish Moodalbail 		/* Find an empty slot */
4286e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++) {
4296e91bba0SGirish Moodalbail 			if (ports[i] == 0)
4306e91bba0SGirish Moodalbail 				break;
4316e91bba0SGirish Moodalbail 		}
4326e91bba0SGirish Moodalbail 		if (i == nports) {
4336e91bba0SGirish Moodalbail 			mutex_exit(lock);
4346e91bba0SGirish Moodalbail 			return (EOVERFLOW);
4356e91bba0SGirish Moodalbail 		}
4366e91bba0SGirish Moodalbail 		/* Set the new value */
4376e91bba0SGirish Moodalbail 		ports[i] = (in_port_t)new_value;
4386e91bba0SGirish Moodalbail 	} else {
4396e91bba0SGirish Moodalbail 		/*
4406e91bba0SGirish Moodalbail 		 * If the user used 'assignment' modifier.
4416e91bba0SGirish Moodalbail 		 * For eg:
4426e91bba0SGirish Moodalbail 		 * 	# ipadm set-prop -p extra_priv_ports=3001 tcp
4436e91bba0SGirish Moodalbail 		 *
4446e91bba0SGirish Moodalbail 		 * We clear all the ports and then just add 3001.
4456e91bba0SGirish Moodalbail 		 */
4466e91bba0SGirish Moodalbail 		ASSERT(flags == MOD_PROP_ACTIVE);
4476e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++)
4486e91bba0SGirish Moodalbail 			ports[i] = 0;
4496e91bba0SGirish Moodalbail 		ports[0] = (in_port_t)new_value;
4506e91bba0SGirish Moodalbail 	}
4516e91bba0SGirish Moodalbail 
4526e91bba0SGirish Moodalbail 	mutex_exit(lock);
4536e91bba0SGirish Moodalbail 	return (0);
4546e91bba0SGirish Moodalbail }
4556e91bba0SGirish Moodalbail 
4566e91bba0SGirish Moodalbail /*
4576e91bba0SGirish Moodalbail  * Note: No locks are held when inspecting *_epriv_ports
4586e91bba0SGirish Moodalbail  * but instead the code relies on:
4596e91bba0SGirish Moodalbail  * - the fact that the address of the array and its size never changes
4606e91bba0SGirish Moodalbail  * - the atomic assignment of the elements of the array
4616e91bba0SGirish Moodalbail  */
4626e91bba0SGirish Moodalbail /* ARGSUSED */
4636e91bba0SGirish Moodalbail int
mod_get_extra_privports(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * val,uint_t psize,uint_t flags)464*299625c6SSebastien Roy mod_get_extra_privports(netstack_t *stack, mod_prop_info_t *pinfo,
465*299625c6SSebastien Roy     const char *ifname, void *val, uint_t psize, uint_t flags)
4666e91bba0SGirish Moodalbail {
4676e91bba0SGirish Moodalbail 	uint_t		proto = pinfo->mpi_proto;
4686e91bba0SGirish Moodalbail 	tcp_stack_t	*tcps;
4696e91bba0SGirish Moodalbail 	sctp_stack_t	*sctps;
4706e91bba0SGirish Moodalbail 	udp_stack_t	*us;
4716e91bba0SGirish Moodalbail 	uint_t		i, nports, size;
4726e91bba0SGirish Moodalbail 	in_port_t	*ports;
4736e91bba0SGirish Moodalbail 	char		*pval = val;
4746e91bba0SGirish Moodalbail 	size_t		nbytes = 0, tbytes = 0;
4756e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
4766e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
4776e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
4786e91bba0SGirish Moodalbail 
4796e91bba0SGirish Moodalbail 	bzero(pval, psize);
4806e91bba0SGirish Moodalbail 	size = psize;
4816e91bba0SGirish Moodalbail 
4826e91bba0SGirish Moodalbail 	if (get_def) {
4836e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1,
4846e91bba0SGirish Moodalbail 		    ULP_DEF_EPRIV_PORT2);
4856e91bba0SGirish Moodalbail 		goto ret;
4866e91bba0SGirish Moodalbail 	} else if (get_perm) {
4876e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
4886e91bba0SGirish Moodalbail 		goto ret;
4896e91bba0SGirish Moodalbail 	}
4906e91bba0SGirish Moodalbail 
4916e91bba0SGirish Moodalbail 	switch (proto) {
4926e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
493*299625c6SSebastien Roy 		tcps = stack->netstack_tcp;
4946e91bba0SGirish Moodalbail 		ports = tcps->tcps_g_epriv_ports;
4956e91bba0SGirish Moodalbail 		nports = tcps->tcps_g_num_epriv_ports;
4966e91bba0SGirish Moodalbail 		break;
4976e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
498*299625c6SSebastien Roy 		us = stack->netstack_udp;
4996e91bba0SGirish Moodalbail 		ports = us->us_epriv_ports;
5006e91bba0SGirish Moodalbail 		nports = us->us_num_epriv_ports;
5016e91bba0SGirish Moodalbail 		break;
5026e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
503*299625c6SSebastien Roy 		sctps = stack->netstack_sctp;
5046e91bba0SGirish Moodalbail 		ports = sctps->sctps_g_epriv_ports;
5056e91bba0SGirish Moodalbail 		nports = sctps->sctps_g_num_epriv_ports;
5066e91bba0SGirish Moodalbail 		break;
5076e91bba0SGirish Moodalbail 	default:
5086e91bba0SGirish Moodalbail 		return (ENOTSUP);
5096e91bba0SGirish Moodalbail 	}
5106e91bba0SGirish Moodalbail 
5116e91bba0SGirish Moodalbail 	if (get_range) {
5126e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
5136e91bba0SGirish Moodalbail 		    pinfo->prop_max_uval);
5146e91bba0SGirish Moodalbail 		goto ret;
5156e91bba0SGirish Moodalbail 	}
5166e91bba0SGirish Moodalbail 
5176e91bba0SGirish Moodalbail 	for (i = 0; i < nports; i++) {
5186e91bba0SGirish Moodalbail 		if (ports[i] != 0) {
5196e91bba0SGirish Moodalbail 			if (psize == size)
5206e91bba0SGirish Moodalbail 				nbytes = snprintf(pval, size, "%u", ports[i]);
5216e91bba0SGirish Moodalbail 			else
5226e91bba0SGirish Moodalbail 				nbytes = snprintf(pval, size, ",%u", ports[i]);
5236e91bba0SGirish Moodalbail 			size -= nbytes;
5246e91bba0SGirish Moodalbail 			pval += nbytes;
5256e91bba0SGirish Moodalbail 			tbytes += nbytes;
5266e91bba0SGirish Moodalbail 			if (tbytes >= psize)
5276e91bba0SGirish Moodalbail 				return (ENOBUFS);
5286e91bba0SGirish Moodalbail 		}
5296e91bba0SGirish Moodalbail 	}
5306e91bba0SGirish Moodalbail 	return (0);
5316e91bba0SGirish Moodalbail ret:
5326e91bba0SGirish Moodalbail 	if (tbytes >= psize)
5336e91bba0SGirish Moodalbail 		return (ENOBUFS);
5346e91bba0SGirish Moodalbail 	return (0);
5356e91bba0SGirish Moodalbail }
536