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;
|