lib: remove unused libfru & libfrureg
[unleashed.git] / kernel / net / tunables.c
blobfef5b5428bc699e350add16fda12758584a4944c
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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.
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>
42 mod_prop_info_t *
43 mod_prop_lookup(mod_prop_info_t ptbl[], const char *prop_name, uint_t proto)
45 mod_prop_info_t *pinfo;
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.
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);
57 return (NULL);
60 static int
61 prop_perm2const(mod_prop_info_t *pinfo)
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);
71 * Modifies the value of the property to default value or to the `pval'
72 * specified by the user.
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)
79 char *end;
80 unsigned long new_value;
82 if (flags & MOD_PROP_DEFAULT) {
83 pinfo->prop_cur_bval = pinfo->prop_def_bval;
84 return (0);
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);
96 * Retrieves property permission, default value, current value or possible
97 * values for those properties whose value type is boolean_t.
99 /* ARGSUSED */
101 mod_get_boolean(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
102 void *pval, uint_t psize, uint_t flags)
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;
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);
124 mod_uint32_value(const void *pval, mod_prop_info_t *pinfo, uint_t flags,
125 ulong_t *new_value)
127 char *end;
129 if (flags & MOD_PROP_DEFAULT) {
130 *new_value = pinfo->prop_def_uval;
131 return (0);
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);
141 return (0);
145 * Modifies the value of the property to default value or to the `pval'
146 * specified by the user.
148 /* ARGSUSED */
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)
153 unsigned long new_value;
154 int err;
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);
163 * Rounds up the value to make it multiple of 8.
165 /* ARGSUSED */
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)
170 int err;
172 if ((err = mod_set_uint32(stack, cr, pinfo, ifname, pval, flags)) != 0)
173 return (err);
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;
181 return (0);
185 * Retrieves property permission, default value, current value or possible
186 * values for those properties whose value type is uint32_t.
188 /* ARGSUSED */
190 mod_get_uint32(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
191 void *pval, uint_t psize, uint_t flags)
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;
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);
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.
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)
223 mod_prop_info_t *maxbuf_pinfo = mod_prop_lookup(ptbl, "max_buf",
224 pinfo->mpi_proto);
226 *min = pinfo->prop_min_uval;
227 *max = maxbuf_pinfo->prop_cur_uval;
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).
236 /* ARGSUSED */
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)
241 unsigned long new_value;
242 char *end;
243 uint32_t min, max;
245 if (flags & MOD_PROP_DEFAULT) {
246 pinfo->prop_cur_uval = pinfo->prop_def_uval;
247 return (0);
250 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
251 return (EINVAL);
253 mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
254 if (new_value < min || new_value > max)
255 return (ERANGE);
257 pinfo->prop_cur_uval = new_value;
258 return (0);
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.
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)
272 size_t nbytes;
273 uint32_t min, max;
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);
280 return (mod_get_uint32(stack, pinfo, ifname, pval, psize, flags));
284 * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
285 * backward compatibility with /sbin/ndd.
287 /* ARGSUSED */
289 mod_get_allprop(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
290 void *val, uint_t psize, uint_t flags)
292 char *pval = val;
293 mod_prop_info_t *ptbl, *prop;
294 uint_t size;
295 size_t nbytes = 0, tbytes = 0;
297 bzero(pval, psize);
298 size = psize;
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);
322 for (prop = ptbl; prop->mpi_name != NULL; prop++) {
323 if (prop->mpi_name[0] == '\0' ||
324 strcmp(prop->mpi_name, "?") == 0) {
325 continue;
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);
337 return (0);
341 * Hold a lock while changing *_epriv_ports to prevent multiple
342 * threads from changing it at the same time.
344 /* ARGSUSED */
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)
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;
361 if (!def) {
362 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
363 *end != '\0') {
364 return (EINVAL);
367 if (new_value < pinfo->prop_min_uval ||
368 new_value > pinfo->prop_max_uval) {
369 return (ERANGE);
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);
396 mutex_enter(lock);
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);
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;
414 if (flags & MOD_PROP_REMOVE) {
415 if (i == nports) {
416 mutex_exit(lock);
417 return (ESRCH);
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);
427 /* Find an empty slot */
428 for (i = 0; i < nports; i++) {
429 if (ports[i] == 0)
430 break;
432 if (i == nports) {
433 mutex_exit(lock);
434 return (EOVERFLOW);
436 /* Set the new value */
437 ports[i] = (in_port_t)new_value;
438 } else {
440 * If the user used 'assignment' modifier.
441 * For eg:
442 * # ipadm set-prop -p extra_priv_ports=3001 tcp
444 * We clear all the ports and then just add 3001.
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;
452 mutex_exit(lock);
453 return (0);
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
462 /* ARGSUSED */
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)
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);
479 bzero(pval, psize);
480 size = psize;
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;
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);
511 if (get_range) {
512 tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
513 pinfo->prop_max_uval);
514 goto ret;
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);
530 return (0);
531 ret:
532 if (tbytes >= psize)
533 return (ENOBUFS);
534 return (0);