Print this page
3942 inject sanity into ipadm tcp buffer size properties
3943 _snd_lowat_fraction tcp tunable has no effect
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Peng Dai <peng.dai@delphix.com>


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 1990 Mentat Inc.

  24  */
  25 
  26 #include <inet/tunables.h>
  27 #include <sys/md5.h>
  28 #include <inet/common.h>
  29 #include <inet/ip.h>
  30 #include <inet/ip6.h>
  31 #include <netinet/icmp6.h>
  32 #include <inet/ip_stack.h>
  33 #include <inet/rawip_impl.h>
  34 #include <inet/tcp_stack.h>
  35 #include <inet/tcp_impl.h>
  36 #include <inet/udp_impl.h>
  37 #include <inet/sctp/sctp_stack.h>
  38 #include <inet/sctp/sctp_impl.h>
  39 #include <inet/tunables.h>
  40 


















  41 static int
  42 prop_perm2const(mod_prop_info_t *pinfo)
  43 {
  44         if (pinfo->mpi_setf == NULL)
  45                 return (MOD_PROP_PERM_READ);
  46         if (pinfo->mpi_getf == NULL)
  47                 return (MOD_PROP_PERM_WRITE);
  48         return (MOD_PROP_PERM_RW);
  49 }
  50 
  51 /*
  52  * Modifies the value of the property to default value or to the `pval'
  53  * specified by the user.
  54  */
  55 /* ARGSUSED */
  56 int
  57 mod_set_boolean(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
  58     const char *ifname, const void* pval, uint_t flags)
  59 {
  60         char            *end;
  61         unsigned long   new_value;
  62 
  63         if (flags & MOD_PROP_DEFAULT) {
  64                 pinfo->prop_cur_bval = pinfo->prop_def_bval;
  65                 return (0);
  66         }
  67 
  68         if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
  69                 return (EINVAL);
  70         if (new_value != B_TRUE && new_value != B_FALSE)
  71                 return (EINVAL);
  72         pinfo->prop_cur_bval = new_value;
  73         return (0);
  74 }
  75 
  76 /*
  77  * Retrieves property permission, default value, current value or possible
  78  * values for those properties whose value type is boolean_t.
  79  */
  80 /* ARGSUSED */
  81 int
  82 mod_get_boolean(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
  83     void *pval, uint_t psize, uint_t flags)
  84 {
  85         boolean_t       get_def = (flags & MOD_PROP_DEFAULT);
  86         boolean_t       get_perm = (flags & MOD_PROP_PERM);
  87         boolean_t       get_range = (flags & MOD_PROP_POSSIBLE);
  88         size_t          nbytes;
  89 
  90         bzero(pval, psize);
  91         if (get_perm)
  92                 nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
  93         else if (get_range)
  94                 nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE);
  95         else if (get_def)
  96                 nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval);
  97         else
  98                 nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval);
  99         if (nbytes >= psize)
 100                 return (ENOBUFS);
 101         return (0);
 102 }


 111                 *new_value = pinfo->prop_def_uval;
 112                 return (0);
 113         }
 114 
 115         if (ddi_strtoul(pval, &end, 10, (ulong_t *)new_value) != 0 ||
 116             *end != '\0')
 117                 return (EINVAL);
 118         if (*new_value < pinfo->prop_min_uval ||
 119             *new_value > pinfo->prop_max_uval) {
 120                 return (ERANGE);
 121         }
 122         return (0);
 123 }
 124 
 125 /*
 126  * Modifies the value of the property to default value or to the `pval'
 127  * specified by the user.
 128  */
 129 /* ARGSUSED */
 130 int
 131 mod_set_uint32(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
 132     const char *ifname, const void *pval, uint_t flags)
 133 {
 134         unsigned long   new_value;
 135         int             err;
 136 
 137         if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
 138                 return (err);
 139         pinfo->prop_cur_uval = (uint32_t)new_value;
 140         return (0);
 141 }
 142 
 143 /*
 144  * Rounds up the value to make it multiple of 8.
 145  */
 146 /* ARGSUSED */
 147 int
 148 mod_set_aligned(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
 149     const char *ifname, const void* pval, uint_t flags)
 150 {
 151         int     err;
 152 
 153         if ((err = mod_set_uint32(cbarg, cr, pinfo, ifname, pval, flags)) != 0)
 154                 return (err);
 155 
 156         /* if required, align the value to multiple of 8 */
 157         if (pinfo->prop_cur_uval & 0x7) {
 158                 pinfo->prop_cur_uval &= ~0x7;
 159                 pinfo->prop_cur_uval += 0x8;
 160         }
 161 
 162         return (0);
 163 }
 164 
 165 /*
 166  * Retrieves property permission, default value, current value or possible
 167  * values for those properties whose value type is uint32_t.
 168  */
 169 /* ARGSUSED */
 170 int
 171 mod_get_uint32(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
 172     void *pval, uint_t psize, uint_t flags)
 173 {
 174         boolean_t       get_def = (flags & MOD_PROP_DEFAULT);
 175         boolean_t       get_perm = (flags & MOD_PROP_PERM);
 176         boolean_t       get_range = (flags & MOD_PROP_POSSIBLE);
 177         size_t          nbytes;
 178 
 179         bzero(pval, psize);
 180         if (get_perm)
 181                 nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
 182         else if (get_range)
 183                 nbytes = snprintf(pval, psize, "%u-%u",
 184                     pinfo->prop_min_uval, pinfo->prop_max_uval);
 185         else if (get_def)
 186                 nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
 187         else
 188                 nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval);
 189         if (nbytes >= psize)
 190                 return (ENOBUFS);
 191         return (0);
 192 }
 193 
 194 /*






































































 195  * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
 196  * backward compatibility with /sbin/ndd.
 197  */
 198 /* ARGSUSED */
 199 int
 200 mod_get_allprop(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
 201     void *val, uint_t psize, uint_t flags)
 202 {
 203         char            *pval = val;
 204         mod_prop_info_t *ptbl, *prop;
 205         ip_stack_t      *ipst;
 206         tcp_stack_t     *tcps;
 207         sctp_stack_t    *sctps;
 208         udp_stack_t     *us;
 209         icmp_stack_t    *is;
 210         uint_t          size;
 211         size_t          nbytes = 0, tbytes = 0;
 212 
 213         bzero(pval, psize);
 214         size = psize;
 215 
 216         switch (pinfo->mpi_proto) {
 217         case MOD_PROTO_IP:
 218         case MOD_PROTO_IPV4:
 219         case MOD_PROTO_IPV6:
 220                 ipst = (ip_stack_t *)cbarg;
 221                 ptbl = ipst->ips_propinfo_tbl;
 222                 break;
 223         case MOD_PROTO_RAWIP:
 224                 is = (icmp_stack_t *)cbarg;
 225                 ptbl = is->is_propinfo_tbl;
 226                 break;
 227         case MOD_PROTO_TCP:
 228                 tcps = (tcp_stack_t *)cbarg;
 229                 ptbl = tcps->tcps_propinfo_tbl;
 230                 break;
 231         case MOD_PROTO_UDP:
 232                 us = (udp_stack_t *)cbarg;
 233                 ptbl = us->us_propinfo_tbl;
 234                 break;
 235         case MOD_PROTO_SCTP:
 236                 sctps = (sctp_stack_t *)cbarg;
 237                 ptbl = sctps->sctps_propinfo_tbl;
 238                 break;
 239         default:
 240                 return (EINVAL);
 241         }
 242 
 243         for (prop = ptbl; prop->mpi_name != NULL; prop++) {
 244                 if (prop->mpi_name[0] == '\0' ||
 245                     strcmp(prop->mpi_name, "?") == 0) {
 246                         continue;
 247                 }
 248                 nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name,
 249                     prop->mpi_proto, prop_perm2const(prop));
 250                 size -= nbytes + 1;
 251                 pval += nbytes + 1;
 252                 tbytes += nbytes + 1;
 253                 if (tbytes >= psize) {
 254                         /* Buffer overflow, stop copying information */
 255                         return (ENOBUFS);
 256                 }
 257         }
 258         return (0);
 259 }
 260 
 261 /*
 262  * Hold a lock while changing *_epriv_ports to prevent multiple
 263  * threads from changing it at the same time.
 264  */
 265 /* ARGSUSED */
 266 int
 267 mod_set_extra_privports(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
 268     const char *ifname, const void* val, uint_t flags)
 269 {
 270         uint_t          proto = pinfo->mpi_proto;
 271         tcp_stack_t     *tcps;
 272         sctp_stack_t    *sctps;
 273         udp_stack_t     *us;
 274         unsigned long   new_value;
 275         char            *end;
 276         kmutex_t        *lock;
 277         uint_t          i, nports;
 278         in_port_t       *ports;
 279         boolean_t       def = (flags & MOD_PROP_DEFAULT);
 280         const char      *pval = val;
 281 
 282         if (!def) {
 283                 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
 284                     *end != '\0') {
 285                         return (EINVAL);
 286                 }
 287 
 288                 if (new_value < pinfo->prop_min_uval ||
 289                     new_value > pinfo->prop_max_uval) {
 290                         return (ERANGE);
 291                 }
 292         }
 293 
 294         switch (proto) {
 295         case MOD_PROTO_TCP:
 296                 tcps = (tcp_stack_t *)cbarg;
 297                 lock = &tcps->tcps_epriv_port_lock;
 298                 ports = tcps->tcps_g_epriv_ports;
 299                 nports = tcps->tcps_g_num_epriv_ports;
 300                 break;
 301         case MOD_PROTO_UDP:
 302                 us = (udp_stack_t *)cbarg;
 303                 lock = &us->us_epriv_port_lock;
 304                 ports = us->us_epriv_ports;
 305                 nports = us->us_num_epriv_ports;
 306                 break;
 307         case MOD_PROTO_SCTP:
 308                 sctps = (sctp_stack_t *)cbarg;
 309                 lock = &sctps->sctps_epriv_port_lock;
 310                 ports = sctps->sctps_g_epriv_ports;
 311                 nports = sctps->sctps_g_num_epriv_ports;
 312                 break;
 313         default:
 314                 return (ENOTSUP);
 315         }
 316 
 317         mutex_enter(lock);
 318 
 319         /* if MOD_PROP_DEFAULT is set then reset the ports list to default */
 320         if (def) {
 321                 for (i = 0; i < nports; i++)
 322                         ports[i] = 0;
 323                 ports[0] = ULP_DEF_EPRIV_PORT1;
 324                 ports[1] = ULP_DEF_EPRIV_PORT2;
 325                 mutex_exit(lock);
 326                 return (0);
 327         }
 328 


 365                  * We clear all the ports and then just add 3001.
 366                  */
 367                 ASSERT(flags == MOD_PROP_ACTIVE);
 368                 for (i = 0; i < nports; i++)
 369                         ports[i] = 0;
 370                 ports[0] = (in_port_t)new_value;
 371         }
 372 
 373         mutex_exit(lock);
 374         return (0);
 375 }
 376 
 377 /*
 378  * Note: No locks are held when inspecting *_epriv_ports
 379  * but instead the code relies on:
 380  * - the fact that the address of the array and its size never changes
 381  * - the atomic assignment of the elements of the array
 382  */
 383 /* ARGSUSED */
 384 int
 385 mod_get_extra_privports(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
 386     void *val, uint_t psize, uint_t flags)
 387 {
 388         uint_t          proto = pinfo->mpi_proto;
 389         tcp_stack_t     *tcps;
 390         sctp_stack_t    *sctps;
 391         udp_stack_t     *us;
 392         uint_t          i, nports, size;
 393         in_port_t       *ports;
 394         char            *pval = val;
 395         size_t          nbytes = 0, tbytes = 0;
 396         boolean_t       get_def = (flags & MOD_PROP_DEFAULT);
 397         boolean_t       get_perm = (flags & MOD_PROP_PERM);
 398         boolean_t       get_range = (flags & MOD_PROP_POSSIBLE);
 399 
 400         bzero(pval, psize);
 401         size = psize;
 402 
 403         if (get_def) {
 404                 tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1,
 405                     ULP_DEF_EPRIV_PORT2);
 406                 goto ret;
 407         } else if (get_perm) {
 408                 tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
 409                 goto ret;
 410         }
 411 
 412         switch (proto) {
 413         case MOD_PROTO_TCP:
 414                 tcps = (tcp_stack_t *)cbarg;
 415                 ports = tcps->tcps_g_epriv_ports;
 416                 nports = tcps->tcps_g_num_epriv_ports;
 417                 break;
 418         case MOD_PROTO_UDP:
 419                 us = (udp_stack_t *)cbarg;
 420                 ports = us->us_epriv_ports;
 421                 nports = us->us_num_epriv_ports;
 422                 break;
 423         case MOD_PROTO_SCTP:
 424                 sctps = (sctp_stack_t *)cbarg;
 425                 ports = sctps->sctps_g_epriv_ports;
 426                 nports = sctps->sctps_g_num_epriv_ports;
 427                 break;
 428         default:
 429                 return (ENOTSUP);
 430         }
 431 
 432         if (get_range) {
 433                 tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
 434                     pinfo->prop_max_uval);
 435                 goto ret;
 436         }
 437 
 438         for (i = 0; i < nports; i++) {
 439                 if (ports[i] != 0) {
 440                         if (psize == size)
 441                                 nbytes = snprintf(pval, size, "%u", ports[i]);
 442                         else
 443                                 nbytes = snprintf(pval, size, ",%u", ports[i]);
 444                         size -= nbytes;


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 1990 Mentat Inc.
  24  * Copyright (c) 2013 by Delphix. All rights reserved.
  25  */
  26 
  27 #include <inet/tunables.h>
  28 #include <sys/md5.h>
  29 #include <inet/common.h>
  30 #include <inet/ip.h>
  31 #include <inet/ip6.h>
  32 #include <netinet/icmp6.h>
  33 #include <inet/ip_stack.h>
  34 #include <inet/rawip_impl.h>
  35 #include <inet/tcp_stack.h>
  36 #include <inet/tcp_impl.h>
  37 #include <inet/udp_impl.h>
  38 #include <inet/sctp/sctp_stack.h>
  39 #include <inet/sctp/sctp_impl.h>
  40 #include <inet/tunables.h>
  41 
  42 mod_prop_info_t *
  43 mod_prop_lookup(mod_prop_info_t ptbl[], const char *prop_name, uint_t proto)
  44 {
  45         mod_prop_info_t *pinfo;
  46 
  47         /*
  48          * Walk the ptbl array looking for a property that has the requested
  49          * name and protocol number.  Note that we assume that all protocol
  50          * tables are terminated by an entry with a NULL property name.
  51          */
  52         for (pinfo = ptbl; pinfo->mpi_name != NULL; pinfo++) {
  53                 if (strcmp(pinfo->mpi_name, prop_name) == 0 &&
  54                     pinfo->mpi_proto == proto)
  55                         return (pinfo);
  56         }
  57         return (NULL);
  58 }
  59 
  60 static int
  61 prop_perm2const(mod_prop_info_t *pinfo)
  62 {
  63         if (pinfo->mpi_setf == NULL)
  64                 return (MOD_PROP_PERM_READ);
  65         if (pinfo->mpi_getf == NULL)
  66                 return (MOD_PROP_PERM_WRITE);
  67         return (MOD_PROP_PERM_RW);
  68 }
  69 
  70 /*
  71  * Modifies the value of the property to default value or to the `pval'
  72  * specified by the user.
  73  */
  74 /* ARGSUSED */
  75 int
  76 mod_set_boolean(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
  77     const char *ifname, const void* pval, uint_t flags)
  78 {
  79         char            *end;
  80         unsigned long   new_value;
  81 
  82         if (flags & MOD_PROP_DEFAULT) {
  83                 pinfo->prop_cur_bval = pinfo->prop_def_bval;
  84                 return (0);
  85         }
  86 
  87         if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
  88                 return (EINVAL);
  89         if (new_value != B_TRUE && new_value != B_FALSE)
  90                 return (EINVAL);
  91         pinfo->prop_cur_bval = new_value;
  92         return (0);
  93 }
  94 
  95 /*
  96  * Retrieves property permission, default value, current value or possible
  97  * values for those properties whose value type is boolean_t.
  98  */
  99 /* ARGSUSED */
 100 int
 101 mod_get_boolean(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
 102     void *pval, uint_t psize, uint_t flags)
 103 {
 104         boolean_t       get_def = (flags & MOD_PROP_DEFAULT);
 105         boolean_t       get_perm = (flags & MOD_PROP_PERM);
 106         boolean_t       get_range = (flags & MOD_PROP_POSSIBLE);
 107         size_t          nbytes;
 108 
 109         bzero(pval, psize);
 110         if (get_perm)
 111                 nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
 112         else if (get_range)
 113                 nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE);
 114         else if (get_def)
 115                 nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval);
 116         else
 117                 nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval);
 118         if (nbytes >= psize)
 119                 return (ENOBUFS);
 120         return (0);
 121 }


 130                 *new_value = pinfo->prop_def_uval;
 131                 return (0);
 132         }
 133 
 134         if (ddi_strtoul(pval, &end, 10, (ulong_t *)new_value) != 0 ||
 135             *end != '\0')
 136                 return (EINVAL);
 137         if (*new_value < pinfo->prop_min_uval ||
 138             *new_value > pinfo->prop_max_uval) {
 139                 return (ERANGE);
 140         }
 141         return (0);
 142 }
 143 
 144 /*
 145  * Modifies the value of the property to default value or to the `pval'
 146  * specified by the user.
 147  */
 148 /* ARGSUSED */
 149 int
 150 mod_set_uint32(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
 151     const char *ifname, const void *pval, uint_t flags)
 152 {
 153         unsigned long   new_value;
 154         int             err;
 155 
 156         if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
 157                 return (err);
 158         pinfo->prop_cur_uval = (uint32_t)new_value;
 159         return (0);
 160 }
 161 
 162 /*
 163  * Rounds up the value to make it multiple of 8.
 164  */
 165 /* ARGSUSED */
 166 int
 167 mod_set_aligned(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
 168     const char *ifname, const void* pval, uint_t flags)
 169 {
 170         int     err;
 171 
 172         if ((err = mod_set_uint32(stack, cr, pinfo, ifname, pval, flags)) != 0)
 173                 return (err);
 174 
 175         /* if required, align the value to multiple of 8 */
 176         if (pinfo->prop_cur_uval & 0x7) {
 177                 pinfo->prop_cur_uval &= ~0x7;
 178                 pinfo->prop_cur_uval += 0x8;
 179         }
 180 
 181         return (0);
 182 }
 183 
 184 /*
 185  * Retrieves property permission, default value, current value or possible
 186  * values for those properties whose value type is uint32_t.
 187  */
 188 /* ARGSUSED */
 189 int
 190 mod_get_uint32(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
 191     void *pval, uint_t psize, uint_t flags)
 192 {
 193         boolean_t       get_def = (flags & MOD_PROP_DEFAULT);
 194         boolean_t       get_perm = (flags & MOD_PROP_PERM);
 195         boolean_t       get_range = (flags & MOD_PROP_POSSIBLE);
 196         size_t          nbytes;
 197 
 198         bzero(pval, psize);
 199         if (get_perm)
 200                 nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
 201         else if (get_range)
 202                 nbytes = snprintf(pval, psize, "%u-%u",
 203                     pinfo->prop_min_uval, pinfo->prop_max_uval);
 204         else if (get_def)
 205                 nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
 206         else
 207                 nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval);
 208         if (nbytes >= psize)
 209                 return (ENOBUFS);
 210         return (0);
 211 }
 212 
 213 /*
 214  * The range of the buffer size properties has a static lower bound configured
 215  * in the property info structure of the property itself, and a dynamic upper
 216  * bound.  The upper bound is the current value of the "max_buf" property
 217  * in the appropriate protocol property table.
 218  */
 219 static void
 220 mod_get_buf_prop_range(mod_prop_info_t ptbl[], mod_prop_info_t *pinfo,
 221     uint32_t *min, uint32_t *max)
 222 {
 223         mod_prop_info_t *maxbuf_pinfo = mod_prop_lookup(ptbl, "max_buf",
 224             pinfo->mpi_proto);
 225 
 226         *min = pinfo->prop_min_uval;
 227         *max = maxbuf_pinfo->prop_cur_uval;
 228 }
 229 
 230 /*
 231  * Modifies the value of the buffer size property to its default value or to
 232  * the value specified by the user.  This is similar to mod_set_uint32() except
 233  * that the value has a dynamically bounded range (see mod_get_buf_prop_range()
 234  * for details).
 235  */
 236 /* ARGSUSED */
 237 int
 238 mod_set_buf_prop(mod_prop_info_t ptbl[], netstack_t *stack, cred_t *cr,
 239     mod_prop_info_t *pinfo, const char *ifname, const void *pval, uint_t flags)
 240 {
 241         unsigned long   new_value;
 242         char            *end;
 243         uint32_t        min, max;
 244 
 245         if (flags & MOD_PROP_DEFAULT) {
 246                 pinfo->prop_cur_uval = pinfo->prop_def_uval;
 247                 return (0);
 248         }
 249 
 250         if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
 251                 return (EINVAL);
 252 
 253         mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
 254         if (new_value < min || new_value > max)
 255                 return (ERANGE);
 256 
 257         pinfo->prop_cur_uval = new_value;
 258         return (0);
 259 }
 260 
 261 /*
 262  * Retrieves property permissions, default value, current value, or possible
 263  * values for buffer size properties.  While these properties have integer
 264  * values, they have a dynamic range (see mod_get_buf_prop_range() for
 265  * details).  As such, they need to be handled differently.
 266  */
 267 int
 268 mod_get_buf_prop(mod_prop_info_t ptbl[], netstack_t *stack,
 269     mod_prop_info_t *pinfo, const char *ifname, void *pval, uint_t psize,
 270     uint_t flags)
 271 {
 272         size_t nbytes;
 273         uint32_t min, max;
 274 
 275         if (flags & MOD_PROP_POSSIBLE) {
 276                 mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
 277                 nbytes = snprintf(pval, psize, "%u-%u", min, max);
 278                 return (nbytes < psize ? 0 : ENOBUFS);
 279         }
 280         return (mod_get_uint32(stack, pinfo, ifname, pval, psize, flags));
 281 }
 282 
 283 /*
 284  * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
 285  * backward compatibility with /sbin/ndd.
 286  */
 287 /* ARGSUSED */
 288 int
 289 mod_get_allprop(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
 290     void *val, uint_t psize, uint_t flags)
 291 {
 292         char            *pval = val;
 293         mod_prop_info_t *ptbl, *prop;





 294         uint_t          size;
 295         size_t          nbytes = 0, tbytes = 0;
 296 
 297         bzero(pval, psize);
 298         size = psize;
 299 
 300         switch (pinfo->mpi_proto) {
 301         case MOD_PROTO_IP:
 302         case MOD_PROTO_IPV4:
 303         case MOD_PROTO_IPV6:
 304                 ptbl = stack->netstack_ip->ips_propinfo_tbl;

 305                 break;
 306         case MOD_PROTO_RAWIP:
 307                 ptbl = stack->netstack_icmp->is_propinfo_tbl;

 308                 break;
 309         case MOD_PROTO_TCP:
 310                 ptbl = stack->netstack_tcp->tcps_propinfo_tbl;

 311                 break;
 312         case MOD_PROTO_UDP:
 313                 ptbl = stack->netstack_udp->us_propinfo_tbl;

 314                 break;
 315         case MOD_PROTO_SCTP:
 316                 ptbl = stack->netstack_sctp->sctps_propinfo_tbl;

 317                 break;
 318         default:
 319                 return (EINVAL);
 320         }
 321 
 322         for (prop = ptbl; prop->mpi_name != NULL; prop++) {
 323                 if (prop->mpi_name[0] == '\0' ||
 324                     strcmp(prop->mpi_name, "?") == 0) {
 325                         continue;
 326                 }
 327                 nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name,
 328                     prop->mpi_proto, prop_perm2const(prop));
 329                 size -= nbytes + 1;
 330                 pval += nbytes + 1;
 331                 tbytes += nbytes + 1;
 332                 if (tbytes >= psize) {
 333                         /* Buffer overflow, stop copying information */
 334                         return (ENOBUFS);
 335                 }
 336         }
 337         return (0);
 338 }
 339 
 340 /*
 341  * Hold a lock while changing *_epriv_ports to prevent multiple
 342  * threads from changing it at the same time.
 343  */
 344 /* ARGSUSED */
 345 int
 346 mod_set_extra_privports(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
 347     const char *ifname, const void* val, uint_t flags)
 348 {
 349         uint_t          proto = pinfo->mpi_proto;
 350         tcp_stack_t     *tcps;
 351         sctp_stack_t    *sctps;
 352         udp_stack_t     *us;
 353         unsigned long   new_value;
 354         char            *end;
 355         kmutex_t        *lock;
 356         uint_t          i, nports;
 357         in_port_t       *ports;
 358         boolean_t       def = (flags & MOD_PROP_DEFAULT);
 359         const char      *pval = val;
 360 
 361         if (!def) {
 362                 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
 363                     *end != '\0') {
 364                         return (EINVAL);
 365                 }
 366 
 367                 if (new_value < pinfo->prop_min_uval ||
 368                     new_value > pinfo->prop_max_uval) {
 369                         return (ERANGE);
 370                 }
 371         }
 372 
 373         switch (proto) {
 374         case MOD_PROTO_TCP:
 375                 tcps = stack->netstack_tcp;
 376                 lock = &tcps->tcps_epriv_port_lock;
 377                 ports = tcps->tcps_g_epriv_ports;
 378                 nports = tcps->tcps_g_num_epriv_ports;
 379                 break;
 380         case MOD_PROTO_UDP:
 381                 us = stack->netstack_udp;
 382                 lock = &us->us_epriv_port_lock;
 383                 ports = us->us_epriv_ports;
 384                 nports = us->us_num_epriv_ports;
 385                 break;
 386         case MOD_PROTO_SCTP:
 387                 sctps = stack->netstack_sctp;
 388                 lock = &sctps->sctps_epriv_port_lock;
 389                 ports = sctps->sctps_g_epriv_ports;
 390                 nports = sctps->sctps_g_num_epriv_ports;
 391                 break;
 392         default:
 393                 return (ENOTSUP);
 394         }
 395 
 396         mutex_enter(lock);
 397 
 398         /* if MOD_PROP_DEFAULT is set then reset the ports list to default */
 399         if (def) {
 400                 for (i = 0; i < nports; i++)
 401                         ports[i] = 0;
 402                 ports[0] = ULP_DEF_EPRIV_PORT1;
 403                 ports[1] = ULP_DEF_EPRIV_PORT2;
 404                 mutex_exit(lock);
 405                 return (0);
 406         }
 407 


 444                  * We clear all the ports and then just add 3001.
 445                  */
 446                 ASSERT(flags == MOD_PROP_ACTIVE);
 447                 for (i = 0; i < nports; i++)
 448                         ports[i] = 0;
 449                 ports[0] = (in_port_t)new_value;
 450         }
 451 
 452         mutex_exit(lock);
 453         return (0);
 454 }
 455 
 456 /*
 457  * Note: No locks are held when inspecting *_epriv_ports
 458  * but instead the code relies on:
 459  * - the fact that the address of the array and its size never changes
 460  * - the atomic assignment of the elements of the array
 461  */
 462 /* ARGSUSED */
 463 int
 464 mod_get_extra_privports(netstack_t *stack, mod_prop_info_t *pinfo,
 465     const char *ifname, void *val, uint_t psize, uint_t flags)
 466 {
 467         uint_t          proto = pinfo->mpi_proto;
 468         tcp_stack_t     *tcps;
 469         sctp_stack_t    *sctps;
 470         udp_stack_t     *us;
 471         uint_t          i, nports, size;
 472         in_port_t       *ports;
 473         char            *pval = val;
 474         size_t          nbytes = 0, tbytes = 0;
 475         boolean_t       get_def = (flags & MOD_PROP_DEFAULT);
 476         boolean_t       get_perm = (flags & MOD_PROP_PERM);
 477         boolean_t       get_range = (flags & MOD_PROP_POSSIBLE);
 478 
 479         bzero(pval, psize);
 480         size = psize;
 481 
 482         if (get_def) {
 483                 tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1,
 484                     ULP_DEF_EPRIV_PORT2);
 485                 goto ret;
 486         } else if (get_perm) {
 487                 tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
 488                 goto ret;
 489         }
 490 
 491         switch (proto) {
 492         case MOD_PROTO_TCP:
 493                 tcps = stack->netstack_tcp;
 494                 ports = tcps->tcps_g_epriv_ports;
 495                 nports = tcps->tcps_g_num_epriv_ports;
 496                 break;
 497         case MOD_PROTO_UDP:
 498                 us = stack->netstack_udp;
 499                 ports = us->us_epriv_ports;
 500                 nports = us->us_num_epriv_ports;
 501                 break;
 502         case MOD_PROTO_SCTP:
 503                 sctps = stack->netstack_sctp;
 504                 ports = sctps->sctps_g_epriv_ports;
 505                 nports = sctps->sctps_g_num_epriv_ports;
 506                 break;
 507         default:
 508                 return (ENOTSUP);
 509         }
 510 
 511         if (get_range) {
 512                 tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
 513                     pinfo->prop_max_uval);
 514                 goto ret;
 515         }
 516 
 517         for (i = 0; i < nports; i++) {
 518                 if (ports[i] != 0) {
 519                         if (psize == size)
 520                                 nbytes = snprintf(pval, size, "%u", ports[i]);
 521                         else
 522                                 nbytes = snprintf(pval, size, ",%u", ports[i]);
 523                         size -= nbytes;