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 /* 22*f1e9465bSSowmini Varadhan * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. 23*f1e9465bSSowmini Varadhan * Copyright (c) 1990 Mentat Inc. 246e91bba0SGirish Moodalbail */ 256e91bba0SGirish Moodalbail 266e91bba0SGirish Moodalbail #include <inet/tunables.h> 276e91bba0SGirish Moodalbail #include <sys/md5.h> 286e91bba0SGirish Moodalbail #include <inet/common.h> 296e91bba0SGirish Moodalbail #include <inet/ip.h> 306e91bba0SGirish Moodalbail #include <inet/ip6.h> 316e91bba0SGirish Moodalbail #include <netinet/icmp6.h> 326e91bba0SGirish Moodalbail #include <inet/ip_stack.h> 336e91bba0SGirish Moodalbail #include <inet/rawip_impl.h> 346e91bba0SGirish Moodalbail #include <inet/tcp_stack.h> 356e91bba0SGirish Moodalbail #include <inet/tcp_impl.h> 366e91bba0SGirish Moodalbail #include <inet/udp_impl.h> 376e91bba0SGirish Moodalbail #include <inet/sctp/sctp_stack.h> 386e91bba0SGirish Moodalbail #include <inet/sctp/sctp_impl.h> 396e91bba0SGirish Moodalbail #include <inet/tunables.h> 406e91bba0SGirish Moodalbail 416e91bba0SGirish Moodalbail static int 426e91bba0SGirish Moodalbail prop_perm2const(mod_prop_info_t *pinfo) 436e91bba0SGirish Moodalbail { 446e91bba0SGirish Moodalbail if (pinfo->mpi_setf == NULL) 456e91bba0SGirish Moodalbail return (MOD_PROP_PERM_READ); 466e91bba0SGirish Moodalbail if (pinfo->mpi_getf == NULL) 476e91bba0SGirish Moodalbail return (MOD_PROP_PERM_WRITE); 486e91bba0SGirish Moodalbail return (MOD_PROP_PERM_RW); 496e91bba0SGirish Moodalbail } 506e91bba0SGirish Moodalbail 516e91bba0SGirish Moodalbail /* 526e91bba0SGirish Moodalbail * Modifies the value of the property to default value or to the `pval' 536e91bba0SGirish Moodalbail * specified by the user. 546e91bba0SGirish Moodalbail */ 556e91bba0SGirish Moodalbail /* ARGSUSED */ 566e91bba0SGirish Moodalbail int 576e91bba0SGirish Moodalbail mod_set_boolean(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo, 586e91bba0SGirish Moodalbail const char *ifname, const void* pval, uint_t flags) 596e91bba0SGirish Moodalbail { 606e91bba0SGirish Moodalbail char *end; 616e91bba0SGirish Moodalbail unsigned long new_value; 626e91bba0SGirish Moodalbail 636e91bba0SGirish Moodalbail if (flags & MOD_PROP_DEFAULT) { 646e91bba0SGirish Moodalbail pinfo->prop_cur_bval = pinfo->prop_def_bval; 656e91bba0SGirish Moodalbail return (0); 666e91bba0SGirish Moodalbail } 676e91bba0SGirish Moodalbail 686e91bba0SGirish Moodalbail if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0') 696e91bba0SGirish Moodalbail return (EINVAL); 706e91bba0SGirish Moodalbail if (new_value != B_TRUE && new_value != B_FALSE) 716e91bba0SGirish Moodalbail return (EINVAL); 726e91bba0SGirish Moodalbail pinfo->prop_cur_bval = new_value; 736e91bba0SGirish Moodalbail return (0); 746e91bba0SGirish Moodalbail } 756e91bba0SGirish Moodalbail 766e91bba0SGirish Moodalbail /* 776e91bba0SGirish Moodalbail * Retrieves property permission, default value, current value or possible 786e91bba0SGirish Moodalbail * values for those properties whose value type is boolean_t. 796e91bba0SGirish Moodalbail */ 806e91bba0SGirish Moodalbail /* ARGSUSED */ 816e91bba0SGirish Moodalbail int 826e91bba0SGirish Moodalbail mod_get_boolean(void *cbarg, mod_prop_info_t *pinfo, const char *ifname, 836e91bba0SGirish Moodalbail void *pval, uint_t psize, uint_t flags) 846e91bba0SGirish Moodalbail { 856e91bba0SGirish Moodalbail boolean_t get_def = (flags & MOD_PROP_DEFAULT); 866e91bba0SGirish Moodalbail boolean_t get_perm = (flags & MOD_PROP_PERM); 876e91bba0SGirish Moodalbail boolean_t get_range = (flags & MOD_PROP_POSSIBLE); 886e91bba0SGirish Moodalbail size_t nbytes; 896e91bba0SGirish Moodalbail 906e91bba0SGirish Moodalbail bzero(pval, psize); 916e91bba0SGirish Moodalbail if (get_perm) 926e91bba0SGirish Moodalbail nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo)); 936e91bba0SGirish Moodalbail else if (get_range) 946e91bba0SGirish Moodalbail nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE); 956e91bba0SGirish Moodalbail else if (get_def) 966e91bba0SGirish Moodalbail nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval); 976e91bba0SGirish Moodalbail else 986e91bba0SGirish Moodalbail nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval); 996e91bba0SGirish Moodalbail if (nbytes >= psize) 1006e91bba0SGirish Moodalbail return (ENOBUFS); 1016e91bba0SGirish Moodalbail return (0); 1026e91bba0SGirish Moodalbail } 1036e91bba0SGirish Moodalbail 1046e91bba0SGirish Moodalbail int 105*f1e9465bSSowmini Varadhan mod_uint32_value(const void *pval, mod_prop_info_t *pinfo, uint_t flags, 106*f1e9465bSSowmini Varadhan ulong_t *new_value) 1076e91bba0SGirish Moodalbail { 1086e91bba0SGirish Moodalbail char *end; 1096e91bba0SGirish Moodalbail 1106e91bba0SGirish Moodalbail if (flags & MOD_PROP_DEFAULT) { 111*f1e9465bSSowmini Varadhan *new_value = pinfo->prop_def_uval; 1126e91bba0SGirish Moodalbail return (0); 1136e91bba0SGirish Moodalbail } 1146e91bba0SGirish Moodalbail 115*f1e9465bSSowmini Varadhan if (ddi_strtoul(pval, &end, 10, (ulong_t *)new_value) != 0 || 116*f1e9465bSSowmini Varadhan *end != '\0') 1176e91bba0SGirish Moodalbail return (EINVAL); 118*f1e9465bSSowmini Varadhan if (*new_value < pinfo->prop_min_uval || 119*f1e9465bSSowmini Varadhan *new_value > pinfo->prop_max_uval) { 1206e91bba0SGirish Moodalbail return (ERANGE); 1216e91bba0SGirish Moodalbail } 122*f1e9465bSSowmini Varadhan return (0); 123*f1e9465bSSowmini Varadhan } 124*f1e9465bSSowmini Varadhan 125*f1e9465bSSowmini Varadhan /* 126*f1e9465bSSowmini Varadhan * Modifies the value of the property to default value or to the `pval' 127*f1e9465bSSowmini Varadhan * specified by the user. 128*f1e9465bSSowmini Varadhan */ 129*f1e9465bSSowmini Varadhan /* ARGSUSED */ 130*f1e9465bSSowmini Varadhan int 131*f1e9465bSSowmini Varadhan mod_set_uint32(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo, 132*f1e9465bSSowmini Varadhan const char *ifname, const void *pval, uint_t flags) 133*f1e9465bSSowmini Varadhan { 134*f1e9465bSSowmini Varadhan unsigned long new_value; 135*f1e9465bSSowmini Varadhan int err; 136*f1e9465bSSowmini Varadhan 137*f1e9465bSSowmini Varadhan if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0) 138*f1e9465bSSowmini Varadhan return (err); 1396e91bba0SGirish Moodalbail pinfo->prop_cur_uval = (uint32_t)new_value; 1406e91bba0SGirish Moodalbail return (0); 1416e91bba0SGirish Moodalbail } 1426e91bba0SGirish Moodalbail 1436e91bba0SGirish Moodalbail /* 1446e91bba0SGirish Moodalbail * Rounds up the value to make it multiple of 8. 1456e91bba0SGirish Moodalbail */ 1466e91bba0SGirish Moodalbail /* ARGSUSED */ 1476e91bba0SGirish Moodalbail int 1486e91bba0SGirish Moodalbail mod_set_aligned(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo, 1496e91bba0SGirish Moodalbail const char *ifname, const void* pval, uint_t flags) 1506e91bba0SGirish Moodalbail { 1516e91bba0SGirish Moodalbail int err; 1526e91bba0SGirish Moodalbail 1536e91bba0SGirish Moodalbail if ((err = mod_set_uint32(cbarg, cr, pinfo, ifname, pval, flags)) != 0) 1546e91bba0SGirish Moodalbail return (err); 1556e91bba0SGirish Moodalbail 1566e91bba0SGirish Moodalbail /* if required, align the value to multiple of 8 */ 1576e91bba0SGirish Moodalbail if (pinfo->prop_cur_uval & 0x7) { 1586e91bba0SGirish Moodalbail pinfo->prop_cur_uval &= ~0x7; 1596e91bba0SGirish Moodalbail pinfo->prop_cur_uval += 0x8; 1606e91bba0SGirish Moodalbail } 1616e91bba0SGirish Moodalbail 1626e91bba0SGirish Moodalbail return (0); 1636e91bba0SGirish Moodalbail } 1646e91bba0SGirish Moodalbail 1656e91bba0SGirish Moodalbail /* 1666e91bba0SGirish Moodalbail * Retrieves property permission, default value, current value or possible 1676e91bba0SGirish Moodalbail * values for those properties whose value type is uint32_t. 1686e91bba0SGirish Moodalbail */ 1696e91bba0SGirish Moodalbail /* ARGSUSED */ 1706e91bba0SGirish Moodalbail int 1716e91bba0SGirish Moodalbail mod_get_uint32(void *cbarg, mod_prop_info_t *pinfo, const char *ifname, 1726e91bba0SGirish Moodalbail void *pval, uint_t psize, uint_t flags) 1736e91bba0SGirish Moodalbail { 1746e91bba0SGirish Moodalbail boolean_t get_def = (flags & MOD_PROP_DEFAULT); 1756e91bba0SGirish Moodalbail boolean_t get_perm = (flags & MOD_PROP_PERM); 1766e91bba0SGirish Moodalbail boolean_t get_range = (flags & MOD_PROP_POSSIBLE); 1776e91bba0SGirish Moodalbail size_t nbytes; 1786e91bba0SGirish Moodalbail 1796e91bba0SGirish Moodalbail bzero(pval, psize); 1806e91bba0SGirish Moodalbail if (get_perm) 1816e91bba0SGirish Moodalbail nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo)); 1826e91bba0SGirish Moodalbail else if (get_range) 1836e91bba0SGirish Moodalbail nbytes = snprintf(pval, psize, "%u-%u", 1846e91bba0SGirish Moodalbail pinfo->prop_min_uval, pinfo->prop_max_uval); 1856e91bba0SGirish Moodalbail else if (get_def) 1866e91bba0SGirish Moodalbail nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval); 1876e91bba0SGirish Moodalbail else 1886e91bba0SGirish Moodalbail nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval); 1896e91bba0SGirish Moodalbail if (nbytes >= psize) 1906e91bba0SGirish Moodalbail return (ENOBUFS); 1916e91bba0SGirish Moodalbail return (0); 1926e91bba0SGirish Moodalbail } 1936e91bba0SGirish Moodalbail 1946e91bba0SGirish Moodalbail /* 1956e91bba0SGirish Moodalbail * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for 1966e91bba0SGirish Moodalbail * backward compatibility with /sbin/ndd. 1976e91bba0SGirish Moodalbail */ 1986e91bba0SGirish Moodalbail /* ARGSUSED */ 1996e91bba0SGirish Moodalbail int 2006e91bba0SGirish Moodalbail mod_get_allprop(void *cbarg, mod_prop_info_t *pinfo, const char *ifname, 2016e91bba0SGirish Moodalbail void *val, uint_t psize, uint_t flags) 2026e91bba0SGirish Moodalbail { 2036e91bba0SGirish Moodalbail char *pval = val; 2046e91bba0SGirish Moodalbail mod_prop_info_t *ptbl, *prop; 2056e91bba0SGirish Moodalbail ip_stack_t *ipst; 2066e91bba0SGirish Moodalbail tcp_stack_t *tcps; 2076e91bba0SGirish Moodalbail sctp_stack_t *sctps; 2086e91bba0SGirish Moodalbail udp_stack_t *us; 2096e91bba0SGirish Moodalbail icmp_stack_t *is; 2106e91bba0SGirish Moodalbail uint_t size; 2116e91bba0SGirish Moodalbail size_t nbytes = 0, tbytes = 0; 2126e91bba0SGirish Moodalbail 2136e91bba0SGirish Moodalbail bzero(pval, psize); 2146e91bba0SGirish Moodalbail size = psize; 2156e91bba0SGirish Moodalbail 2166e91bba0SGirish Moodalbail switch (pinfo->mpi_proto) { 2176e91bba0SGirish Moodalbail case MOD_PROTO_IP: 2186e91bba0SGirish Moodalbail case MOD_PROTO_IPV4: 2196e91bba0SGirish Moodalbail case MOD_PROTO_IPV6: 2206e91bba0SGirish Moodalbail ipst = (ip_stack_t *)cbarg; 2216e91bba0SGirish Moodalbail ptbl = ipst->ips_propinfo_tbl; 2226e91bba0SGirish Moodalbail break; 2236e91bba0SGirish Moodalbail case MOD_PROTO_RAWIP: 2246e91bba0SGirish Moodalbail is = (icmp_stack_t *)cbarg; 2256e91bba0SGirish Moodalbail ptbl = is->is_propinfo_tbl; 2266e91bba0SGirish Moodalbail break; 2276e91bba0SGirish Moodalbail case MOD_PROTO_TCP: 2286e91bba0SGirish Moodalbail tcps = (tcp_stack_t *)cbarg; 2296e91bba0SGirish Moodalbail ptbl = tcps->tcps_propinfo_tbl; 2306e91bba0SGirish Moodalbail break; 2316e91bba0SGirish Moodalbail case MOD_PROTO_UDP: 2326e91bba0SGirish Moodalbail us = (udp_stack_t *)cbarg; 2336e91bba0SGirish Moodalbail ptbl = us->us_propinfo_tbl; 2346e91bba0SGirish Moodalbail break; 2356e91bba0SGirish Moodalbail case MOD_PROTO_SCTP: 2366e91bba0SGirish Moodalbail sctps = (sctp_stack_t *)cbarg; 2376e91bba0SGirish Moodalbail ptbl = sctps->sctps_propinfo_tbl; 2386e91bba0SGirish Moodalbail break; 2396e91bba0SGirish Moodalbail default: 2406e91bba0SGirish Moodalbail return (EINVAL); 2416e91bba0SGirish Moodalbail } 2426e91bba0SGirish Moodalbail 2436e91bba0SGirish Moodalbail for (prop = ptbl; prop->mpi_name != NULL; prop++) { 2446e91bba0SGirish Moodalbail if (prop->mpi_name[0] == '\0' || 2456e91bba0SGirish Moodalbail strcmp(prop->mpi_name, "mtu") == 0 || 2466e91bba0SGirish Moodalbail strcmp(prop->mpi_name, "?") == 0) 2476e91bba0SGirish Moodalbail continue; 2486e91bba0SGirish Moodalbail nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name, 2496e91bba0SGirish Moodalbail prop->mpi_proto, prop_perm2const(prop)); 2506e91bba0SGirish Moodalbail size -= nbytes + 1; 2516e91bba0SGirish Moodalbail pval += nbytes + 1; 2526e91bba0SGirish Moodalbail tbytes += nbytes + 1; 2536e91bba0SGirish Moodalbail if (tbytes >= psize) { 2546e91bba0SGirish Moodalbail /* Buffer overflow, stop copying information */ 2556e91bba0SGirish Moodalbail return (ENOBUFS); 2566e91bba0SGirish Moodalbail } 2576e91bba0SGirish Moodalbail } 2586e91bba0SGirish Moodalbail return (0); 2596e91bba0SGirish Moodalbail } 2606e91bba0SGirish Moodalbail 2616e91bba0SGirish Moodalbail /* 2626e91bba0SGirish Moodalbail * Hold a lock while changing *_epriv_ports to prevent multiple 2636e91bba0SGirish Moodalbail * threads from changing it at the same time. 2646e91bba0SGirish Moodalbail */ 2656e91bba0SGirish Moodalbail /* ARGSUSED */ 2666e91bba0SGirish Moodalbail int 2676e91bba0SGirish Moodalbail mod_set_extra_privports(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo, 2686e91bba0SGirish Moodalbail const char *ifname, const void* val, uint_t flags) 2696e91bba0SGirish Moodalbail { 2706e91bba0SGirish Moodalbail uint_t proto = pinfo->mpi_proto; 2716e91bba0SGirish Moodalbail tcp_stack_t *tcps; 2726e91bba0SGirish Moodalbail sctp_stack_t *sctps; 2736e91bba0SGirish Moodalbail udp_stack_t *us; 2746e91bba0SGirish Moodalbail unsigned long new_value; 2756e91bba0SGirish Moodalbail char *end; 2766e91bba0SGirish Moodalbail kmutex_t *lock; 2776e91bba0SGirish Moodalbail uint_t i, nports; 2786e91bba0SGirish Moodalbail in_port_t *ports; 2796e91bba0SGirish Moodalbail boolean_t def = (flags & MOD_PROP_DEFAULT); 2806e91bba0SGirish Moodalbail const char *pval = val; 2816e91bba0SGirish Moodalbail 2826e91bba0SGirish Moodalbail if (!def) { 2836e91bba0SGirish Moodalbail if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || 2846e91bba0SGirish Moodalbail *end != '\0') { 2856e91bba0SGirish Moodalbail return (EINVAL); 2866e91bba0SGirish Moodalbail } 2876e91bba0SGirish Moodalbail 2886e91bba0SGirish Moodalbail if (new_value < pinfo->prop_min_uval || 2896e91bba0SGirish Moodalbail new_value > pinfo->prop_max_uval) { 2906e91bba0SGirish Moodalbail return (ERANGE); 2916e91bba0SGirish Moodalbail } 2926e91bba0SGirish Moodalbail } 2936e91bba0SGirish Moodalbail 2946e91bba0SGirish Moodalbail switch (proto) { 2956e91bba0SGirish Moodalbail case MOD_PROTO_TCP: 2966e91bba0SGirish Moodalbail tcps = (tcp_stack_t *)cbarg; 2976e91bba0SGirish Moodalbail lock = &tcps->tcps_epriv_port_lock; 2986e91bba0SGirish Moodalbail ports = tcps->tcps_g_epriv_ports; 2996e91bba0SGirish Moodalbail nports = tcps->tcps_g_num_epriv_ports; 3006e91bba0SGirish Moodalbail break; 3016e91bba0SGirish Moodalbail case MOD_PROTO_UDP: 3026e91bba0SGirish Moodalbail us = (udp_stack_t *)cbarg; 3036e91bba0SGirish Moodalbail lock = &us->us_epriv_port_lock; 3046e91bba0SGirish Moodalbail ports = us->us_epriv_ports; 3056e91bba0SGirish Moodalbail nports = us->us_num_epriv_ports; 3066e91bba0SGirish Moodalbail break; 3076e91bba0SGirish Moodalbail case MOD_PROTO_SCTP: 3086e91bba0SGirish Moodalbail sctps = (sctp_stack_t *)cbarg; 3096e91bba0SGirish Moodalbail lock = &sctps->sctps_epriv_port_lock; 3106e91bba0SGirish Moodalbail ports = sctps->sctps_g_epriv_ports; 3116e91bba0SGirish Moodalbail nports = sctps->sctps_g_num_epriv_ports; 3126e91bba0SGirish Moodalbail break; 3136e91bba0SGirish Moodalbail default: 3146e91bba0SGirish Moodalbail return (ENOTSUP); 3156e91bba0SGirish Moodalbail } 3166e91bba0SGirish Moodalbail 3176e91bba0SGirish Moodalbail mutex_enter(lock); 3186e91bba0SGirish Moodalbail 3196e91bba0SGirish Moodalbail /* if MOD_PROP_DEFAULT is set then reset the ports list to default */ 3206e91bba0SGirish Moodalbail if (def) { 3216e91bba0SGirish Moodalbail for (i = 0; i < nports; i++) 3226e91bba0SGirish Moodalbail ports[i] = 0; 3236e91bba0SGirish Moodalbail ports[0] = ULP_DEF_EPRIV_PORT1; 3246e91bba0SGirish Moodalbail ports[1] = ULP_DEF_EPRIV_PORT2; 3256e91bba0SGirish Moodalbail mutex_exit(lock); 3266e91bba0SGirish Moodalbail return (0); 3276e91bba0SGirish Moodalbail } 3286e91bba0SGirish Moodalbail 3296e91bba0SGirish Moodalbail /* Check if the value is already in the list */ 3306e91bba0SGirish Moodalbail for (i = 0; i < nports; i++) { 3316e91bba0SGirish Moodalbail if (new_value == ports[i]) 3326e91bba0SGirish Moodalbail break; 3336e91bba0SGirish Moodalbail } 3346e91bba0SGirish Moodalbail 3356e91bba0SGirish Moodalbail if (flags & MOD_PROP_REMOVE) { 3366e91bba0SGirish Moodalbail if (i == nports) { 3376e91bba0SGirish Moodalbail mutex_exit(lock); 3386e91bba0SGirish Moodalbail return (ESRCH); 3396e91bba0SGirish Moodalbail } 3406e91bba0SGirish Moodalbail /* Clear the value */ 3416e91bba0SGirish Moodalbail ports[i] = 0; 3426e91bba0SGirish Moodalbail } else if (flags & MOD_PROP_APPEND) { 3436e91bba0SGirish Moodalbail if (i != nports) { 3446e91bba0SGirish Moodalbail mutex_exit(lock); 3456e91bba0SGirish Moodalbail return (EEXIST); 3466e91bba0SGirish Moodalbail } 3476e91bba0SGirish Moodalbail 3486e91bba0SGirish Moodalbail /* Find an empty slot */ 3496e91bba0SGirish Moodalbail for (i = 0; i < nports; i++) { 3506e91bba0SGirish Moodalbail if (ports[i] == 0) 3516e91bba0SGirish Moodalbail break; 3526e91bba0SGirish Moodalbail } 3536e91bba0SGirish Moodalbail if (i == nports) { 3546e91bba0SGirish Moodalbail mutex_exit(lock); 3556e91bba0SGirish Moodalbail return (EOVERFLOW); 3566e91bba0SGirish Moodalbail } 3576e91bba0SGirish Moodalbail /* Set the new value */ 3586e91bba0SGirish Moodalbail ports[i] = (in_port_t)new_value; 3596e91bba0SGirish Moodalbail } else { 3606e91bba0SGirish Moodalbail /* 3616e91bba0SGirish Moodalbail * If the user used 'assignment' modifier. 3626e91bba0SGirish Moodalbail * For eg: 3636e91bba0SGirish Moodalbail * # ipadm set-prop -p extra_priv_ports=3001 tcp 3646e91bba0SGirish Moodalbail * 3656e91bba0SGirish Moodalbail * We clear all the ports and then just add 3001. 3666e91bba0SGirish Moodalbail */ 3676e91bba0SGirish Moodalbail ASSERT(flags == MOD_PROP_ACTIVE); 3686e91bba0SGirish Moodalbail for (i = 0; i < nports; i++) 3696e91bba0SGirish Moodalbail ports[i] = 0; 3706e91bba0SGirish Moodalbail ports[0] = (in_port_t)new_value; 3716e91bba0SGirish Moodalbail } 3726e91bba0SGirish Moodalbail 3736e91bba0SGirish Moodalbail mutex_exit(lock); 3746e91bba0SGirish Moodalbail return (0); 3756e91bba0SGirish Moodalbail } 3766e91bba0SGirish Moodalbail 3776e91bba0SGirish Moodalbail /* 3786e91bba0SGirish Moodalbail * Note: No locks are held when inspecting *_epriv_ports 3796e91bba0SGirish Moodalbail * but instead the code relies on: 3806e91bba0SGirish Moodalbail * - the fact that the address of the array and its size never changes 3816e91bba0SGirish Moodalbail * - the atomic assignment of the elements of the array 3826e91bba0SGirish Moodalbail */ 3836e91bba0SGirish Moodalbail /* ARGSUSED */ 3846e91bba0SGirish Moodalbail int 3856e91bba0SGirish Moodalbail mod_get_extra_privports(void *cbarg, mod_prop_info_t *pinfo, const char *ifname, 3866e91bba0SGirish Moodalbail void *val, uint_t psize, uint_t flags) 3876e91bba0SGirish Moodalbail { 3886e91bba0SGirish Moodalbail uint_t proto = pinfo->mpi_proto; 3896e91bba0SGirish Moodalbail tcp_stack_t *tcps; 3906e91bba0SGirish Moodalbail sctp_stack_t *sctps; 3916e91bba0SGirish Moodalbail udp_stack_t *us; 3926e91bba0SGirish Moodalbail uint_t i, nports, size; 3936e91bba0SGirish Moodalbail in_port_t *ports; 3946e91bba0SGirish Moodalbail char *pval = val; 3956e91bba0SGirish Moodalbail size_t nbytes = 0, tbytes = 0; 3966e91bba0SGirish Moodalbail boolean_t get_def = (flags & MOD_PROP_DEFAULT); 3976e91bba0SGirish Moodalbail boolean_t get_perm = (flags & MOD_PROP_PERM); 3986e91bba0SGirish Moodalbail boolean_t get_range = (flags & MOD_PROP_POSSIBLE); 3996e91bba0SGirish Moodalbail 4006e91bba0SGirish Moodalbail bzero(pval, psize); 4016e91bba0SGirish Moodalbail size = psize; 4026e91bba0SGirish Moodalbail 4036e91bba0SGirish Moodalbail if (get_def) { 4046e91bba0SGirish Moodalbail tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1, 4056e91bba0SGirish Moodalbail ULP_DEF_EPRIV_PORT2); 4066e91bba0SGirish Moodalbail goto ret; 4076e91bba0SGirish Moodalbail } else if (get_perm) { 4086e91bba0SGirish Moodalbail tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW); 4096e91bba0SGirish Moodalbail goto ret; 4106e91bba0SGirish Moodalbail } 4116e91bba0SGirish Moodalbail 4126e91bba0SGirish Moodalbail switch (proto) { 4136e91bba0SGirish Moodalbail case MOD_PROTO_TCP: 4146e91bba0SGirish Moodalbail tcps = (tcp_stack_t *)cbarg; 4156e91bba0SGirish Moodalbail ports = tcps->tcps_g_epriv_ports; 4166e91bba0SGirish Moodalbail nports = tcps->tcps_g_num_epriv_ports; 4176e91bba0SGirish Moodalbail break; 4186e91bba0SGirish Moodalbail case MOD_PROTO_UDP: 4196e91bba0SGirish Moodalbail us = (udp_stack_t *)cbarg; 4206e91bba0SGirish Moodalbail ports = us->us_epriv_ports; 4216e91bba0SGirish Moodalbail nports = us->us_num_epriv_ports; 4226e91bba0SGirish Moodalbail break; 4236e91bba0SGirish Moodalbail case MOD_PROTO_SCTP: 4246e91bba0SGirish Moodalbail sctps = (sctp_stack_t *)cbarg; 4256e91bba0SGirish Moodalbail ports = sctps->sctps_g_epriv_ports; 4266e91bba0SGirish Moodalbail nports = sctps->sctps_g_num_epriv_ports; 4276e91bba0SGirish Moodalbail break; 4286e91bba0SGirish Moodalbail default: 4296e91bba0SGirish Moodalbail return (ENOTSUP); 4306e91bba0SGirish Moodalbail } 4316e91bba0SGirish Moodalbail 4326e91bba0SGirish Moodalbail if (get_range) { 4336e91bba0SGirish Moodalbail tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval, 4346e91bba0SGirish Moodalbail pinfo->prop_max_uval); 4356e91bba0SGirish Moodalbail goto ret; 4366e91bba0SGirish Moodalbail } 4376e91bba0SGirish Moodalbail 4386e91bba0SGirish Moodalbail for (i = 0; i < nports; i++) { 4396e91bba0SGirish Moodalbail if (ports[i] != 0) { 4406e91bba0SGirish Moodalbail if (psize == size) 4416e91bba0SGirish Moodalbail nbytes = snprintf(pval, size, "%u", ports[i]); 4426e91bba0SGirish Moodalbail else 4436e91bba0SGirish Moodalbail nbytes = snprintf(pval, size, ",%u", ports[i]); 4446e91bba0SGirish Moodalbail size -= nbytes; 4456e91bba0SGirish Moodalbail pval += nbytes; 4466e91bba0SGirish Moodalbail tbytes += nbytes; 4476e91bba0SGirish Moodalbail if (tbytes >= psize) 4486e91bba0SGirish Moodalbail return (ENOBUFS); 4496e91bba0SGirish Moodalbail } 4506e91bba0SGirish Moodalbail } 4516e91bba0SGirish Moodalbail return (0); 4526e91bba0SGirish Moodalbail ret: 4536e91bba0SGirish Moodalbail if (tbytes >= psize) 4546e91bba0SGirish Moodalbail return (ENOBUFS); 4556e91bba0SGirish Moodalbail return (0); 4566e91bba0SGirish Moodalbail } 457