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 */
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
prop_perm2const(mod_prop_info_t * pinfo)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
mod_set_boolean(void * cbarg,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)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
mod_get_boolean(void * cbarg,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)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 }
103
104 int
mod_uint32_value(const void * pval,mod_prop_info_t * pinfo,uint_t flags,ulong_t * new_value)105 mod_uint32_value(const void *pval, mod_prop_info_t *pinfo, uint_t flags,
106 ulong_t *new_value)
107 {
108 char *end;
109
110 if (flags & MOD_PROP_DEFAULT) {
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
mod_set_uint32(void * cbarg,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)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
mod_set_aligned(void * cbarg,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)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
mod_get_uint32(void * cbarg,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)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
mod_get_allprop(void * cbarg,mod_prop_info_t * pinfo,const char * ifname,void * val,uint_t psize,uint_t flags)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
mod_set_extra_privports(void * cbarg,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * val,uint_t flags)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
329 /* Check if the value is already in the list */
330 for (i = 0; i < nports; i++) {
331 if (new_value == ports[i])
332 break;
333 }
334
335 if (flags & MOD_PROP_REMOVE) {
336 if (i == nports) {
337 mutex_exit(lock);
338 return (ESRCH);
339 }
340 /* Clear the value */
341 ports[i] = 0;
342 } else if (flags & MOD_PROP_APPEND) {
343 if (i != nports) {
344 mutex_exit(lock);
345 return (EEXIST);
346 }
347
348 /* Find an empty slot */
349 for (i = 0; i < nports; i++) {
350 if (ports[i] == 0)
351 break;
352 }
353 if (i == nports) {
354 mutex_exit(lock);
355 return (EOVERFLOW);
356 }
357 /* Set the new value */
358 ports[i] = (in_port_t)new_value;
359 } else {
360 /*
361 * If the user used 'assignment' modifier.
362 * For eg:
363 * # ipadm set-prop -p extra_priv_ports=3001 tcp
364 *
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
mod_get_extra_privports(void * cbarg,mod_prop_info_t * pinfo,const char * ifname,void * val,uint_t psize,uint_t flags)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;
445 pval += nbytes;
446 tbytes += nbytes;
447 if (tbytes >= psize)
448 return (ENOBUFS);
449 }
450 }
451 return (0);
452 ret:
453 if (tbytes >= psize)
454 return (ENOBUFS);
455 return (0);
456 }
457