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 *
mod_prop_lookup(mod_prop_info_t ptbl[],const char * prop_name,uint_t proto)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
prop_perm2const(mod_prop_info_t * pinfo)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
mod_set_boolean(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)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
mod_get_boolean(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)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
mod_uint32_value(const void * pval,mod_prop_info_t * pinfo,uint_t flags,ulong_t * new_value)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
mod_set_uint32(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)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
mod_set_aligned(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)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
mod_get_uint32(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)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
mod_get_buf_prop_range(mod_prop_info_t ptbl[],mod_prop_info_t * pinfo,uint32_t * min,uint32_t * max)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
mod_set_buf_prop(mod_prop_info_t ptbl[],netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)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
mod_get_buf_prop(mod_prop_info_t ptbl[],netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)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
mod_get_allprop(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * val,uint_t psize,uint_t flags)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
mod_set_extra_privports(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * val,uint_t flags)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
mod_get_extra_privports(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * val,uint_t psize,uint_t flags)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 }
536