1 /* 2 * CDDL HEADER START 3 * 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 } 122 123 int 124 mod_uint32_value(const void *pval, mod_prop_info_t *pinfo, uint_t flags, 125 ulong_t *new_value) 126 { 127 char *end; 128 129 if (flags & MOD_PROP_DEFAULT) { 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 408 /* Check if the value is already in the list */ 409 for (i = 0; i < nports; i++) { 410 if (new_value == ports[i]) 411 break; 412 } 413 414 if (flags & MOD_PROP_REMOVE) { 415 if (i == nports) { 416 mutex_exit(lock); 417 return (ESRCH); 418 } 419 /* Clear the value */ 420 ports[i] = 0; 421 } else if (flags & MOD_PROP_APPEND) { 422 if (i != nports) { 423 mutex_exit(lock); 424 return (EEXIST); 425 } 426 427 /* Find an empty slot */ 428 for (i = 0; i < nports; i++) { 429 if (ports[i] == 0) 430 break; 431 } 432 if (i == nports) { 433 mutex_exit(lock); 434 return (EOVERFLOW); 435 } 436 /* Set the new value */ 437 ports[i] = (in_port_t)new_value; 438 } else { 439 /* 440 * If the user used 'assignment' modifier. 441 * For eg: 442 * # ipadm set-prop -p extra_priv_ports=3001 tcp 443 * 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; 524 pval += nbytes; 525 tbytes += nbytes; 526 if (tbytes >= psize) 527 return (ENOBUFS); 528 } 529 } 530 return (0); 531 ret: 532 if (tbytes >= psize) 533 return (ENOBUFS); 534 return (0); 535 }