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 {
796e91bba0SGirish Moodalbail char *end;
806e91bba0SGirish Moodalbail 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
123f1e9465bSSowmini Varadhan 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)
126f1e9465bSSowmini Varadhan {
127f1e9465bSSowmini Varadhan char *end;
128f1e9465bSSowmini Varadhan
129f1e9465bSSowmini Varadhan if (flags & MOD_PROP_DEFAULT) {
130f1e9465bSSowmini Varadhan *new_value = pinfo->prop_def_uval;
131f1e9465bSSowmini Varadhan return (0);
132f1e9465bSSowmini Varadhan }
133f1e9465bSSowmini Varadhan
134f1e9465bSSowmini Varadhan if (ddi_strtoul(pval, &end, 10, (ulong_t *)new_value) != 0 ||
135f1e9465bSSowmini Varadhan *end != '\0')
136f1e9465bSSowmini Varadhan return (EINVAL);
137f1e9465bSSowmini Varadhan if (*new_value < pinfo->prop_min_uval ||
138f1e9465bSSowmini Varadhan *new_value > pinfo->prop_max_uval) {
139f1e9465bSSowmini Varadhan return (ERANGE);
140f1e9465bSSowmini Varadhan }
141f1e9465bSSowmini Varadhan return (0);
142f1e9465bSSowmini Varadhan }
143f1e9465bSSowmini Varadhan
1446e91bba0SGirish Moodalbail /*
1456e91bba0SGirish Moodalbail * Modifies the value of the property to default value or to the `pval'
1466e91bba0SGirish Moodalbail * specified by the user.
1476e91bba0SGirish Moodalbail */
1486e91bba0SGirish Moodalbail /* ARGSUSED */
1496e91bba0SGirish Moodalbail 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,
1516e91bba0SGirish Moodalbail const char *ifname, const void *pval, uint_t flags)
1526e91bba0SGirish Moodalbail {
1536e91bba0SGirish Moodalbail unsigned long new_value;
154f1e9465bSSowmini Varadhan int err;
1556e91bba0SGirish Moodalbail
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
2136e91bba0SGirish Moodalbail /*
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
283*299625c6SSebastien Roy /*
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