xref: /titanic_52/usr/src/uts/common/inet/tunables.c (revision 6e91bba0d6c6bdabbba62cefae583715a4a58e2a)
1*6e91bba0SGirish Moodalbail /*
2*6e91bba0SGirish Moodalbail  * CDDL HEADER START
3*6e91bba0SGirish Moodalbail  *
4*6e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
5*6e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
6*6e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
7*6e91bba0SGirish Moodalbail  *
8*6e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
10*6e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
11*6e91bba0SGirish Moodalbail  * and limitations under the License.
12*6e91bba0SGirish Moodalbail  *
13*6e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
14*6e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
16*6e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
17*6e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6e91bba0SGirish Moodalbail  *
19*6e91bba0SGirish Moodalbail  * CDDL HEADER END
20*6e91bba0SGirish Moodalbail  */
21*6e91bba0SGirish Moodalbail /*
22*6e91bba0SGirish Moodalbail  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23*6e91bba0SGirish Moodalbail  * Use is subject to license terms.
24*6e91bba0SGirish Moodalbail  */
25*6e91bba0SGirish Moodalbail 
26*6e91bba0SGirish Moodalbail #include <inet/tunables.h>
27*6e91bba0SGirish Moodalbail #include <sys/md5.h>
28*6e91bba0SGirish Moodalbail #include <inet/common.h>
29*6e91bba0SGirish Moodalbail #include <inet/ip.h>
30*6e91bba0SGirish Moodalbail #include <inet/ip6.h>
31*6e91bba0SGirish Moodalbail #include <netinet/icmp6.h>
32*6e91bba0SGirish Moodalbail #include <inet/ip_stack.h>
33*6e91bba0SGirish Moodalbail #include <inet/rawip_impl.h>
34*6e91bba0SGirish Moodalbail #include <inet/tcp_stack.h>
35*6e91bba0SGirish Moodalbail #include <inet/tcp_impl.h>
36*6e91bba0SGirish Moodalbail #include <inet/udp_impl.h>
37*6e91bba0SGirish Moodalbail #include <inet/sctp/sctp_stack.h>
38*6e91bba0SGirish Moodalbail #include <inet/sctp/sctp_impl.h>
39*6e91bba0SGirish Moodalbail #include <inet/tunables.h>
40*6e91bba0SGirish Moodalbail 
41*6e91bba0SGirish Moodalbail static int
42*6e91bba0SGirish Moodalbail prop_perm2const(mod_prop_info_t *pinfo)
43*6e91bba0SGirish Moodalbail {
44*6e91bba0SGirish Moodalbail 	if (pinfo->mpi_setf == NULL)
45*6e91bba0SGirish Moodalbail 		return (MOD_PROP_PERM_READ);
46*6e91bba0SGirish Moodalbail 	if (pinfo->mpi_getf == NULL)
47*6e91bba0SGirish Moodalbail 		return (MOD_PROP_PERM_WRITE);
48*6e91bba0SGirish Moodalbail 	return (MOD_PROP_PERM_RW);
49*6e91bba0SGirish Moodalbail }
50*6e91bba0SGirish Moodalbail 
51*6e91bba0SGirish Moodalbail /*
52*6e91bba0SGirish Moodalbail  * Modifies the value of the property to default value or to the `pval'
53*6e91bba0SGirish Moodalbail  * specified by the user.
54*6e91bba0SGirish Moodalbail  */
55*6e91bba0SGirish Moodalbail /* ARGSUSED */
56*6e91bba0SGirish Moodalbail int
57*6e91bba0SGirish Moodalbail mod_set_boolean(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
58*6e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
59*6e91bba0SGirish Moodalbail {
60*6e91bba0SGirish Moodalbail 	char 		*end;
61*6e91bba0SGirish Moodalbail 	unsigned long 	new_value;
62*6e91bba0SGirish Moodalbail 
63*6e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
64*6e91bba0SGirish Moodalbail 		pinfo->prop_cur_bval = pinfo->prop_def_bval;
65*6e91bba0SGirish Moodalbail 		return (0);
66*6e91bba0SGirish Moodalbail 	}
67*6e91bba0SGirish Moodalbail 
68*6e91bba0SGirish Moodalbail 	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
69*6e91bba0SGirish Moodalbail 		return (EINVAL);
70*6e91bba0SGirish Moodalbail 	if (new_value != B_TRUE && new_value != B_FALSE)
71*6e91bba0SGirish Moodalbail 		return (EINVAL);
72*6e91bba0SGirish Moodalbail 	pinfo->prop_cur_bval = new_value;
73*6e91bba0SGirish Moodalbail 	return (0);
74*6e91bba0SGirish Moodalbail }
75*6e91bba0SGirish Moodalbail 
76*6e91bba0SGirish Moodalbail /*
77*6e91bba0SGirish Moodalbail  * Retrieves property permission, default value, current value or possible
78*6e91bba0SGirish Moodalbail  * values for those properties whose value type is boolean_t.
79*6e91bba0SGirish Moodalbail  */
80*6e91bba0SGirish Moodalbail /* ARGSUSED */
81*6e91bba0SGirish Moodalbail int
82*6e91bba0SGirish Moodalbail mod_get_boolean(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
83*6e91bba0SGirish Moodalbail     void *pval, uint_t psize, uint_t flags)
84*6e91bba0SGirish Moodalbail {
85*6e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
86*6e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
87*6e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
88*6e91bba0SGirish Moodalbail 	size_t		nbytes;
89*6e91bba0SGirish Moodalbail 
90*6e91bba0SGirish Moodalbail 	bzero(pval, psize);
91*6e91bba0SGirish Moodalbail 	if (get_perm)
92*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
93*6e91bba0SGirish Moodalbail 	else if (get_range)
94*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE);
95*6e91bba0SGirish Moodalbail 	else if (get_def)
96*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval);
97*6e91bba0SGirish Moodalbail 	else
98*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval);
99*6e91bba0SGirish Moodalbail 	if (nbytes >= psize)
100*6e91bba0SGirish Moodalbail 		return (ENOBUFS);
101*6e91bba0SGirish Moodalbail 	return (0);
102*6e91bba0SGirish Moodalbail }
103*6e91bba0SGirish Moodalbail 
104*6e91bba0SGirish Moodalbail /*
105*6e91bba0SGirish Moodalbail  * Modifies the value of the property to default value or to the `pval'
106*6e91bba0SGirish Moodalbail  * specified by the user.
107*6e91bba0SGirish Moodalbail  */
108*6e91bba0SGirish Moodalbail /* ARGSUSED */
109*6e91bba0SGirish Moodalbail int
110*6e91bba0SGirish Moodalbail mod_set_uint32(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
111*6e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
112*6e91bba0SGirish Moodalbail {
113*6e91bba0SGirish Moodalbail 	char 		*end;
114*6e91bba0SGirish Moodalbail 	unsigned long 	new_value;
115*6e91bba0SGirish Moodalbail 
116*6e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
117*6e91bba0SGirish Moodalbail 		pinfo->prop_cur_uval = pinfo->prop_def_uval;
118*6e91bba0SGirish Moodalbail 		return (0);
119*6e91bba0SGirish Moodalbail 	}
120*6e91bba0SGirish Moodalbail 
121*6e91bba0SGirish Moodalbail 	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
122*6e91bba0SGirish Moodalbail 		return (EINVAL);
123*6e91bba0SGirish Moodalbail 	if (new_value < pinfo->prop_min_uval ||
124*6e91bba0SGirish Moodalbail 	    new_value > pinfo->prop_max_uval) {
125*6e91bba0SGirish Moodalbail 		return (ERANGE);
126*6e91bba0SGirish Moodalbail 	}
127*6e91bba0SGirish Moodalbail 	pinfo->prop_cur_uval = (uint32_t)new_value;
128*6e91bba0SGirish Moodalbail 	return (0);
129*6e91bba0SGirish Moodalbail }
130*6e91bba0SGirish Moodalbail 
131*6e91bba0SGirish Moodalbail /*
132*6e91bba0SGirish Moodalbail  * Rounds up the value to make it multiple of 8.
133*6e91bba0SGirish Moodalbail  */
134*6e91bba0SGirish Moodalbail /* ARGSUSED */
135*6e91bba0SGirish Moodalbail int
136*6e91bba0SGirish Moodalbail mod_set_aligned(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
137*6e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
138*6e91bba0SGirish Moodalbail {
139*6e91bba0SGirish Moodalbail 	int	err;
140*6e91bba0SGirish Moodalbail 
141*6e91bba0SGirish Moodalbail 	if ((err = mod_set_uint32(cbarg, cr, pinfo, ifname, pval, flags)) != 0)
142*6e91bba0SGirish Moodalbail 		return (err);
143*6e91bba0SGirish Moodalbail 
144*6e91bba0SGirish Moodalbail 	/* if required, align the value to multiple of 8 */
145*6e91bba0SGirish Moodalbail 	if (pinfo->prop_cur_uval & 0x7) {
146*6e91bba0SGirish Moodalbail 		pinfo->prop_cur_uval &= ~0x7;
147*6e91bba0SGirish Moodalbail 		pinfo->prop_cur_uval += 0x8;
148*6e91bba0SGirish Moodalbail 	}
149*6e91bba0SGirish Moodalbail 
150*6e91bba0SGirish Moodalbail 	return (0);
151*6e91bba0SGirish Moodalbail }
152*6e91bba0SGirish Moodalbail 
153*6e91bba0SGirish Moodalbail /*
154*6e91bba0SGirish Moodalbail  * Retrieves property permission, default value, current value or possible
155*6e91bba0SGirish Moodalbail  * values for those properties whose value type is uint32_t.
156*6e91bba0SGirish Moodalbail  */
157*6e91bba0SGirish Moodalbail /* ARGSUSED */
158*6e91bba0SGirish Moodalbail int
159*6e91bba0SGirish Moodalbail mod_get_uint32(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
160*6e91bba0SGirish Moodalbail     void *pval, uint_t psize, uint_t flags)
161*6e91bba0SGirish Moodalbail {
162*6e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
163*6e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
164*6e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
165*6e91bba0SGirish Moodalbail 	size_t		nbytes;
166*6e91bba0SGirish Moodalbail 
167*6e91bba0SGirish Moodalbail 	bzero(pval, psize);
168*6e91bba0SGirish Moodalbail 	if (get_perm)
169*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
170*6e91bba0SGirish Moodalbail 	else if (get_range)
171*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u-%u",
172*6e91bba0SGirish Moodalbail 		    pinfo->prop_min_uval, pinfo->prop_max_uval);
173*6e91bba0SGirish Moodalbail 	else if (get_def)
174*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
175*6e91bba0SGirish Moodalbail 	else
176*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval);
177*6e91bba0SGirish Moodalbail 	if (nbytes >= psize)
178*6e91bba0SGirish Moodalbail 		return (ENOBUFS);
179*6e91bba0SGirish Moodalbail 	return (0);
180*6e91bba0SGirish Moodalbail }
181*6e91bba0SGirish Moodalbail 
182*6e91bba0SGirish Moodalbail /*
183*6e91bba0SGirish Moodalbail  * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
184*6e91bba0SGirish Moodalbail  * backward compatibility with /sbin/ndd.
185*6e91bba0SGirish Moodalbail  */
186*6e91bba0SGirish Moodalbail /* ARGSUSED */
187*6e91bba0SGirish Moodalbail int
188*6e91bba0SGirish Moodalbail mod_get_allprop(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
189*6e91bba0SGirish Moodalbail     void *val, uint_t psize, uint_t flags)
190*6e91bba0SGirish Moodalbail {
191*6e91bba0SGirish Moodalbail 	char		*pval = val;
192*6e91bba0SGirish Moodalbail 	mod_prop_info_t	*ptbl, *prop;
193*6e91bba0SGirish Moodalbail 	ip_stack_t	*ipst;
194*6e91bba0SGirish Moodalbail 	tcp_stack_t	*tcps;
195*6e91bba0SGirish Moodalbail 	sctp_stack_t	*sctps;
196*6e91bba0SGirish Moodalbail 	udp_stack_t	*us;
197*6e91bba0SGirish Moodalbail 	icmp_stack_t	*is;
198*6e91bba0SGirish Moodalbail 	uint_t		size;
199*6e91bba0SGirish Moodalbail 	size_t		nbytes = 0, tbytes = 0;
200*6e91bba0SGirish Moodalbail 
201*6e91bba0SGirish Moodalbail 	bzero(pval, psize);
202*6e91bba0SGirish Moodalbail 	size = psize;
203*6e91bba0SGirish Moodalbail 
204*6e91bba0SGirish Moodalbail 	switch (pinfo->mpi_proto) {
205*6e91bba0SGirish Moodalbail 	case MOD_PROTO_IP:
206*6e91bba0SGirish Moodalbail 	case MOD_PROTO_IPV4:
207*6e91bba0SGirish Moodalbail 	case MOD_PROTO_IPV6:
208*6e91bba0SGirish Moodalbail 		ipst = (ip_stack_t *)cbarg;
209*6e91bba0SGirish Moodalbail 		ptbl = ipst->ips_propinfo_tbl;
210*6e91bba0SGirish Moodalbail 		break;
211*6e91bba0SGirish Moodalbail 	case MOD_PROTO_RAWIP:
212*6e91bba0SGirish Moodalbail 		is = (icmp_stack_t *)cbarg;
213*6e91bba0SGirish Moodalbail 		ptbl = is->is_propinfo_tbl;
214*6e91bba0SGirish Moodalbail 		break;
215*6e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
216*6e91bba0SGirish Moodalbail 		tcps = (tcp_stack_t *)cbarg;
217*6e91bba0SGirish Moodalbail 		ptbl = tcps->tcps_propinfo_tbl;
218*6e91bba0SGirish Moodalbail 		break;
219*6e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
220*6e91bba0SGirish Moodalbail 		us = (udp_stack_t *)cbarg;
221*6e91bba0SGirish Moodalbail 		ptbl = us->us_propinfo_tbl;
222*6e91bba0SGirish Moodalbail 		break;
223*6e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
224*6e91bba0SGirish Moodalbail 		sctps = (sctp_stack_t *)cbarg;
225*6e91bba0SGirish Moodalbail 		ptbl = sctps->sctps_propinfo_tbl;
226*6e91bba0SGirish Moodalbail 		break;
227*6e91bba0SGirish Moodalbail 	default:
228*6e91bba0SGirish Moodalbail 		return (EINVAL);
229*6e91bba0SGirish Moodalbail 	}
230*6e91bba0SGirish Moodalbail 
231*6e91bba0SGirish Moodalbail 	for (prop = ptbl; prop->mpi_name != NULL; prop++) {
232*6e91bba0SGirish Moodalbail 		if (prop->mpi_name[0] == '\0' ||
233*6e91bba0SGirish Moodalbail 		    strcmp(prop->mpi_name, "mtu") == 0 ||
234*6e91bba0SGirish Moodalbail 		    strcmp(prop->mpi_name, "?") == 0)
235*6e91bba0SGirish Moodalbail 			continue;
236*6e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name,
237*6e91bba0SGirish Moodalbail 		    prop->mpi_proto, prop_perm2const(prop));
238*6e91bba0SGirish Moodalbail 		size -= nbytes + 1;
239*6e91bba0SGirish Moodalbail 		pval += nbytes + 1;
240*6e91bba0SGirish Moodalbail 		tbytes += nbytes + 1;
241*6e91bba0SGirish Moodalbail 		if (tbytes >= psize) {
242*6e91bba0SGirish Moodalbail 			/* Buffer overflow, stop copying information */
243*6e91bba0SGirish Moodalbail 			return (ENOBUFS);
244*6e91bba0SGirish Moodalbail 		}
245*6e91bba0SGirish Moodalbail 	}
246*6e91bba0SGirish Moodalbail 	return (0);
247*6e91bba0SGirish Moodalbail }
248*6e91bba0SGirish Moodalbail 
249*6e91bba0SGirish Moodalbail /*
250*6e91bba0SGirish Moodalbail  * Hold a lock while changing *_epriv_ports to prevent multiple
251*6e91bba0SGirish Moodalbail  * threads from changing it at the same time.
252*6e91bba0SGirish Moodalbail  */
253*6e91bba0SGirish Moodalbail /* ARGSUSED */
254*6e91bba0SGirish Moodalbail int
255*6e91bba0SGirish Moodalbail mod_set_extra_privports(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
256*6e91bba0SGirish Moodalbail     const char *ifname, const void* val, uint_t flags)
257*6e91bba0SGirish Moodalbail {
258*6e91bba0SGirish Moodalbail 	uint_t		proto = pinfo->mpi_proto;
259*6e91bba0SGirish Moodalbail 	tcp_stack_t	*tcps;
260*6e91bba0SGirish Moodalbail 	sctp_stack_t	*sctps;
261*6e91bba0SGirish Moodalbail 	udp_stack_t	*us;
262*6e91bba0SGirish Moodalbail 	unsigned long	new_value;
263*6e91bba0SGirish Moodalbail 	char		*end;
264*6e91bba0SGirish Moodalbail 	kmutex_t	*lock;
265*6e91bba0SGirish Moodalbail 	uint_t		i, nports;
266*6e91bba0SGirish Moodalbail 	in_port_t	*ports;
267*6e91bba0SGirish Moodalbail 	boolean_t	def = (flags & MOD_PROP_DEFAULT);
268*6e91bba0SGirish Moodalbail 	const char	*pval = val;
269*6e91bba0SGirish Moodalbail 
270*6e91bba0SGirish Moodalbail 	if (!def) {
271*6e91bba0SGirish Moodalbail 		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
272*6e91bba0SGirish Moodalbail 		    *end != '\0') {
273*6e91bba0SGirish Moodalbail 			return (EINVAL);
274*6e91bba0SGirish Moodalbail 		}
275*6e91bba0SGirish Moodalbail 
276*6e91bba0SGirish Moodalbail 		if (new_value < pinfo->prop_min_uval ||
277*6e91bba0SGirish Moodalbail 		    new_value > pinfo->prop_max_uval) {
278*6e91bba0SGirish Moodalbail 			return (ERANGE);
279*6e91bba0SGirish Moodalbail 		}
280*6e91bba0SGirish Moodalbail 	}
281*6e91bba0SGirish Moodalbail 
282*6e91bba0SGirish Moodalbail 	switch (proto) {
283*6e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
284*6e91bba0SGirish Moodalbail 		tcps = (tcp_stack_t *)cbarg;
285*6e91bba0SGirish Moodalbail 		lock = &tcps->tcps_epriv_port_lock;
286*6e91bba0SGirish Moodalbail 		ports = tcps->tcps_g_epriv_ports;
287*6e91bba0SGirish Moodalbail 		nports = tcps->tcps_g_num_epriv_ports;
288*6e91bba0SGirish Moodalbail 		break;
289*6e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
290*6e91bba0SGirish Moodalbail 		us = (udp_stack_t *)cbarg;
291*6e91bba0SGirish Moodalbail 		lock = &us->us_epriv_port_lock;
292*6e91bba0SGirish Moodalbail 		ports = us->us_epriv_ports;
293*6e91bba0SGirish Moodalbail 		nports = us->us_num_epriv_ports;
294*6e91bba0SGirish Moodalbail 		break;
295*6e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
296*6e91bba0SGirish Moodalbail 		sctps = (sctp_stack_t *)cbarg;
297*6e91bba0SGirish Moodalbail 		lock = &sctps->sctps_epriv_port_lock;
298*6e91bba0SGirish Moodalbail 		ports = sctps->sctps_g_epriv_ports;
299*6e91bba0SGirish Moodalbail 		nports = sctps->sctps_g_num_epriv_ports;
300*6e91bba0SGirish Moodalbail 		break;
301*6e91bba0SGirish Moodalbail 	default:
302*6e91bba0SGirish Moodalbail 		return (ENOTSUP);
303*6e91bba0SGirish Moodalbail 	}
304*6e91bba0SGirish Moodalbail 
305*6e91bba0SGirish Moodalbail 	mutex_enter(lock);
306*6e91bba0SGirish Moodalbail 
307*6e91bba0SGirish Moodalbail 	/* if MOD_PROP_DEFAULT is set then reset the ports list to default */
308*6e91bba0SGirish Moodalbail 	if (def) {
309*6e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++)
310*6e91bba0SGirish Moodalbail 			ports[i] = 0;
311*6e91bba0SGirish Moodalbail 		ports[0] = ULP_DEF_EPRIV_PORT1;
312*6e91bba0SGirish Moodalbail 		ports[1] = ULP_DEF_EPRIV_PORT2;
313*6e91bba0SGirish Moodalbail 		mutex_exit(lock);
314*6e91bba0SGirish Moodalbail 		return (0);
315*6e91bba0SGirish Moodalbail 	}
316*6e91bba0SGirish Moodalbail 
317*6e91bba0SGirish Moodalbail 	/* Check if the value is already in the list */
318*6e91bba0SGirish Moodalbail 	for (i = 0; i < nports; i++) {
319*6e91bba0SGirish Moodalbail 		if (new_value == ports[i])
320*6e91bba0SGirish Moodalbail 			break;
321*6e91bba0SGirish Moodalbail 	}
322*6e91bba0SGirish Moodalbail 
323*6e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_REMOVE) {
324*6e91bba0SGirish Moodalbail 		if (i == nports) {
325*6e91bba0SGirish Moodalbail 			mutex_exit(lock);
326*6e91bba0SGirish Moodalbail 			return (ESRCH);
327*6e91bba0SGirish Moodalbail 		}
328*6e91bba0SGirish Moodalbail 		/* Clear the value */
329*6e91bba0SGirish Moodalbail 		ports[i] = 0;
330*6e91bba0SGirish Moodalbail 	} else if (flags & MOD_PROP_APPEND) {
331*6e91bba0SGirish Moodalbail 		if (i != nports) {
332*6e91bba0SGirish Moodalbail 			mutex_exit(lock);
333*6e91bba0SGirish Moodalbail 			return (EEXIST);
334*6e91bba0SGirish Moodalbail 		}
335*6e91bba0SGirish Moodalbail 
336*6e91bba0SGirish Moodalbail 		/* Find an empty slot */
337*6e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++) {
338*6e91bba0SGirish Moodalbail 			if (ports[i] == 0)
339*6e91bba0SGirish Moodalbail 				break;
340*6e91bba0SGirish Moodalbail 		}
341*6e91bba0SGirish Moodalbail 		if (i == nports) {
342*6e91bba0SGirish Moodalbail 			mutex_exit(lock);
343*6e91bba0SGirish Moodalbail 			return (EOVERFLOW);
344*6e91bba0SGirish Moodalbail 		}
345*6e91bba0SGirish Moodalbail 		/* Set the new value */
346*6e91bba0SGirish Moodalbail 		ports[i] = (in_port_t)new_value;
347*6e91bba0SGirish Moodalbail 	} else {
348*6e91bba0SGirish Moodalbail 		/*
349*6e91bba0SGirish Moodalbail 		 * If the user used 'assignment' modifier.
350*6e91bba0SGirish Moodalbail 		 * For eg:
351*6e91bba0SGirish Moodalbail 		 * 	# ipadm set-prop -p extra_priv_ports=3001 tcp
352*6e91bba0SGirish Moodalbail 		 *
353*6e91bba0SGirish Moodalbail 		 * We clear all the ports and then just add 3001.
354*6e91bba0SGirish Moodalbail 		 */
355*6e91bba0SGirish Moodalbail 		ASSERT(flags == MOD_PROP_ACTIVE);
356*6e91bba0SGirish Moodalbail 		for (i = 0; i < nports; i++)
357*6e91bba0SGirish Moodalbail 			ports[i] = 0;
358*6e91bba0SGirish Moodalbail 		ports[0] = (in_port_t)new_value;
359*6e91bba0SGirish Moodalbail 	}
360*6e91bba0SGirish Moodalbail 
361*6e91bba0SGirish Moodalbail 	mutex_exit(lock);
362*6e91bba0SGirish Moodalbail 	return (0);
363*6e91bba0SGirish Moodalbail }
364*6e91bba0SGirish Moodalbail 
365*6e91bba0SGirish Moodalbail /*
366*6e91bba0SGirish Moodalbail  * Note: No locks are held when inspecting *_epriv_ports
367*6e91bba0SGirish Moodalbail  * but instead the code relies on:
368*6e91bba0SGirish Moodalbail  * - the fact that the address of the array and its size never changes
369*6e91bba0SGirish Moodalbail  * - the atomic assignment of the elements of the array
370*6e91bba0SGirish Moodalbail  */
371*6e91bba0SGirish Moodalbail /* ARGSUSED */
372*6e91bba0SGirish Moodalbail int
373*6e91bba0SGirish Moodalbail mod_get_extra_privports(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
374*6e91bba0SGirish Moodalbail     void *val, uint_t psize, uint_t flags)
375*6e91bba0SGirish Moodalbail {
376*6e91bba0SGirish Moodalbail 	uint_t		proto = pinfo->mpi_proto;
377*6e91bba0SGirish Moodalbail 	tcp_stack_t	*tcps;
378*6e91bba0SGirish Moodalbail 	sctp_stack_t	*sctps;
379*6e91bba0SGirish Moodalbail 	udp_stack_t	*us;
380*6e91bba0SGirish Moodalbail 	uint_t		i, nports, size;
381*6e91bba0SGirish Moodalbail 	in_port_t	*ports;
382*6e91bba0SGirish Moodalbail 	char		*pval = val;
383*6e91bba0SGirish Moodalbail 	size_t		nbytes = 0, tbytes = 0;
384*6e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
385*6e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
386*6e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
387*6e91bba0SGirish Moodalbail 
388*6e91bba0SGirish Moodalbail 	bzero(pval, psize);
389*6e91bba0SGirish Moodalbail 	size = psize;
390*6e91bba0SGirish Moodalbail 
391*6e91bba0SGirish Moodalbail 	if (get_def) {
392*6e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1,
393*6e91bba0SGirish Moodalbail 		    ULP_DEF_EPRIV_PORT2);
394*6e91bba0SGirish Moodalbail 		goto ret;
395*6e91bba0SGirish Moodalbail 	} else if (get_perm) {
396*6e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
397*6e91bba0SGirish Moodalbail 		goto ret;
398*6e91bba0SGirish Moodalbail 	}
399*6e91bba0SGirish Moodalbail 
400*6e91bba0SGirish Moodalbail 	switch (proto) {
401*6e91bba0SGirish Moodalbail 	case MOD_PROTO_TCP:
402*6e91bba0SGirish Moodalbail 		tcps = (tcp_stack_t *)cbarg;
403*6e91bba0SGirish Moodalbail 		ports = tcps->tcps_g_epriv_ports;
404*6e91bba0SGirish Moodalbail 		nports = tcps->tcps_g_num_epriv_ports;
405*6e91bba0SGirish Moodalbail 		break;
406*6e91bba0SGirish Moodalbail 	case MOD_PROTO_UDP:
407*6e91bba0SGirish Moodalbail 		us = (udp_stack_t *)cbarg;
408*6e91bba0SGirish Moodalbail 		ports = us->us_epriv_ports;
409*6e91bba0SGirish Moodalbail 		nports = us->us_num_epriv_ports;
410*6e91bba0SGirish Moodalbail 		break;
411*6e91bba0SGirish Moodalbail 	case MOD_PROTO_SCTP:
412*6e91bba0SGirish Moodalbail 		sctps = (sctp_stack_t *)cbarg;
413*6e91bba0SGirish Moodalbail 		ports = sctps->sctps_g_epriv_ports;
414*6e91bba0SGirish Moodalbail 		nports = sctps->sctps_g_num_epriv_ports;
415*6e91bba0SGirish Moodalbail 		break;
416*6e91bba0SGirish Moodalbail 	default:
417*6e91bba0SGirish Moodalbail 		return (ENOTSUP);
418*6e91bba0SGirish Moodalbail 	}
419*6e91bba0SGirish Moodalbail 
420*6e91bba0SGirish Moodalbail 	if (get_range) {
421*6e91bba0SGirish Moodalbail 		tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
422*6e91bba0SGirish Moodalbail 		    pinfo->prop_max_uval);
423*6e91bba0SGirish Moodalbail 		goto ret;
424*6e91bba0SGirish Moodalbail 	}
425*6e91bba0SGirish Moodalbail 
426*6e91bba0SGirish Moodalbail 	for (i = 0; i < nports; i++) {
427*6e91bba0SGirish Moodalbail 		if (ports[i] != 0) {
428*6e91bba0SGirish Moodalbail 			if (psize == size)
429*6e91bba0SGirish Moodalbail 				nbytes = snprintf(pval, size, "%u", ports[i]);
430*6e91bba0SGirish Moodalbail 			else
431*6e91bba0SGirish Moodalbail 				nbytes = snprintf(pval, size, ",%u", ports[i]);
432*6e91bba0SGirish Moodalbail 			size -= nbytes;
433*6e91bba0SGirish Moodalbail 			pval += nbytes;
434*6e91bba0SGirish Moodalbail 			tbytes += nbytes;
435*6e91bba0SGirish Moodalbail 			if (tbytes >= psize)
436*6e91bba0SGirish Moodalbail 				return (ENOBUFS);
437*6e91bba0SGirish Moodalbail 		}
438*6e91bba0SGirish Moodalbail 	}
439*6e91bba0SGirish Moodalbail 	return (0);
440*6e91bba0SGirish Moodalbail ret:
441*6e91bba0SGirish Moodalbail 	if (tbytes >= psize)
442*6e91bba0SGirish Moodalbail 		return (ENOBUFS);
443*6e91bba0SGirish Moodalbail 	return (0);
444*6e91bba0SGirish Moodalbail }
445