xref: /onnv-gate/usr/src/uts/common/inet/tunables.c (revision 13125:34b1540309cc)
112016SGirish.Moodalbail@Sun.COM /*
212016SGirish.Moodalbail@Sun.COM  * CDDL HEADER START
312016SGirish.Moodalbail@Sun.COM  *
412016SGirish.Moodalbail@Sun.COM  * The contents of this file are subject to the terms of the
512016SGirish.Moodalbail@Sun.COM  * Common Development and Distribution License (the "License").
612016SGirish.Moodalbail@Sun.COM  * You may not use this file except in compliance with the License.
712016SGirish.Moodalbail@Sun.COM  *
812016SGirish.Moodalbail@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912016SGirish.Moodalbail@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1012016SGirish.Moodalbail@Sun.COM  * See the License for the specific language governing permissions
1112016SGirish.Moodalbail@Sun.COM  * and limitations under the License.
1212016SGirish.Moodalbail@Sun.COM  *
1312016SGirish.Moodalbail@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1412016SGirish.Moodalbail@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512016SGirish.Moodalbail@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1612016SGirish.Moodalbail@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1712016SGirish.Moodalbail@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1812016SGirish.Moodalbail@Sun.COM  *
1912016SGirish.Moodalbail@Sun.COM  * CDDL HEADER END
2012016SGirish.Moodalbail@Sun.COM  */
2112016SGirish.Moodalbail@Sun.COM /*
2212313SSowmini.Varadhan@Sun.COM  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
2312313SSowmini.Varadhan@Sun.COM  * Copyright (c) 1990 Mentat Inc.
2412016SGirish.Moodalbail@Sun.COM  */
2512016SGirish.Moodalbail@Sun.COM 
2612016SGirish.Moodalbail@Sun.COM #include <inet/tunables.h>
2712016SGirish.Moodalbail@Sun.COM #include <sys/md5.h>
2812016SGirish.Moodalbail@Sun.COM #include <inet/common.h>
2912016SGirish.Moodalbail@Sun.COM #include <inet/ip.h>
3012016SGirish.Moodalbail@Sun.COM #include <inet/ip6.h>
3112016SGirish.Moodalbail@Sun.COM #include <netinet/icmp6.h>
3212016SGirish.Moodalbail@Sun.COM #include <inet/ip_stack.h>
3312016SGirish.Moodalbail@Sun.COM #include <inet/rawip_impl.h>
3412016SGirish.Moodalbail@Sun.COM #include <inet/tcp_stack.h>
3512016SGirish.Moodalbail@Sun.COM #include <inet/tcp_impl.h>
3612016SGirish.Moodalbail@Sun.COM #include <inet/udp_impl.h>
3712016SGirish.Moodalbail@Sun.COM #include <inet/sctp/sctp_stack.h>
3812016SGirish.Moodalbail@Sun.COM #include <inet/sctp/sctp_impl.h>
3912016SGirish.Moodalbail@Sun.COM #include <inet/tunables.h>
4012016SGirish.Moodalbail@Sun.COM 
4112016SGirish.Moodalbail@Sun.COM static int
prop_perm2const(mod_prop_info_t * pinfo)4212016SGirish.Moodalbail@Sun.COM prop_perm2const(mod_prop_info_t *pinfo)
4312016SGirish.Moodalbail@Sun.COM {
4412016SGirish.Moodalbail@Sun.COM 	if (pinfo->mpi_setf == NULL)
4512016SGirish.Moodalbail@Sun.COM 		return (MOD_PROP_PERM_READ);
4612016SGirish.Moodalbail@Sun.COM 	if (pinfo->mpi_getf == NULL)
4712016SGirish.Moodalbail@Sun.COM 		return (MOD_PROP_PERM_WRITE);
4812016SGirish.Moodalbail@Sun.COM 	return (MOD_PROP_PERM_RW);
4912016SGirish.Moodalbail@Sun.COM }
5012016SGirish.Moodalbail@Sun.COM 
5112016SGirish.Moodalbail@Sun.COM /*
5212016SGirish.Moodalbail@Sun.COM  * Modifies the value of the property to default value or to the `pval'
5312016SGirish.Moodalbail@Sun.COM  * specified by the user.
5412016SGirish.Moodalbail@Sun.COM  */
5512016SGirish.Moodalbail@Sun.COM /* ARGSUSED */
5612016SGirish.Moodalbail@Sun.COM int
mod_set_boolean(void * cbarg,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)5712016SGirish.Moodalbail@Sun.COM mod_set_boolean(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
5812016SGirish.Moodalbail@Sun.COM     const char *ifname, const void* pval, uint_t flags)
5912016SGirish.Moodalbail@Sun.COM {
6012016SGirish.Moodalbail@Sun.COM 	char 		*end;
6112016SGirish.Moodalbail@Sun.COM 	unsigned long 	new_value;
6212016SGirish.Moodalbail@Sun.COM 
6312016SGirish.Moodalbail@Sun.COM 	if (flags & MOD_PROP_DEFAULT) {
6412016SGirish.Moodalbail@Sun.COM 		pinfo->prop_cur_bval = pinfo->prop_def_bval;
6512016SGirish.Moodalbail@Sun.COM 		return (0);
6612016SGirish.Moodalbail@Sun.COM 	}
6712016SGirish.Moodalbail@Sun.COM 
6812016SGirish.Moodalbail@Sun.COM 	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
6912016SGirish.Moodalbail@Sun.COM 		return (EINVAL);
7012016SGirish.Moodalbail@Sun.COM 	if (new_value != B_TRUE && new_value != B_FALSE)
7112016SGirish.Moodalbail@Sun.COM 		return (EINVAL);
7212016SGirish.Moodalbail@Sun.COM 	pinfo->prop_cur_bval = new_value;
7312016SGirish.Moodalbail@Sun.COM 	return (0);
7412016SGirish.Moodalbail@Sun.COM }
7512016SGirish.Moodalbail@Sun.COM 
7612016SGirish.Moodalbail@Sun.COM /*
7712016SGirish.Moodalbail@Sun.COM  * Retrieves property permission, default value, current value or possible
7812016SGirish.Moodalbail@Sun.COM  * values for those properties whose value type is boolean_t.
7912016SGirish.Moodalbail@Sun.COM  */
8012016SGirish.Moodalbail@Sun.COM /* ARGSUSED */
8112016SGirish.Moodalbail@Sun.COM int
mod_get_boolean(void * cbarg,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)8212016SGirish.Moodalbail@Sun.COM mod_get_boolean(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
8312016SGirish.Moodalbail@Sun.COM     void *pval, uint_t psize, uint_t flags)
8412016SGirish.Moodalbail@Sun.COM {
8512016SGirish.Moodalbail@Sun.COM 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
8612016SGirish.Moodalbail@Sun.COM 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
8712016SGirish.Moodalbail@Sun.COM 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
8812016SGirish.Moodalbail@Sun.COM 	size_t		nbytes;
8912016SGirish.Moodalbail@Sun.COM 
9012016SGirish.Moodalbail@Sun.COM 	bzero(pval, psize);
9112016SGirish.Moodalbail@Sun.COM 	if (get_perm)
9212016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
9312016SGirish.Moodalbail@Sun.COM 	else if (get_range)
9412016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE);
9512016SGirish.Moodalbail@Sun.COM 	else if (get_def)
9612016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval);
9712016SGirish.Moodalbail@Sun.COM 	else
9812016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval);
9912016SGirish.Moodalbail@Sun.COM 	if (nbytes >= psize)
10012016SGirish.Moodalbail@Sun.COM 		return (ENOBUFS);
10112016SGirish.Moodalbail@Sun.COM 	return (0);
10212016SGirish.Moodalbail@Sun.COM }
10312016SGirish.Moodalbail@Sun.COM 
10412313SSowmini.Varadhan@Sun.COM int
mod_uint32_value(const void * pval,mod_prop_info_t * pinfo,uint_t flags,ulong_t * new_value)10512313SSowmini.Varadhan@Sun.COM mod_uint32_value(const void *pval, mod_prop_info_t *pinfo, uint_t flags,
10612313SSowmini.Varadhan@Sun.COM     ulong_t *new_value)
10712313SSowmini.Varadhan@Sun.COM {
10812313SSowmini.Varadhan@Sun.COM 	char 		*end;
10912313SSowmini.Varadhan@Sun.COM 
11012313SSowmini.Varadhan@Sun.COM 	if (flags & MOD_PROP_DEFAULT) {
11112313SSowmini.Varadhan@Sun.COM 		*new_value = pinfo->prop_def_uval;
11212313SSowmini.Varadhan@Sun.COM 		return (0);
11312313SSowmini.Varadhan@Sun.COM 	}
11412313SSowmini.Varadhan@Sun.COM 
11512313SSowmini.Varadhan@Sun.COM 	if (ddi_strtoul(pval, &end, 10, (ulong_t *)new_value) != 0 ||
11612313SSowmini.Varadhan@Sun.COM 	    *end != '\0')
11712313SSowmini.Varadhan@Sun.COM 		return (EINVAL);
11812313SSowmini.Varadhan@Sun.COM 	if (*new_value < pinfo->prop_min_uval ||
11912313SSowmini.Varadhan@Sun.COM 	    *new_value > pinfo->prop_max_uval) {
12012313SSowmini.Varadhan@Sun.COM 		return (ERANGE);
12112313SSowmini.Varadhan@Sun.COM 	}
12212313SSowmini.Varadhan@Sun.COM 	return (0);
12312313SSowmini.Varadhan@Sun.COM }
12412313SSowmini.Varadhan@Sun.COM 
12512016SGirish.Moodalbail@Sun.COM /*
12612016SGirish.Moodalbail@Sun.COM  * Modifies the value of the property to default value or to the `pval'
12712016SGirish.Moodalbail@Sun.COM  * specified by the user.
12812016SGirish.Moodalbail@Sun.COM  */
12912016SGirish.Moodalbail@Sun.COM /* ARGSUSED */
13012016SGirish.Moodalbail@Sun.COM int
mod_set_uint32(void * cbarg,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)13112016SGirish.Moodalbail@Sun.COM mod_set_uint32(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
13212313SSowmini.Varadhan@Sun.COM     const char *ifname, const void *pval, uint_t flags)
13312016SGirish.Moodalbail@Sun.COM {
13412313SSowmini.Varadhan@Sun.COM 	unsigned long	new_value;
13512313SSowmini.Varadhan@Sun.COM 	int		err;
13612016SGirish.Moodalbail@Sun.COM 
13712313SSowmini.Varadhan@Sun.COM 	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
13812313SSowmini.Varadhan@Sun.COM 		return (err);
13912016SGirish.Moodalbail@Sun.COM 	pinfo->prop_cur_uval = (uint32_t)new_value;
14012016SGirish.Moodalbail@Sun.COM 	return (0);
14112016SGirish.Moodalbail@Sun.COM }
14212016SGirish.Moodalbail@Sun.COM 
14312016SGirish.Moodalbail@Sun.COM /*
14412016SGirish.Moodalbail@Sun.COM  * Rounds up the value to make it multiple of 8.
14512016SGirish.Moodalbail@Sun.COM  */
14612016SGirish.Moodalbail@Sun.COM /* ARGSUSED */
14712016SGirish.Moodalbail@Sun.COM int
mod_set_aligned(void * cbarg,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)14812016SGirish.Moodalbail@Sun.COM mod_set_aligned(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
14912016SGirish.Moodalbail@Sun.COM     const char *ifname, const void* pval, uint_t flags)
15012016SGirish.Moodalbail@Sun.COM {
15112016SGirish.Moodalbail@Sun.COM 	int	err;
15212016SGirish.Moodalbail@Sun.COM 
15312016SGirish.Moodalbail@Sun.COM 	if ((err = mod_set_uint32(cbarg, cr, pinfo, ifname, pval, flags)) != 0)
15412016SGirish.Moodalbail@Sun.COM 		return (err);
15512016SGirish.Moodalbail@Sun.COM 
15612016SGirish.Moodalbail@Sun.COM 	/* if required, align the value to multiple of 8 */
15712016SGirish.Moodalbail@Sun.COM 	if (pinfo->prop_cur_uval & 0x7) {
15812016SGirish.Moodalbail@Sun.COM 		pinfo->prop_cur_uval &= ~0x7;
15912016SGirish.Moodalbail@Sun.COM 		pinfo->prop_cur_uval += 0x8;
16012016SGirish.Moodalbail@Sun.COM 	}
16112016SGirish.Moodalbail@Sun.COM 
16212016SGirish.Moodalbail@Sun.COM 	return (0);
16312016SGirish.Moodalbail@Sun.COM }
16412016SGirish.Moodalbail@Sun.COM 
16512016SGirish.Moodalbail@Sun.COM /*
16612016SGirish.Moodalbail@Sun.COM  * Retrieves property permission, default value, current value or possible
16712016SGirish.Moodalbail@Sun.COM  * values for those properties whose value type is uint32_t.
16812016SGirish.Moodalbail@Sun.COM  */
16912016SGirish.Moodalbail@Sun.COM /* ARGSUSED */
17012016SGirish.Moodalbail@Sun.COM int
mod_get_uint32(void * cbarg,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)17112016SGirish.Moodalbail@Sun.COM mod_get_uint32(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
17212016SGirish.Moodalbail@Sun.COM     void *pval, uint_t psize, uint_t flags)
17312016SGirish.Moodalbail@Sun.COM {
17412016SGirish.Moodalbail@Sun.COM 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
17512016SGirish.Moodalbail@Sun.COM 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
17612016SGirish.Moodalbail@Sun.COM 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
17712016SGirish.Moodalbail@Sun.COM 	size_t		nbytes;
17812016SGirish.Moodalbail@Sun.COM 
17912016SGirish.Moodalbail@Sun.COM 	bzero(pval, psize);
18012016SGirish.Moodalbail@Sun.COM 	if (get_perm)
18112016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
18212016SGirish.Moodalbail@Sun.COM 	else if (get_range)
18312016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, psize, "%u-%u",
18412016SGirish.Moodalbail@Sun.COM 		    pinfo->prop_min_uval, pinfo->prop_max_uval);
18512016SGirish.Moodalbail@Sun.COM 	else if (get_def)
18612016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
18712016SGirish.Moodalbail@Sun.COM 	else
18812016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval);
18912016SGirish.Moodalbail@Sun.COM 	if (nbytes >= psize)
19012016SGirish.Moodalbail@Sun.COM 		return (ENOBUFS);
19112016SGirish.Moodalbail@Sun.COM 	return (0);
19212016SGirish.Moodalbail@Sun.COM }
19312016SGirish.Moodalbail@Sun.COM 
19412016SGirish.Moodalbail@Sun.COM /*
19512016SGirish.Moodalbail@Sun.COM  * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
19612016SGirish.Moodalbail@Sun.COM  * backward compatibility with /sbin/ndd.
19712016SGirish.Moodalbail@Sun.COM  */
19812016SGirish.Moodalbail@Sun.COM /* ARGSUSED */
19912016SGirish.Moodalbail@Sun.COM int
mod_get_allprop(void * cbarg,mod_prop_info_t * pinfo,const char * ifname,void * val,uint_t psize,uint_t flags)20012016SGirish.Moodalbail@Sun.COM mod_get_allprop(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
20112016SGirish.Moodalbail@Sun.COM     void *val, uint_t psize, uint_t flags)
20212016SGirish.Moodalbail@Sun.COM {
20312016SGirish.Moodalbail@Sun.COM 	char		*pval = val;
20412016SGirish.Moodalbail@Sun.COM 	mod_prop_info_t	*ptbl, *prop;
20512016SGirish.Moodalbail@Sun.COM 	ip_stack_t	*ipst;
20612016SGirish.Moodalbail@Sun.COM 	tcp_stack_t	*tcps;
20712016SGirish.Moodalbail@Sun.COM 	sctp_stack_t	*sctps;
20812016SGirish.Moodalbail@Sun.COM 	udp_stack_t	*us;
20912016SGirish.Moodalbail@Sun.COM 	icmp_stack_t	*is;
21012016SGirish.Moodalbail@Sun.COM 	uint_t		size;
21112016SGirish.Moodalbail@Sun.COM 	size_t		nbytes = 0, tbytes = 0;
21212016SGirish.Moodalbail@Sun.COM 
21312016SGirish.Moodalbail@Sun.COM 	bzero(pval, psize);
21412016SGirish.Moodalbail@Sun.COM 	size = psize;
21512016SGirish.Moodalbail@Sun.COM 
21612016SGirish.Moodalbail@Sun.COM 	switch (pinfo->mpi_proto) {
21712016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_IP:
21812016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_IPV4:
21912016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_IPV6:
22012016SGirish.Moodalbail@Sun.COM 		ipst = (ip_stack_t *)cbarg;
22112016SGirish.Moodalbail@Sun.COM 		ptbl = ipst->ips_propinfo_tbl;
22212016SGirish.Moodalbail@Sun.COM 		break;
22312016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_RAWIP:
22412016SGirish.Moodalbail@Sun.COM 		is = (icmp_stack_t *)cbarg;
22512016SGirish.Moodalbail@Sun.COM 		ptbl = is->is_propinfo_tbl;
22612016SGirish.Moodalbail@Sun.COM 		break;
22712016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_TCP:
22812016SGirish.Moodalbail@Sun.COM 		tcps = (tcp_stack_t *)cbarg;
22912016SGirish.Moodalbail@Sun.COM 		ptbl = tcps->tcps_propinfo_tbl;
23012016SGirish.Moodalbail@Sun.COM 		break;
23112016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_UDP:
23212016SGirish.Moodalbail@Sun.COM 		us = (udp_stack_t *)cbarg;
23312016SGirish.Moodalbail@Sun.COM 		ptbl = us->us_propinfo_tbl;
23412016SGirish.Moodalbail@Sun.COM 		break;
23512016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_SCTP:
23612016SGirish.Moodalbail@Sun.COM 		sctps = (sctp_stack_t *)cbarg;
23712016SGirish.Moodalbail@Sun.COM 		ptbl = sctps->sctps_propinfo_tbl;
23812016SGirish.Moodalbail@Sun.COM 		break;
23912016SGirish.Moodalbail@Sun.COM 	default:
24012016SGirish.Moodalbail@Sun.COM 		return (EINVAL);
24112016SGirish.Moodalbail@Sun.COM 	}
24212016SGirish.Moodalbail@Sun.COM 
24312016SGirish.Moodalbail@Sun.COM 	for (prop = ptbl; prop->mpi_name != NULL; prop++) {
24412016SGirish.Moodalbail@Sun.COM 		if (prop->mpi_name[0] == '\0' ||
245*13125SGirish.Moodalbail@oracle.COM 		    strcmp(prop->mpi_name, "?") == 0) {
24612016SGirish.Moodalbail@Sun.COM 			continue;
247*13125SGirish.Moodalbail@oracle.COM 		}
24812016SGirish.Moodalbail@Sun.COM 		nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name,
24912016SGirish.Moodalbail@Sun.COM 		    prop->mpi_proto, prop_perm2const(prop));
25012016SGirish.Moodalbail@Sun.COM 		size -= nbytes + 1;
25112016SGirish.Moodalbail@Sun.COM 		pval += nbytes + 1;
25212016SGirish.Moodalbail@Sun.COM 		tbytes += nbytes + 1;
25312016SGirish.Moodalbail@Sun.COM 		if (tbytes >= psize) {
25412016SGirish.Moodalbail@Sun.COM 			/* Buffer overflow, stop copying information */
25512016SGirish.Moodalbail@Sun.COM 			return (ENOBUFS);
25612016SGirish.Moodalbail@Sun.COM 		}
25712016SGirish.Moodalbail@Sun.COM 	}
25812016SGirish.Moodalbail@Sun.COM 	return (0);
25912016SGirish.Moodalbail@Sun.COM }
26012016SGirish.Moodalbail@Sun.COM 
26112016SGirish.Moodalbail@Sun.COM /*
26212016SGirish.Moodalbail@Sun.COM  * Hold a lock while changing *_epriv_ports to prevent multiple
26312016SGirish.Moodalbail@Sun.COM  * threads from changing it at the same time.
26412016SGirish.Moodalbail@Sun.COM  */
26512016SGirish.Moodalbail@Sun.COM /* ARGSUSED */
26612016SGirish.Moodalbail@Sun.COM int
mod_set_extra_privports(void * cbarg,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * val,uint_t flags)26712016SGirish.Moodalbail@Sun.COM mod_set_extra_privports(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
26812016SGirish.Moodalbail@Sun.COM     const char *ifname, const void* val, uint_t flags)
26912016SGirish.Moodalbail@Sun.COM {
27012016SGirish.Moodalbail@Sun.COM 	uint_t		proto = pinfo->mpi_proto;
27112016SGirish.Moodalbail@Sun.COM 	tcp_stack_t	*tcps;
27212016SGirish.Moodalbail@Sun.COM 	sctp_stack_t	*sctps;
27312016SGirish.Moodalbail@Sun.COM 	udp_stack_t	*us;
27412016SGirish.Moodalbail@Sun.COM 	unsigned long	new_value;
27512016SGirish.Moodalbail@Sun.COM 	char		*end;
27612016SGirish.Moodalbail@Sun.COM 	kmutex_t	*lock;
27712016SGirish.Moodalbail@Sun.COM 	uint_t		i, nports;
27812016SGirish.Moodalbail@Sun.COM 	in_port_t	*ports;
27912016SGirish.Moodalbail@Sun.COM 	boolean_t	def = (flags & MOD_PROP_DEFAULT);
28012016SGirish.Moodalbail@Sun.COM 	const char	*pval = val;
28112016SGirish.Moodalbail@Sun.COM 
28212016SGirish.Moodalbail@Sun.COM 	if (!def) {
28312016SGirish.Moodalbail@Sun.COM 		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
28412016SGirish.Moodalbail@Sun.COM 		    *end != '\0') {
28512016SGirish.Moodalbail@Sun.COM 			return (EINVAL);
28612016SGirish.Moodalbail@Sun.COM 		}
28712016SGirish.Moodalbail@Sun.COM 
28812016SGirish.Moodalbail@Sun.COM 		if (new_value < pinfo->prop_min_uval ||
28912016SGirish.Moodalbail@Sun.COM 		    new_value > pinfo->prop_max_uval) {
29012016SGirish.Moodalbail@Sun.COM 			return (ERANGE);
29112016SGirish.Moodalbail@Sun.COM 		}
29212016SGirish.Moodalbail@Sun.COM 	}
29312016SGirish.Moodalbail@Sun.COM 
29412016SGirish.Moodalbail@Sun.COM 	switch (proto) {
29512016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_TCP:
29612016SGirish.Moodalbail@Sun.COM 		tcps = (tcp_stack_t *)cbarg;
29712016SGirish.Moodalbail@Sun.COM 		lock = &tcps->tcps_epriv_port_lock;
29812016SGirish.Moodalbail@Sun.COM 		ports = tcps->tcps_g_epriv_ports;
29912016SGirish.Moodalbail@Sun.COM 		nports = tcps->tcps_g_num_epriv_ports;
30012016SGirish.Moodalbail@Sun.COM 		break;
30112016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_UDP:
30212016SGirish.Moodalbail@Sun.COM 		us = (udp_stack_t *)cbarg;
30312016SGirish.Moodalbail@Sun.COM 		lock = &us->us_epriv_port_lock;
30412016SGirish.Moodalbail@Sun.COM 		ports = us->us_epriv_ports;
30512016SGirish.Moodalbail@Sun.COM 		nports = us->us_num_epriv_ports;
30612016SGirish.Moodalbail@Sun.COM 		break;
30712016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_SCTP:
30812016SGirish.Moodalbail@Sun.COM 		sctps = (sctp_stack_t *)cbarg;
30912016SGirish.Moodalbail@Sun.COM 		lock = &sctps->sctps_epriv_port_lock;
31012016SGirish.Moodalbail@Sun.COM 		ports = sctps->sctps_g_epriv_ports;
31112016SGirish.Moodalbail@Sun.COM 		nports = sctps->sctps_g_num_epriv_ports;
31212016SGirish.Moodalbail@Sun.COM 		break;
31312016SGirish.Moodalbail@Sun.COM 	default:
31412016SGirish.Moodalbail@Sun.COM 		return (ENOTSUP);
31512016SGirish.Moodalbail@Sun.COM 	}
31612016SGirish.Moodalbail@Sun.COM 
31712016SGirish.Moodalbail@Sun.COM 	mutex_enter(lock);
31812016SGirish.Moodalbail@Sun.COM 
31912016SGirish.Moodalbail@Sun.COM 	/* if MOD_PROP_DEFAULT is set then reset the ports list to default */
32012016SGirish.Moodalbail@Sun.COM 	if (def) {
32112016SGirish.Moodalbail@Sun.COM 		for (i = 0; i < nports; i++)
32212016SGirish.Moodalbail@Sun.COM 			ports[i] = 0;
32312016SGirish.Moodalbail@Sun.COM 		ports[0] = ULP_DEF_EPRIV_PORT1;
32412016SGirish.Moodalbail@Sun.COM 		ports[1] = ULP_DEF_EPRIV_PORT2;
32512016SGirish.Moodalbail@Sun.COM 		mutex_exit(lock);
32612016SGirish.Moodalbail@Sun.COM 		return (0);
32712016SGirish.Moodalbail@Sun.COM 	}
32812016SGirish.Moodalbail@Sun.COM 
32912016SGirish.Moodalbail@Sun.COM 	/* Check if the value is already in the list */
33012016SGirish.Moodalbail@Sun.COM 	for (i = 0; i < nports; i++) {
33112016SGirish.Moodalbail@Sun.COM 		if (new_value == ports[i])
33212016SGirish.Moodalbail@Sun.COM 			break;
33312016SGirish.Moodalbail@Sun.COM 	}
33412016SGirish.Moodalbail@Sun.COM 
33512016SGirish.Moodalbail@Sun.COM 	if (flags & MOD_PROP_REMOVE) {
33612016SGirish.Moodalbail@Sun.COM 		if (i == nports) {
33712016SGirish.Moodalbail@Sun.COM 			mutex_exit(lock);
33812016SGirish.Moodalbail@Sun.COM 			return (ESRCH);
33912016SGirish.Moodalbail@Sun.COM 		}
34012016SGirish.Moodalbail@Sun.COM 		/* Clear the value */
34112016SGirish.Moodalbail@Sun.COM 		ports[i] = 0;
34212016SGirish.Moodalbail@Sun.COM 	} else if (flags & MOD_PROP_APPEND) {
34312016SGirish.Moodalbail@Sun.COM 		if (i != nports) {
34412016SGirish.Moodalbail@Sun.COM 			mutex_exit(lock);
34512016SGirish.Moodalbail@Sun.COM 			return (EEXIST);
34612016SGirish.Moodalbail@Sun.COM 		}
34712016SGirish.Moodalbail@Sun.COM 
34812016SGirish.Moodalbail@Sun.COM 		/* Find an empty slot */
34912016SGirish.Moodalbail@Sun.COM 		for (i = 0; i < nports; i++) {
35012016SGirish.Moodalbail@Sun.COM 			if (ports[i] == 0)
35112016SGirish.Moodalbail@Sun.COM 				break;
35212016SGirish.Moodalbail@Sun.COM 		}
35312016SGirish.Moodalbail@Sun.COM 		if (i == nports) {
35412016SGirish.Moodalbail@Sun.COM 			mutex_exit(lock);
35512016SGirish.Moodalbail@Sun.COM 			return (EOVERFLOW);
35612016SGirish.Moodalbail@Sun.COM 		}
35712016SGirish.Moodalbail@Sun.COM 		/* Set the new value */
35812016SGirish.Moodalbail@Sun.COM 		ports[i] = (in_port_t)new_value;
35912016SGirish.Moodalbail@Sun.COM 	} else {
36012016SGirish.Moodalbail@Sun.COM 		/*
36112016SGirish.Moodalbail@Sun.COM 		 * If the user used 'assignment' modifier.
36212016SGirish.Moodalbail@Sun.COM 		 * For eg:
36312016SGirish.Moodalbail@Sun.COM 		 * 	# ipadm set-prop -p extra_priv_ports=3001 tcp
36412016SGirish.Moodalbail@Sun.COM 		 *
36512016SGirish.Moodalbail@Sun.COM 		 * We clear all the ports and then just add 3001.
36612016SGirish.Moodalbail@Sun.COM 		 */
36712016SGirish.Moodalbail@Sun.COM 		ASSERT(flags == MOD_PROP_ACTIVE);
36812016SGirish.Moodalbail@Sun.COM 		for (i = 0; i < nports; i++)
36912016SGirish.Moodalbail@Sun.COM 			ports[i] = 0;
37012016SGirish.Moodalbail@Sun.COM 		ports[0] = (in_port_t)new_value;
37112016SGirish.Moodalbail@Sun.COM 	}
37212016SGirish.Moodalbail@Sun.COM 
37312016SGirish.Moodalbail@Sun.COM 	mutex_exit(lock);
37412016SGirish.Moodalbail@Sun.COM 	return (0);
37512016SGirish.Moodalbail@Sun.COM }
37612016SGirish.Moodalbail@Sun.COM 
37712016SGirish.Moodalbail@Sun.COM /*
37812016SGirish.Moodalbail@Sun.COM  * Note: No locks are held when inspecting *_epriv_ports
37912016SGirish.Moodalbail@Sun.COM  * but instead the code relies on:
38012016SGirish.Moodalbail@Sun.COM  * - the fact that the address of the array and its size never changes
38112016SGirish.Moodalbail@Sun.COM  * - the atomic assignment of the elements of the array
38212016SGirish.Moodalbail@Sun.COM  */
38312016SGirish.Moodalbail@Sun.COM /* ARGSUSED */
38412016SGirish.Moodalbail@Sun.COM int
mod_get_extra_privports(void * cbarg,mod_prop_info_t * pinfo,const char * ifname,void * val,uint_t psize,uint_t flags)38512016SGirish.Moodalbail@Sun.COM mod_get_extra_privports(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
38612016SGirish.Moodalbail@Sun.COM     void *val, uint_t psize, uint_t flags)
38712016SGirish.Moodalbail@Sun.COM {
38812016SGirish.Moodalbail@Sun.COM 	uint_t		proto = pinfo->mpi_proto;
38912016SGirish.Moodalbail@Sun.COM 	tcp_stack_t	*tcps;
39012016SGirish.Moodalbail@Sun.COM 	sctp_stack_t	*sctps;
39112016SGirish.Moodalbail@Sun.COM 	udp_stack_t	*us;
39212016SGirish.Moodalbail@Sun.COM 	uint_t		i, nports, size;
39312016SGirish.Moodalbail@Sun.COM 	in_port_t	*ports;
39412016SGirish.Moodalbail@Sun.COM 	char		*pval = val;
39512016SGirish.Moodalbail@Sun.COM 	size_t		nbytes = 0, tbytes = 0;
39612016SGirish.Moodalbail@Sun.COM 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
39712016SGirish.Moodalbail@Sun.COM 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
39812016SGirish.Moodalbail@Sun.COM 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
39912016SGirish.Moodalbail@Sun.COM 
40012016SGirish.Moodalbail@Sun.COM 	bzero(pval, psize);
40112016SGirish.Moodalbail@Sun.COM 	size = psize;
40212016SGirish.Moodalbail@Sun.COM 
40312016SGirish.Moodalbail@Sun.COM 	if (get_def) {
40412016SGirish.Moodalbail@Sun.COM 		tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1,
40512016SGirish.Moodalbail@Sun.COM 		    ULP_DEF_EPRIV_PORT2);
40612016SGirish.Moodalbail@Sun.COM 		goto ret;
40712016SGirish.Moodalbail@Sun.COM 	} else if (get_perm) {
40812016SGirish.Moodalbail@Sun.COM 		tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
40912016SGirish.Moodalbail@Sun.COM 		goto ret;
41012016SGirish.Moodalbail@Sun.COM 	}
41112016SGirish.Moodalbail@Sun.COM 
41212016SGirish.Moodalbail@Sun.COM 	switch (proto) {
41312016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_TCP:
41412016SGirish.Moodalbail@Sun.COM 		tcps = (tcp_stack_t *)cbarg;
41512016SGirish.Moodalbail@Sun.COM 		ports = tcps->tcps_g_epriv_ports;
41612016SGirish.Moodalbail@Sun.COM 		nports = tcps->tcps_g_num_epriv_ports;
41712016SGirish.Moodalbail@Sun.COM 		break;
41812016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_UDP:
41912016SGirish.Moodalbail@Sun.COM 		us = (udp_stack_t *)cbarg;
42012016SGirish.Moodalbail@Sun.COM 		ports = us->us_epriv_ports;
42112016SGirish.Moodalbail@Sun.COM 		nports = us->us_num_epriv_ports;
42212016SGirish.Moodalbail@Sun.COM 		break;
42312016SGirish.Moodalbail@Sun.COM 	case MOD_PROTO_SCTP:
42412016SGirish.Moodalbail@Sun.COM 		sctps = (sctp_stack_t *)cbarg;
42512016SGirish.Moodalbail@Sun.COM 		ports = sctps->sctps_g_epriv_ports;
42612016SGirish.Moodalbail@Sun.COM 		nports = sctps->sctps_g_num_epriv_ports;
42712016SGirish.Moodalbail@Sun.COM 		break;
42812016SGirish.Moodalbail@Sun.COM 	default:
42912016SGirish.Moodalbail@Sun.COM 		return (ENOTSUP);
43012016SGirish.Moodalbail@Sun.COM 	}
43112016SGirish.Moodalbail@Sun.COM 
43212016SGirish.Moodalbail@Sun.COM 	if (get_range) {
43312016SGirish.Moodalbail@Sun.COM 		tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
43412016SGirish.Moodalbail@Sun.COM 		    pinfo->prop_max_uval);
43512016SGirish.Moodalbail@Sun.COM 		goto ret;
43612016SGirish.Moodalbail@Sun.COM 	}
43712016SGirish.Moodalbail@Sun.COM 
43812016SGirish.Moodalbail@Sun.COM 	for (i = 0; i < nports; i++) {
43912016SGirish.Moodalbail@Sun.COM 		if (ports[i] != 0) {
44012016SGirish.Moodalbail@Sun.COM 			if (psize == size)
44112016SGirish.Moodalbail@Sun.COM 				nbytes = snprintf(pval, size, "%u", ports[i]);
44212016SGirish.Moodalbail@Sun.COM 			else
44312016SGirish.Moodalbail@Sun.COM 				nbytes = snprintf(pval, size, ",%u", ports[i]);
44412016SGirish.Moodalbail@Sun.COM 			size -= nbytes;
44512016SGirish.Moodalbail@Sun.COM 			pval += nbytes;
44612016SGirish.Moodalbail@Sun.COM 			tbytes += nbytes;
44712016SGirish.Moodalbail@Sun.COM 			if (tbytes >= psize)
44812016SGirish.Moodalbail@Sun.COM 				return (ENOBUFS);
44912016SGirish.Moodalbail@Sun.COM 		}
45012016SGirish.Moodalbail@Sun.COM 	}
45112016SGirish.Moodalbail@Sun.COM 	return (0);
45212016SGirish.Moodalbail@Sun.COM ret:
45312016SGirish.Moodalbail@Sun.COM 	if (tbytes >= psize)
45412016SGirish.Moodalbail@Sun.COM 		return (ENOBUFS);
45512016SGirish.Moodalbail@Sun.COM 	return (0);
45612016SGirish.Moodalbail@Sun.COM }
457