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]
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>
29 #include <inet/common.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>
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
)
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.
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
)
80 unsigned long new_value
;
82 if (flags
& MOD_PROP_DEFAULT
) {
83 pinfo
->prop_cur_bval
= pinfo
->prop_def_bval
;
87 if (ddi_strtoul(pval
, &end
, 10, &new_value
) != 0 || *end
!= '\0')
89 if (new_value
!= B_TRUE
&& new_value
!= B_FALSE
)
91 pinfo
->prop_cur_bval
= new_value
;
96 * Retrieves property permission, default value, current value or possible
97 * values for those properties whose value type is boolean_t.
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
);
111 nbytes
= snprintf(pval
, psize
, "%u", prop_perm2const(pinfo
));
113 nbytes
= snprintf(pval
, psize
, "%u,%u", B_FALSE
, B_TRUE
);
115 nbytes
= snprintf(pval
, psize
, "%u", pinfo
->prop_def_bval
);
117 nbytes
= snprintf(pval
, psize
, "%u", pinfo
->prop_cur_bval
);
124 mod_uint32_value(const void *pval
, mod_prop_info_t
*pinfo
, uint_t flags
,
129 if (flags
& MOD_PROP_DEFAULT
) {
130 *new_value
= pinfo
->prop_def_uval
;
134 if (ddi_strtoul(pval
, &end
, 10, (ulong_t
*)new_value
) != 0 ||
137 if (*new_value
< pinfo
->prop_min_uval
||
138 *new_value
> pinfo
->prop_max_uval
) {
145 * Modifies the value of the property to default value or to the `pval'
146 * specified by the user.
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
;
156 if ((err
= mod_uint32_value(pval
, pinfo
, flags
, &new_value
)) != 0)
158 pinfo
->prop_cur_uval
= (uint32_t)new_value
;
163 * Rounds up the value to make it multiple of 8.
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
)
172 if ((err
= mod_set_uint32(stack
, cr
, pinfo
, ifname
, pval
, flags
)) != 0)
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;
185 * Retrieves property permission, default value, current value or possible
186 * values for those properties whose value type is uint32_t.
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
);
200 nbytes
= snprintf(pval
, psize
, "%u", prop_perm2const(pinfo
));
202 nbytes
= snprintf(pval
, psize
, "%u-%u",
203 pinfo
->prop_min_uval
, pinfo
->prop_max_uval
);
205 nbytes
= snprintf(pval
, psize
, "%u", pinfo
->prop_def_uval
);
207 nbytes
= snprintf(pval
, psize
, "%u", pinfo
->prop_cur_uval
);
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.
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",
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()
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
;
245 if (flags
& MOD_PROP_DEFAULT
) {
246 pinfo
->prop_cur_uval
= pinfo
->prop_def_uval
;
250 if (ddi_strtoul(pval
, &end
, 10, &new_value
) != 0 || *end
!= '\0')
253 mod_get_buf_prop_range(ptbl
, pinfo
, &min
, &max
);
254 if (new_value
< min
|| new_value
> max
)
257 pinfo
->prop_cur_uval
= new_value
;
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
,
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.
289 mod_get_allprop(netstack_t
*stack
, mod_prop_info_t
*pinfo
, const char *ifname
,
290 void *val
, uint_t psize
, uint_t flags
)
293 mod_prop_info_t
*ptbl
, *prop
;
295 size_t nbytes
= 0, tbytes
= 0;
300 switch (pinfo
->mpi_proto
) {
304 ptbl
= stack
->netstack_ip
->ips_propinfo_tbl
;
306 case MOD_PROTO_RAWIP
:
307 ptbl
= stack
->netstack_icmp
->is_propinfo_tbl
;
310 ptbl
= stack
->netstack_tcp
->tcps_propinfo_tbl
;
313 ptbl
= stack
->netstack_udp
->us_propinfo_tbl
;
316 ptbl
= stack
->netstack_sctp
->sctps_propinfo_tbl
;
322 for (prop
= ptbl
; prop
->mpi_name
!= NULL
; prop
++) {
323 if (prop
->mpi_name
[0] == '\0' ||
324 strcmp(prop
->mpi_name
, "?") == 0) {
327 nbytes
= snprintf(pval
, size
, "%s %d %d", prop
->mpi_name
,
328 prop
->mpi_proto
, prop_perm2const(prop
));
331 tbytes
+= nbytes
+ 1;
332 if (tbytes
>= psize
) {
333 /* Buffer overflow, stop copying information */
341 * Hold a lock while changing *_epriv_ports to prevent multiple
342 * threads from changing it at the same time.
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
;
353 unsigned long new_value
;
358 boolean_t def
= (flags
& MOD_PROP_DEFAULT
);
359 const char *pval
= val
;
362 if (ddi_strtoul(pval
, &end
, 10, &new_value
) != 0 ||
367 if (new_value
< pinfo
->prop_min_uval
||
368 new_value
> pinfo
->prop_max_uval
) {
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
;
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
;
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
;
398 /* if MOD_PROP_DEFAULT is set then reset the ports list to default */
400 for (i
= 0; i
< nports
; i
++)
402 ports
[0] = ULP_DEF_EPRIV_PORT1
;
403 ports
[1] = ULP_DEF_EPRIV_PORT2
;
408 /* Check if the value is already in the list */
409 for (i
= 0; i
< nports
; i
++) {
410 if (new_value
== ports
[i
])
414 if (flags
& MOD_PROP_REMOVE
) {
419 /* Clear the value */
421 } else if (flags
& MOD_PROP_APPEND
) {
427 /* Find an empty slot */
428 for (i
= 0; i
< nports
; i
++) {
436 /* Set the new value */
437 ports
[i
] = (in_port_t
)new_value
;
440 * If the user used 'assignment' modifier.
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
++)
449 ports
[0] = (in_port_t
)new_value
;
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
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
;
471 uint_t i
, nports
, size
;
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
);
483 tbytes
= snprintf(pval
, psize
, "%u,%u", ULP_DEF_EPRIV_PORT1
,
484 ULP_DEF_EPRIV_PORT2
);
486 } else if (get_perm
) {
487 tbytes
= snprintf(pval
, psize
, "%u", MOD_PROP_PERM_RW
);
493 tcps
= stack
->netstack_tcp
;
494 ports
= tcps
->tcps_g_epriv_ports
;
495 nports
= tcps
->tcps_g_num_epriv_ports
;
498 us
= stack
->netstack_udp
;
499 ports
= us
->us_epriv_ports
;
500 nports
= us
->us_num_epriv_ports
;
503 sctps
= stack
->netstack_sctp
;
504 ports
= sctps
->sctps_g_epriv_ports
;
505 nports
= sctps
->sctps_g_num_epriv_ports
;
512 tbytes
= snprintf(pval
, psize
, "%u-%u", pinfo
->prop_min_uval
,
513 pinfo
->prop_max_uval
);
517 for (i
= 0; i
< nports
; i
++) {
520 nbytes
= snprintf(pval
, size
, "%u", ports
[i
]);
522 nbytes
= snprintf(pval
, size
, ",%u", ports
[i
]);