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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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