Print this page
%B
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libipadm/common/ipadm_prop.c
+++ new/usr/src/lib/libipadm/common/ipadm_prop.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 /*
26 26 * This file contains routines that are used to modify/retrieve protocol or
27 27 * interface property values. It also holds all the supported properties for
28 28 * both IP interface and protocols in `ipadm_prop_desc_t'. Following protocols
29 - * are supported: IP, IPv4, IPv6, TCP, SCTP, UDP and ICMP.
29 + * are supported: IP, IPv4, IPv6, TCP, SCTP, UDP, ICMP and DCCP.
30 30 *
31 31 * This file also contains walkers, which walks through the property table and
32 32 * calls the callback function, of the form `ipadm_prop_wfunc_t' , for every
33 33 * property in the table.
34 34 */
35 35
36 36 #include <unistd.h>
37 37 #include <errno.h>
38 38 #include <ctype.h>
39 39 #include <fcntl.h>
40 40 #include <strings.h>
41 41 #include <stdlib.h>
42 42 #include <netinet/in.h>
43 43 #include <arpa/inet.h>
44 44 #include <sys/sockio.h>
45 45 #include <assert.h>
46 46 #include <libdllink.h>
47 47 #include <zone.h>
48 48 #include "libipadm_impl.h"
49 49 #include <inet/tunables.h>
50 50
51 51 #define IPADM_NONESTR "none"
52 52 #define DEF_METRIC_VAL 0 /* default metric value */
53 53
54 54 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0]))
55 55
56 56 static ipadm_status_t i_ipadm_validate_if(ipadm_handle_t, const char *,
57 57 uint_t, uint_t);
58 58
59 59 /*
60 60 * Callback functions to retrieve property values from the kernel. These
61 61 * functions, when required, translate the values from the kernel to a format
62 62 * suitable for printing. For example: boolean values will be translated
63 63 * to on/off. They also retrieve DEFAULT, PERM and POSSIBLE values for
64 64 * a given property.
65 65 */
66 66 static ipadm_pd_getf_t i_ipadm_get_prop, i_ipadm_get_ifprop_flags,
67 67 i_ipadm_get_mtu, i_ipadm_get_metric,
68 68 i_ipadm_get_usesrc, i_ipadm_get_forwarding,
69 69 i_ipadm_get_ecnsack, i_ipadm_get_hostmodel;
70 70
71 71 /*
72 72 * Callback function to set property values. These functions translate the
73 73 * values to a format suitable for kernel consumption, allocates the necessary
74 74 * ioctl buffers and then invokes ioctl().
↓ open down ↓ |
35 lines elided |
↑ open up ↑ |
75 75 */
76 76 static ipadm_pd_setf_t i_ipadm_set_prop, i_ipadm_set_mtu,
77 77 i_ipadm_set_ifprop_flags,
78 78 i_ipadm_set_metric, i_ipadm_set_usesrc,
79 79 i_ipadm_set_forwarding, i_ipadm_set_eprivport,
80 80 i_ipadm_set_ecnsack, i_ipadm_set_hostmodel;
81 81
82 82 /* array of protocols we support */
83 83 static int protocols[] = { MOD_PROTO_IP, MOD_PROTO_RAWIP,
84 84 MOD_PROTO_TCP, MOD_PROTO_UDP,
85 - MOD_PROTO_SCTP };
85 + MOD_PROTO_SCTP, MOD_PROTO_DCCP };
86 86
87 87 /*
88 88 * Supported IP protocol properties.
89 89 */
90 90 static ipadm_prop_desc_t ipadm_ip_prop_table[] = {
91 91 { "arp", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
92 92 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
93 93 i_ipadm_get_ifprop_flags },
94 94
95 95 { "forwarding", IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV4, 0,
96 96 i_ipadm_set_forwarding, i_ipadm_get_onoff,
97 97 i_ipadm_get_forwarding },
98 98
99 99 { "metric", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
100 100 i_ipadm_set_metric, NULL, i_ipadm_get_metric },
101 101
102 102 { "mtu", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
103 103 i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
104 104
105 105 { "exchange_routes", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
106 106 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
107 107 i_ipadm_get_ifprop_flags },
108 108
109 109 { "usesrc", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
110 110 i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
111 111
112 112 { "ttl", IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
113 113 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
114 114
115 115 { "forwarding", IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV6, 0,
116 116 i_ipadm_set_forwarding, i_ipadm_get_onoff,
117 117 i_ipadm_get_forwarding },
118 118
119 119 { "hoplimit", IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
120 120 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
121 121
122 122 { "metric", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
123 123 i_ipadm_set_metric, NULL, i_ipadm_get_metric },
124 124
125 125 { "mtu", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
126 126 i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
127 127
128 128 { "nud", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
129 129 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
130 130 i_ipadm_get_ifprop_flags },
131 131
132 132 { "exchange_routes", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
133 133 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
134 134 i_ipadm_get_ifprop_flags },
135 135
136 136 { "usesrc", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
137 137 i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
138 138
139 139 { "hostmodel", IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
140 140 i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
141 141 i_ipadm_get_hostmodel },
142 142
143 143 { "hostmodel", IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
144 144 i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
145 145 i_ipadm_get_hostmodel },
146 146
147 147 { NULL, 0, 0, 0, NULL, NULL, NULL }
148 148 };
149 149
150 150 /* possible values for TCP properties `ecn' and `sack' */
151 151 static const char *ecn_sack_vals[] = {"never", "passive", "active", NULL};
152 152
153 153 /* Supported TCP protocol properties */
154 154 static ipadm_prop_desc_t ipadm_tcp_prop_table[] = {
155 155 { "ecn", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
156 156 i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
157 157
158 158 { "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
159 159 IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
160 160 i_ipadm_get_prop },
161 161
162 162 { "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
163 163 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
164 164
165 165 { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
166 166 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
167 167
168 168 { "sack", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
169 169 i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
170 170
171 171 { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
172 172 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
173 173
174 174 { "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
175 175 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
176 176
177 177 { "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
178 178 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
179 179
180 180 { NULL, 0, 0, 0, NULL, NULL, NULL }
181 181 };
182 182
183 183 /* Supported UDP protocol properties */
184 184 static ipadm_prop_desc_t ipadm_udp_prop_table[] = {
185 185 { "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
186 186 IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
187 187 i_ipadm_get_prop },
188 188
189 189 { "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
190 190 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
191 191
192 192 { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
193 193 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
194 194
195 195 { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
196 196 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
197 197
198 198 { "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
199 199 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
200 200
201 201 { "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
202 202 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
203 203
204 204 { NULL, 0, 0, 0, NULL, NULL, NULL }
205 205 };
206 206
207 207 /* Supported SCTP protocol properties */
208 208 static ipadm_prop_desc_t ipadm_sctp_prop_table[] = {
209 209 { "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
210 210 IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
211 211 i_ipadm_get_prop },
212 212
213 213 { "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
214 214 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
215 215
216 216 { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
217 217 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
218 218
219 219 { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
220 220 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
221 221
222 222 { "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
223 223 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
224 224
225 225 { "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
226 226 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
227 227
228 228 { NULL, 0, 0, 0, NULL, NULL, NULL }
229 229 };
230 230
231 231 /* Supported ICMP protocol properties */
↓ open down ↓ |
136 lines elided |
↑ open up ↑ |
232 232 static ipadm_prop_desc_t ipadm_icmp_prop_table[] = {
233 233 { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
234 234 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
235 235
236 236 { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
237 237 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
238 238
239 239 { NULL, 0, 0, 0, NULL, NULL, NULL }
240 240 };
241 241
242 +/* Supported DCCP protocol properties */
243 +static ipadm_prop_desc_t ipadm_dccp_prop_table[] = {
244 + { "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_DCCP,
245 + IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
246 + i_ipadm_get_prop },
247 +
248 + { "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_DCCP, 0,
249 + i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
250 +
251 + { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_DCCP, 0,
252 + i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
253 +
254 + { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_DCCP, 0,
255 + i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
256 +
257 + { "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_DCCP, 0,
258 + i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
259 +
260 + { "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_DCCP, 0,
261 + i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
262 +
263 + { NULL, 0, 0, 0, NULL, NULL, NULL }
264 +};
265 +
242 266 /*
243 267 * A dummy private property structure, used while handling private
244 268 * protocol properties (properties not yet supported by libipadm).
245 269 */
246 270 static ipadm_prop_desc_t ipadm_privprop =\
247 271 { NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_NONE, 0,
248 272 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop };
249 273
250 274 /*
251 275 * Returns the property description table, for the given protocol
252 276 */
253 277 static ipadm_prop_desc_t *
254 278 i_ipadm_get_propdesc_table(uint_t proto)
255 279 {
256 280 switch (proto) {
257 281 case MOD_PROTO_IP:
258 282 case MOD_PROTO_IPV4:
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
259 283 case MOD_PROTO_IPV6:
260 284 return (ipadm_ip_prop_table);
261 285 case MOD_PROTO_RAWIP:
262 286 return (ipadm_icmp_prop_table);
263 287 case MOD_PROTO_TCP:
264 288 return (ipadm_tcp_prop_table);
265 289 case MOD_PROTO_UDP:
266 290 return (ipadm_udp_prop_table);
267 291 case MOD_PROTO_SCTP:
268 292 return (ipadm_sctp_prop_table);
293 + case MOD_PROTO_DCCP:
294 + return (ipadm_dccp_prop_table);
269 295 }
270 296
271 297 return (NULL);
272 298 }
273 299
274 300 static ipadm_prop_desc_t *
275 301 i_ipadm_get_prop_desc(const char *pname, uint_t proto, int *errp)
276 302 {
277 303 int err = 0;
278 304 boolean_t matched_name = B_FALSE;
279 305 ipadm_prop_desc_t *ipdp = NULL, *ipdtbl;
280 306
281 307 if ((ipdtbl = i_ipadm_get_propdesc_table(proto)) == NULL) {
282 308 err = EINVAL;
283 309 goto ret;
284 310 }
285 311 for (ipdp = ipdtbl; ipdp->ipd_name != NULL; ipdp++) {
286 312 if (strcmp(pname, ipdp->ipd_name) == 0) {
287 313 matched_name = B_TRUE;
288 314 if (ipdp->ipd_proto == proto)
289 315 break;
290 316 }
291 317 }
292 318 if (ipdp->ipd_name == NULL) {
293 319 err = ENOENT;
294 320 /* if we matched name, but failed protocol check */
295 321 if (matched_name)
296 322 err = EPROTO;
297 323 ipdp = NULL;
298 324 }
299 325 ret:
300 326 if (errp != NULL)
301 327 *errp = err;
302 328 return (ipdp);
303 329 }
304 330
305 331 char *
306 332 ipadm_proto2str(uint_t proto)
307 333 {
308 334 switch (proto) {
309 335 case MOD_PROTO_IP:
310 336 return ("ip");
311 337 case MOD_PROTO_IPV4:
312 338 return ("ipv4");
↓ open down ↓ |
34 lines elided |
↑ open up ↑ |
313 339 case MOD_PROTO_IPV6:
314 340 return ("ipv6");
315 341 case MOD_PROTO_RAWIP:
316 342 return ("icmp");
317 343 case MOD_PROTO_TCP:
318 344 return ("tcp");
319 345 case MOD_PROTO_UDP:
320 346 return ("udp");
321 347 case MOD_PROTO_SCTP:
322 348 return ("sctp");
349 + case MOD_PROTO_DCCP:
350 + return ("dccp");
323 351 }
324 352
325 353 return (NULL);
326 354 }
327 355
328 356 uint_t
329 357 ipadm_str2proto(const char *protostr)
330 358 {
331 359 if (protostr == NULL)
332 360 return (MOD_PROTO_NONE);
333 361 if (strcmp(protostr, "tcp") == 0)
334 362 return (MOD_PROTO_TCP);
335 363 else if (strcmp(protostr, "udp") == 0)
336 364 return (MOD_PROTO_UDP);
337 365 else if (strcmp(protostr, "ip") == 0)
338 366 return (MOD_PROTO_IP);
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
339 367 else if (strcmp(protostr, "ipv4") == 0)
340 368 return (MOD_PROTO_IPV4);
341 369 else if (strcmp(protostr, "ipv6") == 0)
342 370 return (MOD_PROTO_IPV6);
343 371 else if (strcmp(protostr, "icmp") == 0)
344 372 return (MOD_PROTO_RAWIP);
345 373 else if (strcmp(protostr, "sctp") == 0)
346 374 return (MOD_PROTO_SCTP);
347 375 else if (strcmp(protostr, "arp") == 0)
348 376 return (MOD_PROTO_IP);
377 + else if (strcmp(protostr, "dccp") == 0)
378 + return (MOD_PROTO_DCCP);
349 379
350 380 return (MOD_PROTO_NONE);
351 381 }
352 382
353 383 /* ARGSUSED */
354 384 static ipadm_status_t
355 385 i_ipadm_set_mtu(ipadm_handle_t iph, const void *arg,
356 386 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
357 387 {
358 388 struct lifreq lifr;
359 389 char *endp;
360 390 uint_t mtu;
361 391 int s;
362 392 const char *ifname = arg;
363 393 char val[MAXPROPVALLEN];
364 394
365 395 /* to reset MTU first retrieve the default MTU and then set it */
366 396 if (flags & IPADM_OPT_DEFAULT) {
367 397 ipadm_status_t status;
368 398 uint_t size = MAXPROPVALLEN;
369 399
370 400 status = i_ipadm_get_prop(iph, arg, pdp, val, &size,
371 401 proto, MOD_PROP_DEFAULT);
372 402 if (status != IPADM_SUCCESS)
373 403 return (status);
374 404 pval = val;
375 405 }
376 406
377 407 errno = 0;
378 408 mtu = (uint_t)strtol(pval, &endp, 10);
379 409 if (errno != 0 || *endp != '\0')
380 410 return (IPADM_INVALID_ARG);
381 411
382 412 bzero(&lifr, sizeof (lifr));
383 413 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
384 414 lifr.lifr_mtu = mtu;
385 415
386 416 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
387 417 if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
388 418 return (ipadm_errno2status(errno));
389 419
390 420 return (IPADM_SUCCESS);
391 421 }
392 422
393 423 /* ARGSUSED */
394 424 static ipadm_status_t
395 425 i_ipadm_set_metric(ipadm_handle_t iph, const void *arg,
396 426 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
397 427 {
398 428 struct lifreq lifr;
399 429 char *endp;
400 430 int metric;
401 431 const char *ifname = arg;
402 432 int s;
403 433
404 434 /* if we are resetting, set the value to its default value */
405 435 if (flags & IPADM_OPT_DEFAULT) {
406 436 metric = DEF_METRIC_VAL;
407 437 } else {
408 438 errno = 0;
409 439 metric = (uint_t)strtol(pval, &endp, 10);
410 440 if (errno != 0 || *endp != '\0')
411 441 return (IPADM_INVALID_ARG);
412 442 }
413 443
414 444 bzero(&lifr, sizeof (lifr));
415 445 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
416 446 lifr.lifr_metric = metric;
417 447
418 448 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
419 449
420 450 if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
421 451 return (ipadm_errno2status(errno));
422 452
423 453 return (IPADM_SUCCESS);
424 454 }
425 455
426 456 /* ARGSUSED */
427 457 static ipadm_status_t
428 458 i_ipadm_set_usesrc(ipadm_handle_t iph, const void *arg,
429 459 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
430 460 {
431 461 struct lifreq lifr;
432 462 const char *ifname = arg;
433 463 int s;
434 464 uint_t ifindex = 0;
435 465
436 466 /* if we are resetting, set the value to its default value */
437 467 if (flags & IPADM_OPT_DEFAULT)
438 468 pval = IPADM_NONESTR;
439 469
440 470 /*
441 471 * cannot specify logical interface name. We can also filter out other
442 472 * bogus interface names here itself through i_ipadm_validate_ifname().
443 473 */
444 474 if (strcmp(pval, IPADM_NONESTR) != 0 &&
445 475 !i_ipadm_validate_ifname(iph, pval))
446 476 return (IPADM_INVALID_ARG);
447 477
448 478 bzero(&lifr, sizeof (lifr));
449 479 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
450 480
451 481 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
452 482
453 483 if (strcmp(pval, IPADM_NONESTR) != 0) {
454 484 if ((ifindex = if_nametoindex(pval)) == 0)
455 485 return (ipadm_errno2status(errno));
456 486 lifr.lifr_index = ifindex;
457 487 } else {
458 488 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
459 489 return (ipadm_errno2status(errno));
460 490 lifr.lifr_index = 0;
461 491 }
462 492 if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) < 0)
463 493 return (ipadm_errno2status(errno));
464 494
465 495 return (IPADM_SUCCESS);
466 496 }
467 497
468 498 static struct hostmodel_strval {
469 499 char *esm_str;
470 500 ip_hostmodel_t esm_val;
471 501 } esm_arr[] = {
472 502 {"weak", IP_WEAK_ES},
473 503 {"src-priority", IP_SRC_PRI_ES},
474 504 {"strong", IP_STRONG_ES},
475 505 {"custom", IP_MAXVAL_ES}
476 506 };
477 507
478 508 static ip_hostmodel_t
479 509 i_ipadm_hostmodel_str2val(const char *pval)
480 510 {
481 511 int i;
482 512
483 513 for (i = 0; i < A_CNT(esm_arr); i++) {
484 514 if (esm_arr[i].esm_str != NULL &&
485 515 strcmp(pval, esm_arr[i].esm_str) == 0) {
486 516 return (esm_arr[i].esm_val);
487 517 }
488 518 }
489 519 return (IP_MAXVAL_ES);
490 520 }
491 521
492 522 static char *
493 523 i_ipadm_hostmodel_val2str(ip_hostmodel_t pval)
494 524 {
495 525 int i;
496 526
497 527 for (i = 0; i < A_CNT(esm_arr); i++) {
498 528 if (esm_arr[i].esm_val == pval)
499 529 return (esm_arr[i].esm_str);
500 530 }
501 531 return (NULL);
502 532 }
503 533
504 534 /* ARGSUSED */
505 535 static ipadm_status_t
506 536 i_ipadm_set_hostmodel(ipadm_handle_t iph, const void *arg,
507 537 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
508 538 {
509 539 ip_hostmodel_t hostmodel;
510 540 char val[11]; /* covers uint32_max as a string */
511 541
512 542 if ((flags & IPADM_OPT_DEFAULT) == 0) {
513 543 hostmodel = i_ipadm_hostmodel_str2val(pval);
514 544 if (hostmodel == IP_MAXVAL_ES)
515 545 return (IPADM_INVALID_ARG);
516 546 (void) snprintf(val, sizeof (val), "%d", hostmodel);
517 547 pval = val;
518 548 }
519 549 return (i_ipadm_set_prop(iph, NULL, pdp, pval, proto, flags));
520 550 }
521 551
522 552 /* ARGSUSED */
523 553 static ipadm_status_t
524 554 i_ipadm_get_hostmodel(ipadm_handle_t iph, const void *arg,
525 555 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
526 556 uint_t valtype)
527 557 {
528 558 ip_hostmodel_t hostmodel;
529 559 char *cp;
530 560 size_t nbytes;
531 561 ipadm_status_t status;
532 562
533 563 switch (valtype) {
534 564 case MOD_PROP_PERM:
535 565 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
536 566 break;
537 567 case MOD_PROP_DEFAULT:
538 568 nbytes = snprintf(buf, *bufsize, "weak");
539 569 break;
540 570 case MOD_PROP_ACTIVE:
541 571 status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
542 572 valtype);
543 573 if (status != IPADM_SUCCESS)
544 574 return (status);
545 575 bcopy(buf, &hostmodel, sizeof (hostmodel));
546 576 cp = i_ipadm_hostmodel_val2str(hostmodel);
547 577 nbytes = snprintf(buf, *bufsize, "%s",
548 578 (cp != NULL ? cp : "?"));
549 579 break;
550 580 case MOD_PROP_POSSIBLE:
551 581 nbytes = snprintf(buf, *bufsize, "strong,src-priority,weak");
552 582 break;
553 583 default:
554 584 return (IPADM_INVALID_ARG);
555 585 }
556 586 if (nbytes >= *bufsize) {
557 587 /* insufficient buffer space */
558 588 *bufsize = nbytes + 1;
559 589 return (IPADM_NO_BUFS);
560 590 }
561 591 return (IPADM_SUCCESS);
562 592 }
563 593
564 594 /* ARGSUSED */
565 595 static ipadm_status_t
566 596 i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg,
567 597 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
568 598 {
569 599 ipadm_status_t status = IPADM_SUCCESS;
570 600 const char *ifname = arg;
571 601 uint64_t on_flags = 0, off_flags = 0;
572 602 boolean_t on = B_FALSE;
573 603 sa_family_t af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
574 604
575 605 /* if we are resetting, set the value to its default value */
576 606 if (flags & IPADM_OPT_DEFAULT) {
577 607 if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
578 608 strcmp(pdp->ipd_name, "arp") == 0 ||
579 609 strcmp(pdp->ipd_name, "nud") == 0) {
580 610 pval = IPADM_ONSTR;
581 611 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
582 612 pval = IPADM_OFFSTR;
583 613 } else {
584 614 return (IPADM_PROP_UNKNOWN);
585 615 }
586 616 }
587 617
588 618 if (strcmp(pval, IPADM_ONSTR) == 0)
589 619 on = B_TRUE;
590 620 else if (strcmp(pval, IPADM_OFFSTR) == 0)
591 621 on = B_FALSE;
592 622 else
593 623 return (IPADM_INVALID_ARG);
594 624
595 625 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
596 626 if (on)
597 627 off_flags = IFF_NORTEXCH;
598 628 else
599 629 on_flags = IFF_NORTEXCH;
600 630 } else if (strcmp(pdp->ipd_name, "arp") == 0) {
601 631 if (on)
602 632 off_flags = IFF_NOARP;
603 633 else
604 634 on_flags = IFF_NOARP;
605 635 } else if (strcmp(pdp->ipd_name, "nud") == 0) {
606 636 if (on)
607 637 off_flags = IFF_NONUD;
608 638 else
609 639 on_flags = IFF_NONUD;
610 640 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
611 641 if (on)
612 642 on_flags = IFF_ROUTER;
613 643 else
614 644 off_flags = IFF_ROUTER;
615 645 }
616 646
617 647 if (on_flags || off_flags) {
618 648 status = i_ipadm_set_flags(iph, ifname, af, on_flags,
619 649 off_flags);
620 650 }
621 651 return (status);
622 652 }
623 653
624 654 /* ARGSUSED */
625 655 static ipadm_status_t
626 656 i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
627 657 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
628 658 {
629 659 nvlist_t *portsnvl = NULL;
630 660 nvpair_t *nvp;
631 661 ipadm_status_t status = IPADM_SUCCESS;
632 662 int err;
633 663 uint_t count = 0;
634 664
635 665 if (flags & IPADM_OPT_DEFAULT) {
636 666 assert(pval == NULL);
637 667 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
638 668 }
639 669
640 670 if ((err = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
641 671 return (ipadm_errno2status(err));
642 672
643 673 /* count the number of ports */
644 674 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
645 675 nvp = nvlist_next_nvpair(portsnvl, nvp)) {
646 676 ++count;
647 677 }
648 678
649 679 if (iph->iph_flags & IPH_INIT) {
650 680 flags |= IPADM_OPT_APPEND;
651 681 } else if (count > 1) {
652 682 /*
653 683 * We allow only one port to be added, removed or
654 684 * assigned at a time.
655 685 *
656 686 * However on reboot, while initializing protocol
657 687 * properties, extra_priv_ports might have multiple
658 688 * values. Only in that case we allow setting multiple
659 689 * values.
660 690 */
661 691 nvlist_free(portsnvl);
662 692 return (IPADM_INVALID_ARG);
663 693 }
664 694
665 695 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
666 696 nvp = nvlist_next_nvpair(portsnvl, nvp)) {
667 697 status = i_ipadm_set_prop(iph, arg, pdp, nvpair_name(nvp),
668 698 proto, flags);
669 699 if (status != IPADM_SUCCESS)
670 700 break;
671 701 }
672 702 nvlist_free(portsnvl);
673 703 return (status);
674 704 }
675 705
676 706 /* ARGSUSED */
677 707 static ipadm_status_t
678 708 i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg,
679 709 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
680 710 {
681 711 const char *ifname = arg;
682 712 ipadm_status_t status;
683 713
684 714 /*
685 715 * if interface name is provided, then set forwarding using the
686 716 * IFF_ROUTER flag
687 717 */
688 718 if (ifname != NULL) {
689 719 status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval,
690 720 proto, flags);
691 721 } else {
692 722 char *val = NULL;
693 723
694 724 /*
695 725 * if the caller is IPH_LEGACY, `pval' already contains
696 726 * numeric values.
697 727 */
698 728 if (!(flags & IPADM_OPT_DEFAULT) &&
699 729 !(iph->iph_flags & IPH_LEGACY)) {
700 730
701 731 if (strcmp(pval, IPADM_ONSTR) == 0)
702 732 val = "1";
703 733 else if (strcmp(pval, IPADM_OFFSTR) == 0)
704 734 val = "0";
705 735 else
706 736 return (IPADM_INVALID_ARG);
707 737 pval = val;
708 738 }
709 739
710 740 status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags);
711 741 }
712 742
713 743 return (status);
714 744 }
715 745
716 746 /* ARGSUSED */
717 747 static ipadm_status_t
718 748 i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg,
719 749 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
720 750 {
721 751 uint_t i;
722 752 char val[MAXPROPVALLEN];
723 753
724 754 /* if IPH_LEGACY is set, `pval' already contains numeric values */
725 755 if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) {
726 756 for (i = 0; ecn_sack_vals[i] != NULL; i++) {
727 757 if (strcmp(pval, ecn_sack_vals[i]) == 0)
728 758 break;
729 759 }
730 760 if (ecn_sack_vals[i] == NULL)
731 761 return (IPADM_INVALID_ARG);
732 762 (void) snprintf(val, MAXPROPVALLEN, "%d", i);
733 763 pval = val;
734 764 }
735 765
736 766 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
737 767 }
738 768
739 769 /* ARGSUSED */
740 770 ipadm_status_t
741 771 i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg,
742 772 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
743 773 uint_t valtype)
744 774 {
745 775 ipadm_status_t status = IPADM_SUCCESS;
746 776 uint_t i, nbytes = 0;
747 777
748 778 switch (valtype) {
749 779 case MOD_PROP_POSSIBLE:
750 780 for (i = 0; ecn_sack_vals[i] != NULL; i++) {
751 781 if (i == 0)
752 782 nbytes += snprintf(buf + nbytes,
753 783 *bufsize - nbytes, "%s", ecn_sack_vals[i]);
754 784 else
755 785 nbytes += snprintf(buf + nbytes,
756 786 *bufsize - nbytes, ",%s", ecn_sack_vals[i]);
757 787 if (nbytes >= *bufsize)
758 788 break;
759 789 }
760 790 break;
761 791 case MOD_PROP_PERM:
762 792 case MOD_PROP_DEFAULT:
763 793 case MOD_PROP_ACTIVE:
764 794 status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
765 795 valtype);
766 796
767 797 /*
768 798 * If IPH_LEGACY is set, do not convert the value returned
769 799 * from kernel,
770 800 */
771 801 if (iph->iph_flags & IPH_LEGACY)
772 802 break;
773 803
774 804 /*
775 805 * For current and default value, convert the value returned
776 806 * from kernel to more discrete representation.
777 807 */
778 808 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
779 809 valtype == MOD_PROP_DEFAULT)) {
780 810 i = atoi(buf);
781 811 assert(i < 3);
782 812 nbytes = snprintf(buf, *bufsize, "%s",
783 813 ecn_sack_vals[i]);
784 814 }
785 815 break;
786 816 default:
787 817 return (IPADM_INVALID_ARG);
788 818 }
789 819 if (nbytes >= *bufsize) {
790 820 /* insufficient buffer space */
791 821 *bufsize = nbytes + 1;
792 822 return (IPADM_NO_BUFS);
793 823 }
794 824
795 825 return (status);
796 826 }
797 827
798 828 /* ARGSUSED */
799 829 static ipadm_status_t
800 830 i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg,
801 831 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
802 832 uint_t valtype)
803 833 {
804 834 const char *ifname = arg;
805 835 ipadm_status_t status = IPADM_SUCCESS;
806 836
807 837 /*
808 838 * if interface name is provided, then get forwarding status using
809 839 * SIOCGLIFFLAGS
810 840 */
811 841 if (ifname != NULL) {
812 842 status = i_ipadm_get_ifprop_flags(iph, ifname, pdp,
813 843 buf, bufsize, pdp->ipd_proto, valtype);
814 844 } else {
815 845 status = i_ipadm_get_prop(iph, ifname, pdp, buf,
816 846 bufsize, proto, valtype);
817 847 /*
818 848 * If IPH_LEGACY is set, do not convert the value returned
819 849 * from kernel,
820 850 */
821 851 if (iph->iph_flags & IPH_LEGACY)
822 852 goto ret;
823 853 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
824 854 valtype == MOD_PROP_DEFAULT)) {
825 855 uint_t val = atoi(buf);
826 856
827 857 (void) snprintf(buf, *bufsize,
828 858 (val == 1 ? IPADM_ONSTR : IPADM_OFFSTR));
829 859 }
830 860 }
831 861
832 862 ret:
833 863 return (status);
834 864 }
835 865
836 866 /* ARGSUSED */
837 867 static ipadm_status_t
838 868 i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg,
839 869 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
840 870 uint_t valtype)
841 871 {
842 872 struct lifreq lifr;
843 873 const char *ifname = arg;
844 874 size_t nbytes;
845 875 int s;
846 876
847 877 switch (valtype) {
848 878 case MOD_PROP_PERM:
849 879 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
850 880 break;
851 881 case MOD_PROP_DEFAULT:
852 882 case MOD_PROP_POSSIBLE:
853 883 return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize,
854 884 proto, valtype));
855 885 case MOD_PROP_ACTIVE:
856 886 bzero(&lifr, sizeof (lifr));
857 887 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
858 888 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
859 889
860 890 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0)
861 891 return (ipadm_errno2status(errno));
862 892 nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu);
863 893 break;
864 894 default:
865 895 return (IPADM_INVALID_ARG);
866 896 }
867 897 if (nbytes >= *bufsize) {
868 898 /* insufficient buffer space */
869 899 *bufsize = nbytes + 1;
870 900 return (IPADM_NO_BUFS);
871 901 }
872 902 return (IPADM_SUCCESS);
873 903 }
874 904
875 905 /* ARGSUSED */
876 906 static ipadm_status_t
877 907 i_ipadm_get_metric(ipadm_handle_t iph, const void *arg,
878 908 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
879 909 uint_t valtype)
880 910 {
881 911 struct lifreq lifr;
882 912 const char *ifname = arg;
883 913 size_t nbytes;
884 914 int s, val;
885 915
886 916 switch (valtype) {
887 917 case MOD_PROP_PERM:
888 918 val = MOD_PROP_PERM_RW;
889 919 break;
890 920 case MOD_PROP_DEFAULT:
891 921 val = DEF_METRIC_VAL;
892 922 break;
893 923 case MOD_PROP_ACTIVE:
894 924 bzero(&lifr, sizeof (lifr));
895 925 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
896 926
897 927 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
898 928 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0)
899 929 return (ipadm_errno2status(errno));
900 930 val = lifr.lifr_metric;
901 931 break;
902 932 default:
903 933 return (IPADM_INVALID_ARG);
904 934 }
905 935 nbytes = snprintf(buf, *bufsize, "%d", val);
906 936 if (nbytes >= *bufsize) {
907 937 /* insufficient buffer space */
908 938 *bufsize = nbytes + 1;
909 939 return (IPADM_NO_BUFS);
910 940 }
911 941
912 942 return (IPADM_SUCCESS);
913 943 }
914 944
915 945 /* ARGSUSED */
916 946 static ipadm_status_t
917 947 i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg,
918 948 ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto,
919 949 uint_t valtype)
920 950 {
921 951 struct lifreq lifr;
922 952 const char *ifname = arg;
923 953 int s;
924 954 char if_name[IF_NAMESIZE];
925 955 size_t nbytes;
926 956
927 957 switch (valtype) {
928 958 case MOD_PROP_PERM:
929 959 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
930 960 break;
931 961 case MOD_PROP_DEFAULT:
932 962 nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR);
933 963 break;
934 964 case MOD_PROP_ACTIVE:
935 965 bzero(&lifr, sizeof (lifr));
936 966 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
937 967
938 968 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
939 969 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
940 970 return (ipadm_errno2status(errno));
941 971 if (lifr.lifr_index == 0) {
942 972 /* no src address was set, so print 'none' */
943 973 (void) strlcpy(if_name, IPADM_NONESTR,
944 974 sizeof (if_name));
945 975 } else if (if_indextoname(lifr.lifr_index, if_name) == NULL) {
946 976 return (ipadm_errno2status(errno));
947 977 }
948 978 nbytes = snprintf(buf, *bufsize, "%s", if_name);
949 979 break;
950 980 default:
951 981 return (IPADM_INVALID_ARG);
952 982 }
953 983 if (nbytes >= *bufsize) {
954 984 /* insufficient buffer space */
955 985 *bufsize = nbytes + 1;
956 986 return (IPADM_NO_BUFS);
957 987 }
958 988 return (IPADM_SUCCESS);
959 989 }
960 990
961 991 /* ARGSUSED */
962 992 static ipadm_status_t
963 993 i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
964 994 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
965 995 uint_t valtype)
966 996 {
967 997 uint64_t intf_flags;
968 998 char *val;
969 999 size_t nbytes;
970 1000 const char *ifname = arg;
971 1001 sa_family_t af;
972 1002 ipadm_status_t status = IPADM_SUCCESS;
973 1003
974 1004 switch (valtype) {
975 1005 case MOD_PROP_PERM:
976 1006 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
977 1007 break;
978 1008 case MOD_PROP_DEFAULT:
979 1009 if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
980 1010 strcmp(pdp->ipd_name, "arp") == 0 ||
981 1011 strcmp(pdp->ipd_name, "nud") == 0) {
982 1012 val = IPADM_ONSTR;
983 1013 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
984 1014 val = IPADM_OFFSTR;
985 1015 } else {
986 1016 return (IPADM_PROP_UNKNOWN);
987 1017 }
988 1018 nbytes = snprintf(buf, *bufsize, "%s", val);
989 1019 break;
990 1020 case MOD_PROP_ACTIVE:
991 1021 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
992 1022 status = i_ipadm_get_flags(iph, ifname, af, &intf_flags);
993 1023 if (status != IPADM_SUCCESS)
994 1024 return (status);
995 1025
996 1026 val = IPADM_OFFSTR;
997 1027 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
998 1028 if (!(intf_flags & IFF_NORTEXCH))
999 1029 val = IPADM_ONSTR;
1000 1030 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
1001 1031 if (intf_flags & IFF_ROUTER)
1002 1032 val = IPADM_ONSTR;
1003 1033 } else if (strcmp(pdp->ipd_name, "arp") == 0) {
1004 1034 if (!(intf_flags & IFF_NOARP))
1005 1035 val = IPADM_ONSTR;
1006 1036 } else if (strcmp(pdp->ipd_name, "nud") == 0) {
1007 1037 if (!(intf_flags & IFF_NONUD))
1008 1038 val = IPADM_ONSTR;
1009 1039 }
1010 1040 nbytes = snprintf(buf, *bufsize, "%s", val);
1011 1041 break;
1012 1042 default:
1013 1043 return (IPADM_INVALID_ARG);
1014 1044 }
1015 1045 if (nbytes >= *bufsize) {
1016 1046 /* insufficient buffer space */
1017 1047 *bufsize = nbytes + 1;
1018 1048 status = IPADM_NO_BUFS;
1019 1049 }
1020 1050
1021 1051 return (status);
1022 1052 }
1023 1053
1024 1054 static void
1025 1055 i_ipadm_perm2str(char *buf, uint_t *bufsize)
1026 1056 {
1027 1057 uint_t perm = atoi(buf);
1028 1058
1029 1059 (void) snprintf(buf, *bufsize, "%c%c",
1030 1060 ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
1031 1061 ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
1032 1062 }
1033 1063
1034 1064 /* ARGSUSED */
1035 1065 static ipadm_status_t
1036 1066 i_ipadm_get_prop(ipadm_handle_t iph, const void *arg,
1037 1067 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
1038 1068 uint_t valtype)
1039 1069 {
1040 1070 ipadm_status_t status = IPADM_SUCCESS;
1041 1071 const char *ifname = arg;
1042 1072 mod_ioc_prop_t *mip;
1043 1073 char *pname = pdp->ipd_name;
1044 1074 uint_t iocsize;
1045 1075
1046 1076 /* allocate sufficient ioctl buffer to retrieve value */
1047 1077 iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1;
1048 1078 if ((mip = calloc(1, iocsize)) == NULL)
1049 1079 return (IPADM_NO_BUFS);
1050 1080
1051 1081 mip->mpr_version = MOD_PROP_VERSION;
1052 1082 mip->mpr_flags = valtype;
1053 1083 mip->mpr_proto = proto;
1054 1084 if (ifname != NULL) {
1055 1085 (void) strlcpy(mip->mpr_ifname, ifname,
1056 1086 sizeof (mip->mpr_ifname));
1057 1087 }
1058 1088 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1059 1089 mip->mpr_valsize = *bufsize;
1060 1090
1061 1091 if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip,
1062 1092 iocsize) < 0) {
1063 1093 if (errno == ENOENT)
1064 1094 status = IPADM_PROP_UNKNOWN;
1065 1095 else
1066 1096 status = ipadm_errno2status(errno);
1067 1097 } else {
1068 1098 bcopy(mip->mpr_val, buf, *bufsize);
1069 1099 }
1070 1100
1071 1101 free(mip);
1072 1102 return (status);
1073 1103 }
1074 1104
1075 1105 /*
1076 1106 * Populates the ipmgmt_prop_arg_t based on the class of property.
1077 1107 *
1078 1108 * For private protocol properties, while persisting information in ipadm
1079 1109 * data store, to ensure there is no collision of namespace between ipadm
1080 1110 * private nvpair names (which also starts with '_', see ipadm_ipmgmt.h)
1081 1111 * and private protocol property names, we will prepend IPADM_PRIV_PROP_PREFIX
1082 1112 * to property names.
1083 1113 */
1084 1114 static void
1085 1115 i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp,
1086 1116 const char *pval, const void *object)
1087 1117 {
1088 1118 const struct ipadm_addrobj_s *ipaddr;
1089 1119 uint_t class = pdp->ipd_class;
1090 1120 uint_t proto = pdp->ipd_proto;
1091 1121
1092 1122 (void) strlcpy(pargp->ia_pname, pdp->ipd_name,
1093 1123 sizeof (pargp->ia_pname));
1094 1124 if (pval != NULL)
1095 1125 (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
1096 1126
1097 1127 switch (class) {
1098 1128 case IPADMPROP_CLASS_MODULE:
1099 1129 /* if it's a private property then add the prefix. */
1100 1130 if (pdp->ipd_name[0] == '_') {
1101 1131 (void) snprintf(pargp->ia_pname,
1102 1132 sizeof (pargp->ia_pname), "_%s", pdp->ipd_name);
1103 1133 }
1104 1134 (void) strlcpy(pargp->ia_module, object,
1105 1135 sizeof (pargp->ia_module));
1106 1136 break;
1107 1137 case IPADMPROP_CLASS_MODIF:
1108 1138 /* check if object is protostr or an ifname */
1109 1139 if (ipadm_str2proto(object) != MOD_PROTO_NONE) {
1110 1140 (void) strlcpy(pargp->ia_module, object,
1111 1141 sizeof (pargp->ia_module));
1112 1142 break;
1113 1143 }
1114 1144 /* it's an interface property, fall through */
1115 1145 /* FALLTHRU */
1116 1146 case IPADMPROP_CLASS_IF:
1117 1147 (void) strlcpy(pargp->ia_ifname, object,
1118 1148 sizeof (pargp->ia_ifname));
1119 1149 (void) strlcpy(pargp->ia_module, ipadm_proto2str(proto),
1120 1150 sizeof (pargp->ia_module));
1121 1151 break;
1122 1152 case IPADMPROP_CLASS_ADDR:
1123 1153 ipaddr = object;
1124 1154 (void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname,
1125 1155 sizeof (pargp->ia_ifname));
1126 1156 (void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname,
1127 1157 sizeof (pargp->ia_aobjname));
1128 1158 break;
1129 1159 }
1130 1160 }
1131 1161
1132 1162 /*
1133 1163 * Common function to retrieve property value for a given interface `ifname' or
1134 1164 * for a given protocol `proto'. The property name is in `pname'.
1135 1165 *
1136 1166 * `valtype' determines the type of value that will be retrieved.
1137 1167 * IPADM_OPT_ACTIVE - current value of the property (active config)
1138 1168 * IPADM_OPT_PERSIST - value of the property from persistent store
1139 1169 * IPADM_OPT_DEFAULT - default hard coded value (boot-time value)
1140 1170 * IPADM_OPT_PERM - read/write permissions for the value
1141 1171 * IPADM_OPT_POSSIBLE - range of values
1142 1172 */
1143 1173 static ipadm_status_t
1144 1174 i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname,
1145 1175 const char *pname, char *buf, uint_t *bufsize, uint_t proto,
1146 1176 uint_t valtype)
1147 1177 {
1148 1178 ipadm_status_t status = IPADM_SUCCESS;
1149 1179 ipadm_prop_desc_t *pdp;
1150 1180 char priv_propname[MAXPROPNAMELEN];
1151 1181 boolean_t is_if = (ifname != NULL);
1152 1182 int err = 0;
1153 1183
1154 1184 pdp = i_ipadm_get_prop_desc(pname, proto, &err);
1155 1185 if (err == EPROTO)
1156 1186 return (IPADM_BAD_PROTOCOL);
1157 1187 /* there are no private interface properties */
1158 1188 if (is_if && err == ENOENT)
1159 1189 return (IPADM_PROP_UNKNOWN);
1160 1190
1161 1191 if (pdp != NULL) {
1162 1192 /*
1163 1193 * check whether the property can be
1164 1194 * applied on an interface
1165 1195 */
1166 1196 if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF))
1167 1197 return (IPADM_INVALID_ARG);
1168 1198 /*
1169 1199 * check whether the property can be
1170 1200 * applied on a module
1171 1201 */
1172 1202 if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1173 1203 return (IPADM_INVALID_ARG);
1174 1204
1175 1205 } else {
1176 1206 /* private protocol properties, pass it to kernel directly */
1177 1207 pdp = &ipadm_privprop;
1178 1208 (void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1179 1209 pdp->ipd_name = priv_propname;
1180 1210 }
1181 1211
1182 1212 switch (valtype) {
1183 1213 case IPADM_OPT_PERM:
1184 1214 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1185 1215 MOD_PROP_PERM);
1186 1216 if (status == IPADM_SUCCESS)
1187 1217 i_ipadm_perm2str(buf, bufsize);
1188 1218 break;
1189 1219 case IPADM_OPT_ACTIVE:
1190 1220 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1191 1221 MOD_PROP_ACTIVE);
1192 1222 break;
1193 1223 case IPADM_OPT_DEFAULT:
1194 1224 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1195 1225 MOD_PROP_DEFAULT);
1196 1226 break;
1197 1227 case IPADM_OPT_POSSIBLE:
1198 1228 if (pdp->ipd_get_range != NULL) {
1199 1229 status = pdp->ipd_get_range(iph, ifname, pdp, buf,
1200 1230 bufsize, proto, MOD_PROP_POSSIBLE);
1201 1231 break;
1202 1232 }
1203 1233 buf[0] = '\0';
1204 1234 break;
1205 1235 case IPADM_OPT_PERSIST:
1206 1236 /* retrieve from database */
1207 1237 if (is_if)
1208 1238 status = i_ipadm_get_persist_propval(iph, pdp, buf,
1209 1239 bufsize, ifname);
1210 1240 else
1211 1241 status = i_ipadm_get_persist_propval(iph, pdp, buf,
1212 1242 bufsize, ipadm_proto2str(proto));
1213 1243 break;
1214 1244 default:
1215 1245 status = IPADM_INVALID_ARG;
1216 1246 break;
1217 1247 }
1218 1248 return (status);
1219 1249 }
1220 1250
1221 1251 /*
1222 1252 * Get protocol property of the specified protocol.
1223 1253 */
1224 1254 ipadm_status_t
1225 1255 ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf,
1226 1256 uint_t *bufsize, uint_t proto, uint_t valtype)
1227 1257 {
1228 1258 /*
1229 1259 * validate the arguments of the function.
1230 1260 */
1231 1261 if (iph == NULL || pname == NULL || buf == NULL ||
1232 1262 bufsize == NULL || *bufsize == 0) {
1233 1263 return (IPADM_INVALID_ARG);
1234 1264 }
1235 1265 /*
1236 1266 * Do we support this proto, if not return error.
1237 1267 */
1238 1268 if (ipadm_proto2str(proto) == NULL)
1239 1269 return (IPADM_NOTSUP);
1240 1270
1241 1271 return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize,
1242 1272 proto, valtype));
1243 1273 }
1244 1274
1245 1275 /*
1246 1276 * Get interface property of the specified interface.
1247 1277 */
1248 1278 ipadm_status_t
1249 1279 ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1250 1280 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1251 1281 {
1252 1282 /* validate the arguments of the function. */
1253 1283 if (iph == NULL || pname == NULL || buf == NULL ||
1254 1284 bufsize == NULL || *bufsize == 0) {
1255 1285 return (IPADM_INVALID_ARG);
1256 1286 }
1257 1287
1258 1288 /* Do we support this proto, if not return error. */
1259 1289 if (ipadm_proto2str(proto) == NULL)
1260 1290 return (IPADM_NOTSUP);
1261 1291
1262 1292 /*
1263 1293 * check if interface name is provided for interface property and
1264 1294 * is valid.
1265 1295 */
1266 1296 if (!i_ipadm_validate_ifname(iph, ifname))
1267 1297 return (IPADM_INVALID_ARG);
1268 1298
1269 1299 return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize,
1270 1300 proto, valtype));
1271 1301 }
1272 1302
1273 1303 /*
1274 1304 * Allocates sufficient ioctl buffers and copies property name and the
1275 1305 * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
1276 1306 * `pval' will be NULL and it instructs the kernel to reset the current
1277 1307 * value to property's default value.
1278 1308 */
1279 1309 static ipadm_status_t
1280 1310 i_ipadm_set_prop(ipadm_handle_t iph, const void *arg,
1281 1311 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
1282 1312 {
1283 1313 ipadm_status_t status = IPADM_SUCCESS;
1284 1314 const char *ifname = arg;
1285 1315 mod_ioc_prop_t *mip;
1286 1316 char *pname = pdp->ipd_name;
1287 1317 uint_t valsize, iocsize;
1288 1318 uint_t iocflags = 0;
1289 1319
1290 1320 if (flags & IPADM_OPT_DEFAULT) {
1291 1321 iocflags |= MOD_PROP_DEFAULT;
1292 1322 } else if (flags & IPADM_OPT_ACTIVE) {
1293 1323 iocflags |= MOD_PROP_ACTIVE;
1294 1324 if (flags & IPADM_OPT_APPEND)
1295 1325 iocflags |= MOD_PROP_APPEND;
1296 1326 else if (flags & IPADM_OPT_REMOVE)
1297 1327 iocflags |= MOD_PROP_REMOVE;
1298 1328 }
1299 1329
1300 1330 if (pval != NULL) {
1301 1331 valsize = strlen(pval);
1302 1332 iocsize = sizeof (mod_ioc_prop_t) + valsize - 1;
1303 1333 } else {
1304 1334 valsize = 0;
1305 1335 iocsize = sizeof (mod_ioc_prop_t);
1306 1336 }
1307 1337
1308 1338 if ((mip = calloc(1, iocsize)) == NULL)
1309 1339 return (IPADM_NO_BUFS);
1310 1340
1311 1341 mip->mpr_version = MOD_PROP_VERSION;
1312 1342 mip->mpr_flags = iocflags;
1313 1343 mip->mpr_proto = proto;
1314 1344 if (ifname != NULL) {
1315 1345 (void) strlcpy(mip->mpr_ifname, ifname,
1316 1346 sizeof (mip->mpr_ifname));
1317 1347 }
1318 1348
1319 1349 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1320 1350 mip->mpr_valsize = valsize;
1321 1351 if (pval != NULL)
1322 1352 bcopy(pval, mip->mpr_val, valsize);
1323 1353
1324 1354 if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip,
1325 1355 iocsize) < 0) {
1326 1356 if (errno == ENOENT)
1327 1357 status = IPADM_PROP_UNKNOWN;
1328 1358 else
1329 1359 status = ipadm_errno2status(errno);
1330 1360 }
1331 1361 free(mip);
1332 1362 return (status);
1333 1363 }
1334 1364
1335 1365 /*
1336 1366 * Common function for modifying both protocol/interface property.
1337 1367 *
1338 1368 * If:
1339 1369 * IPADM_OPT_PERSIST is set then the value is persisted.
1340 1370 * IPADM_OPT_DEFAULT is set then the default value for the property will
1341 1371 * be applied.
1342 1372 */
1343 1373 static ipadm_status_t
1344 1374 i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname,
1345 1375 const char *pname, const char *buf, uint_t proto, uint_t pflags)
1346 1376 {
1347 1377 ipadm_status_t status = IPADM_SUCCESS;
1348 1378 boolean_t persist = (pflags & IPADM_OPT_PERSIST);
1349 1379 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1350 1380 ipadm_prop_desc_t *pdp;
1351 1381 boolean_t is_if = (ifname != NULL);
1352 1382 char priv_propname[MAXPROPNAMELEN];
1353 1383 int err = 0;
1354 1384
1355 1385 /* Check that property value is within the allowed size */
1356 1386 if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN)
1357 1387 return (IPADM_INVALID_ARG);
1358 1388
1359 1389 pdp = i_ipadm_get_prop_desc(pname, proto, &err);
1360 1390 if (err == EPROTO)
1361 1391 return (IPADM_BAD_PROTOCOL);
1362 1392 /* there are no private interface properties */
1363 1393 if (is_if && err == ENOENT)
1364 1394 return (IPADM_PROP_UNKNOWN);
1365 1395
1366 1396 if (pdp != NULL) {
1367 1397 /* do some sanity checks */
1368 1398 if (is_if) {
1369 1399 if (!(pdp->ipd_class & IPADMPROP_CLASS_IF))
1370 1400 return (IPADM_INVALID_ARG);
1371 1401 } else {
1372 1402 if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1373 1403 return (IPADM_INVALID_ARG);
1374 1404 }
1375 1405 /*
1376 1406 * if the property is not multi-valued and IPADM_OPT_APPEND or
1377 1407 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG.
1378 1408 */
1379 1409 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && (pflags &
1380 1410 (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1381 1411 return (IPADM_INVALID_ARG);
1382 1412 }
1383 1413 } else {
1384 1414 /* private protocol property, pass it to kernel directly */
1385 1415 pdp = &ipadm_privprop;
1386 1416 (void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1387 1417 pdp->ipd_name = priv_propname;
1388 1418 }
1389 1419
1390 1420 status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags);
1391 1421 if (status != IPADM_SUCCESS)
1392 1422 return (status);
1393 1423
1394 1424 if (persist) {
1395 1425 if (is_if)
1396 1426 status = i_ipadm_persist_propval(iph, pdp, buf, ifname,
1397 1427 pflags);
1398 1428 else
1399 1429 status = i_ipadm_persist_propval(iph, pdp, buf,
1400 1430 ipadm_proto2str(proto), pflags);
1401 1431 }
1402 1432 return (status);
1403 1433 }
1404 1434
1405 1435 /*
1406 1436 * Sets the property value of the specified interface
1407 1437 */
1408 1438 ipadm_status_t
1409 1439 ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1410 1440 const char *buf, uint_t proto, uint_t pflags)
1411 1441 {
1412 1442 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1413 1443 ipadm_status_t status;
1414 1444
1415 1445 /* check for solaris.network.interface.config authorization */
1416 1446 if (!ipadm_check_auth())
1417 1447 return (IPADM_EAUTH);
1418 1448 /*
1419 1449 * validate the arguments of the function.
1420 1450 */
1421 1451 if (iph == NULL || pname == NULL || (!reset && buf == NULL) ||
1422 1452 pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1423 1453 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) {
1424 1454 return (IPADM_INVALID_ARG);
1425 1455 }
1426 1456
1427 1457 /*
1428 1458 * Do we support this protocol, if not return error.
1429 1459 */
1430 1460 if (ipadm_proto2str(proto) == NULL)
1431 1461 return (IPADM_NOTSUP);
1432 1462
1433 1463 /*
1434 1464 * Validate the interface and check if a persistent
1435 1465 * operation is performed on a temporary object.
1436 1466 */
1437 1467 status = i_ipadm_validate_if(iph, ifname, proto, pflags);
1438 1468 if (status != IPADM_SUCCESS)
1439 1469 return (status);
1440 1470
1441 1471 return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto,
1442 1472 pflags));
1443 1473 }
1444 1474
1445 1475 /*
1446 1476 * Sets the property value of the specified protocol.
1447 1477 */
1448 1478 ipadm_status_t
1449 1479 ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf,
1450 1480 uint_t proto, uint_t pflags)
1451 1481 {
1452 1482 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1453 1483
1454 1484 /* check for solaris.network.interface.config authorization */
1455 1485 if (!ipadm_check_auth())
1456 1486 return (IPADM_EAUTH);
1457 1487 /*
1458 1488 * validate the arguments of the function.
1459 1489 */
1460 1490 if (iph == NULL || pname == NULL ||(!reset && buf == NULL) ||
1461 1491 pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1462 1492 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT|
1463 1493 IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1464 1494 return (IPADM_INVALID_ARG);
1465 1495 }
1466 1496
1467 1497 /*
1468 1498 * Do we support this proto, if not return error.
1469 1499 */
1470 1500 if (ipadm_proto2str(proto) == NULL)
1471 1501 return (IPADM_NOTSUP);
1472 1502
1473 1503 return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto,
1474 1504 pflags));
1475 1505 }
1476 1506
1477 1507 /* helper function for ipadm_walk_proptbl */
1478 1508 static void
1479 1509 i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class,
1480 1510 ipadm_prop_wfunc_t *func, void *arg)
1481 1511 {
1482 1512 ipadm_prop_desc_t *pdp;
1483 1513
1484 1514 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1485 1515 if (!(pdp->ipd_class & class))
1486 1516 continue;
1487 1517
1488 1518 if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto))
1489 1519 continue;
1490 1520
1491 1521 /*
1492 1522 * we found a class specific match, call the
1493 1523 * user callback function.
1494 1524 */
1495 1525 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1496 1526 break;
1497 1527 }
1498 1528 }
1499 1529
1500 1530 /*
1501 1531 * Walks through all the properties, for a given protocol and property class
1502 1532 * (protocol or interface).
1503 1533 *
1504 1534 * Further if proto == MOD_PROTO_NONE, then it walks through all the supported
1505 1535 * protocol property tables.
1506 1536 */
1507 1537 ipadm_status_t
1508 1538 ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func,
1509 1539 void *arg)
1510 1540 {
1511 1541 ipadm_prop_desc_t *pdtbl;
1512 1542 ipadm_status_t status = IPADM_SUCCESS;
1513 1543 int i;
1514 1544 int count = A_CNT(protocols);
1515 1545
1516 1546 if (func == NULL)
1517 1547 return (IPADM_INVALID_ARG);
1518 1548
1519 1549 switch (class) {
1520 1550 case IPADMPROP_CLASS_ADDR:
1521 1551 pdtbl = ipadm_addrprop_table;
1522 1552 break;
1523 1553 case IPADMPROP_CLASS_IF:
1524 1554 case IPADMPROP_CLASS_MODULE:
1525 1555 pdtbl = i_ipadm_get_propdesc_table(proto);
1526 1556 if (pdtbl == NULL && proto != MOD_PROTO_NONE)
1527 1557 return (IPADM_INVALID_ARG);
1528 1558 break;
1529 1559 default:
1530 1560 return (IPADM_INVALID_ARG);
1531 1561 }
1532 1562
1533 1563 if (pdtbl != NULL) {
1534 1564 /*
1535 1565 * proto will be MOD_PROTO_NONE in the case of
1536 1566 * IPADMPROP_CLASS_ADDR.
1537 1567 */
1538 1568 i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg);
1539 1569 } else {
1540 1570 /* Walk thru all the protocol tables, we support */
1541 1571 for (i = 0; i < count; i++) {
1542 1572 pdtbl = i_ipadm_get_propdesc_table(protocols[i]);
1543 1573 i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func,
1544 1574 arg);
1545 1575 }
1546 1576 }
1547 1577 return (status);
1548 1578 }
1549 1579
1550 1580 /*
1551 1581 * Given a property name, walks through all the instances of a property name.
1552 1582 * Some properties have two instances one for v4 interfaces and another for v6
1553 1583 * interfaces. For example: MTU. MTU can have different values for v4 and v6.
1554 1584 * Therefore there are two properties for 'MTU'.
1555 1585 *
1556 1586 * This function invokes `func' for every instance of property `pname'
1557 1587 */
1558 1588 ipadm_status_t
1559 1589 ipadm_walk_prop(const char *pname, uint_t proto, uint_t class,
1560 1590 ipadm_prop_wfunc_t *func, void *arg)
1561 1591 {
1562 1592 ipadm_prop_desc_t *pdtbl, *pdp;
1563 1593 ipadm_status_t status = IPADM_SUCCESS;
1564 1594 boolean_t matched = B_FALSE;
1565 1595
1566 1596 if (pname == NULL || func == NULL)
1567 1597 return (IPADM_INVALID_ARG);
1568 1598
1569 1599 switch (class) {
1570 1600 case IPADMPROP_CLASS_ADDR:
1571 1601 pdtbl = ipadm_addrprop_table;
1572 1602 break;
1573 1603 case IPADMPROP_CLASS_IF:
1574 1604 case IPADMPROP_CLASS_MODULE:
1575 1605 pdtbl = i_ipadm_get_propdesc_table(proto);
1576 1606 break;
1577 1607 default:
1578 1608 return (IPADM_INVALID_ARG);
1579 1609 }
1580 1610
1581 1611 if (pdtbl == NULL)
1582 1612 return (IPADM_INVALID_ARG);
1583 1613
1584 1614 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1585 1615 if (strcmp(pname, pdp->ipd_name) != 0)
1586 1616 continue;
1587 1617 if (!(pdp->ipd_proto & proto))
1588 1618 continue;
1589 1619 matched = B_TRUE;
1590 1620 /* we found a match, call the callback function */
1591 1621 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1592 1622 break;
1593 1623 }
1594 1624 if (!matched)
1595 1625 status = IPADM_PROP_UNKNOWN;
1596 1626 return (status);
1597 1627 }
1598 1628
1599 1629 /* ARGSUSED */
1600 1630 ipadm_status_t
1601 1631 i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp,
1602 1632 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1603 1633 {
1604 1634 (void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR);
1605 1635 return (IPADM_SUCCESS);
1606 1636 }
1607 1637
1608 1638 /*
1609 1639 * Makes a door call to ipmgmtd to retrieve the persisted property value
1610 1640 */
1611 1641 ipadm_status_t
1612 1642 i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1613 1643 char *gbuf, uint_t *gbufsize, const void *object)
1614 1644 {
1615 1645 ipmgmt_prop_arg_t parg;
1616 1646 ipmgmt_getprop_rval_t rval, *rvalp;
1617 1647 size_t nbytes;
1618 1648 int err = 0;
1619 1649
1620 1650 bzero(&parg, sizeof (parg));
1621 1651 parg.ia_cmd = IPMGMT_CMD_GETPROP;
1622 1652 i_ipadm_populate_proparg(&parg, pdp, NULL, object);
1623 1653
1624 1654 rvalp = &rval;
1625 1655 err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp,
1626 1656 sizeof (rval), B_FALSE);
1627 1657 if (err == 0) {
1628 1658 /* assert that rvalp was not reallocated */
1629 1659 assert(rvalp == &rval);
1630 1660
1631 1661 /* `ir_pval' contains the property value */
1632 1662 nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval);
1633 1663 if (nbytes >= *gbufsize) {
1634 1664 /* insufficient buffer space */
1635 1665 *gbufsize = nbytes + 1;
1636 1666 err = ENOBUFS;
1637 1667 }
1638 1668 }
1639 1669 return (ipadm_errno2status(err));
1640 1670 }
1641 1671
1642 1672 /*
1643 1673 * Persists the property value for a given property in the data store
1644 1674 */
1645 1675 ipadm_status_t
1646 1676 i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1647 1677 const char *pval, const void *object, uint_t flags)
1648 1678 {
1649 1679 ipmgmt_prop_arg_t parg;
1650 1680 int err = 0;
1651 1681
1652 1682 bzero(&parg, sizeof (parg));
1653 1683 i_ipadm_populate_proparg(&parg, pdp, pval, object);
1654 1684 /*
1655 1685 * Check if value to be persisted need to be appended or removed. This
1656 1686 * is required for multi-valued property.
1657 1687 */
1658 1688 if (flags & IPADM_OPT_APPEND)
1659 1689 parg.ia_flags |= IPMGMT_APPEND;
1660 1690 if (flags & IPADM_OPT_REMOVE)
1661 1691 parg.ia_flags |= IPMGMT_REMOVE;
1662 1692
1663 1693 if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE))
1664 1694 parg.ia_cmd = IPMGMT_CMD_RESETPROP;
1665 1695 else
1666 1696 parg.ia_cmd = IPMGMT_CMD_SETPROP;
1667 1697
1668 1698 err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE);
1669 1699
1670 1700 /*
1671 1701 * its fine if there were no entry in the DB to delete. The user
1672 1702 * might be changing property value, which was not changed
1673 1703 * persistently.
1674 1704 */
1675 1705 if (err == ENOENT)
1676 1706 err = 0;
1677 1707 return (ipadm_errno2status(err));
1678 1708 }
1679 1709
1680 1710 /*
1681 1711 * This is called from ipadm_set_ifprop() to validate the set operation.
1682 1712 * It does the following steps:
1683 1713 * 1. Validates the interface name.
1684 1714 * 2. Fails if it is an IPMP meta-interface or an underlying interface.
1685 1715 * 3. In case of a persistent operation, verifies that the
1686 1716 * interface is persistent.
1687 1717 */
1688 1718 static ipadm_status_t
1689 1719 i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname,
1690 1720 uint_t proto, uint_t flags)
1691 1721 {
1692 1722 sa_family_t af, other_af;
1693 1723 ipadm_status_t status;
1694 1724 boolean_t p_exists;
1695 1725 boolean_t af_exists, other_af_exists, a_exists;
1696 1726
1697 1727 /* Check if the interface name is valid. */
1698 1728 if (!i_ipadm_validate_ifname(iph, ifname))
1699 1729 return (IPADM_INVALID_ARG);
1700 1730
1701 1731 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
1702 1732 /*
1703 1733 * Setting properties on an IPMP meta-interface or underlying
1704 1734 * interface is not supported.
1705 1735 */
1706 1736 if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
1707 1737 return (IPADM_NOTSUP);
1708 1738
1709 1739 /* Check if interface exists in the persistent configuration. */
1710 1740 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1711 1741 if (status != IPADM_SUCCESS)
1712 1742 return (status);
1713 1743
1714 1744 /* Check if interface exists in the active configuration. */
1715 1745 af_exists = ipadm_if_enabled(iph, ifname, af);
1716 1746 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1717 1747 other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
1718 1748 a_exists = (af_exists || other_af_exists);
1719 1749 if (!a_exists && p_exists)
1720 1750 return (IPADM_OP_DISABLE_OBJ);
1721 1751 if (!af_exists)
1722 1752 return (IPADM_ENXIO);
1723 1753
1724 1754 /*
1725 1755 * If a persistent operation is requested, check if the underlying
1726 1756 * IP interface is persistent.
1727 1757 */
1728 1758 if ((flags & IPADM_OPT_PERSIST) && !p_exists)
1729 1759 return (IPADM_TEMPORARY_OBJ);
1730 1760 return (IPADM_SUCCESS);
1731 1761 }
1732 1762
1733 1763 /*
1734 1764 * Private protocol properties namespace scheme:
1735 1765 *
1736 1766 * PSARC 2010/080 identified the private protocol property names to be the
1737 1767 * leading protocol names. For e.g. tcp_strong_iss, ip_strict_src_multihoming,
1738 1768 * et al,. However to be consistent with private data-link property names,
1739 1769 * which starts with '_', private protocol property names will start with '_'.
1740 1770 * For e.g. _strong_iss, _strict_src_multihoming, et al,.
1741 1771 */
1742 1772
1743 1773 /* maps new private protocol property name to the old private property name */
1744 1774 typedef struct ipadm_oname2nname_map {
1745 1775 char *iom_oname;
1746 1776 char *iom_nname;
1747 1777 uint_t iom_proto;
1748 1778 } ipadm_oname2nname_map_t;
1749 1779
1750 1780 /*
1751 1781 * IP is a special case. It isn't straight forward to derive the legacy name
1752 1782 * from the new name and vice versa. No set standard was followed in naming
1753 1783 * the properties and hence we need a table to capture the mapping.
1754 1784 */
1755 1785 static ipadm_oname2nname_map_t name_map[] = {
1756 1786 { "arp_probe_delay", "_arp_probe_delay",
1757 1787 MOD_PROTO_IP },
1758 1788 { "arp_fastprobe_delay", "_arp_fastprobe_delay",
1759 1789 MOD_PROTO_IP },
1760 1790 { "arp_probe_interval", "_arp_probe_interval",
1761 1791 MOD_PROTO_IP },
1762 1792 { "arp_fastprobe_interval", "_arp_fastprobe_interval",
1763 1793 MOD_PROTO_IP },
1764 1794 { "arp_probe_count", "_arp_probe_count",
1765 1795 MOD_PROTO_IP },
1766 1796 { "arp_fastprobe_count", "_arp_fastprobe_count",
1767 1797 MOD_PROTO_IP },
1768 1798 { "arp_defend_interval", "_arp_defend_interval",
1769 1799 MOD_PROTO_IP },
1770 1800 { "arp_defend_rate", "_arp_defend_rate",
1771 1801 MOD_PROTO_IP },
1772 1802 { "arp_defend_period", "_arp_defend_period",
1773 1803 MOD_PROTO_IP },
1774 1804 { "ndp_defend_interval", "_ndp_defend_interval",
1775 1805 MOD_PROTO_IP },
1776 1806 { "ndp_defend_rate", "_ndp_defend_rate",
1777 1807 MOD_PROTO_IP },
1778 1808 { "ndp_defend_period", "_ndp_defend_period",
1779 1809 MOD_PROTO_IP },
1780 1810 { "igmp_max_version", "_igmp_max_version",
1781 1811 MOD_PROTO_IP },
1782 1812 { "mld_max_version", "_mld_max_version",
1783 1813 MOD_PROTO_IP },
1784 1814 { "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy",
1785 1815 MOD_PROTO_IP },
1786 1816 { "ipsec_policy_log_interval", "_ipsec_policy_log_interval",
1787 1817 MOD_PROTO_IP },
1788 1818 { "icmp_accept_clear_messages", "_icmp_accept_clear_messages",
1789 1819 MOD_PROTO_IP },
1790 1820 { "igmp_accept_clear_messages", "_igmp_accept_clear_messages",
1791 1821 MOD_PROTO_IP },
1792 1822 { "pim_accept_clear_messages", "_pim_accept_clear_messages",
1793 1823 MOD_PROTO_IP },
1794 1824 { "ip_respond_to_echo_multicast", "_respond_to_echo_multicast",
1795 1825 MOD_PROTO_IPV4 },
1796 1826 { "ip_send_redirects", "_send_redirects",
1797 1827 MOD_PROTO_IPV4 },
1798 1828 { "ip_forward_src_routed", "_forward_src_routed",
1799 1829 MOD_PROTO_IPV4 },
1800 1830 { "ip_icmp_return_data_bytes", "_icmp_return_data_bytes",
1801 1831 MOD_PROTO_IPV4 },
1802 1832 { "ip_ignore_redirect", "_ignore_redirect",
1803 1833 MOD_PROTO_IPV4 },
1804 1834 { "ip_strict_dst_multihoming", "_strict_dst_multihoming",
1805 1835 MOD_PROTO_IPV4 },
1806 1836 { "ip_reasm_timeout", "_reasm_timeout",
1807 1837 MOD_PROTO_IPV4 },
1808 1838 { "ip_strict_src_multihoming", "_strict_src_multihoming",
1809 1839 MOD_PROTO_IPV4 },
1810 1840 { "ipv4_dad_announce_interval", "_dad_announce_interval",
1811 1841 MOD_PROTO_IPV4 },
1812 1842 { "ipv4_icmp_return_pmtu", "_icmp_return_pmtu",
1813 1843 MOD_PROTO_IPV4 },
1814 1844 { "ipv6_dad_announce_interval", "_dad_announce_interval",
1815 1845 MOD_PROTO_IPV6 },
1816 1846 { "ipv6_icmp_return_pmtu", "_icmp_return_pmtu",
1817 1847 MOD_PROTO_IPV6 },
1818 1848 { NULL, NULL, MOD_PROTO_NONE }
1819 1849 };
1820 1850
1821 1851 /*
1822 1852 * Following API returns a new property name in `nname' for the given legacy
1823 1853 * property name in `oname'.
1824 1854 */
1825 1855 int
1826 1856 ipadm_legacy2new_propname(const char *oname, char *nname, uint_t nnamelen,
1827 1857 uint_t *proto)
1828 1858 {
1829 1859 const char *str;
1830 1860 ipadm_oname2nname_map_t *ionmp;
1831 1861
1832 1862 /* if it's a public property, there is nothing to return */
1833 1863 if (i_ipadm_get_prop_desc(oname, *proto, NULL) != NULL)
1834 1864 return (-1);
1835 1865
1836 1866 /*
1837 1867 * we didn't find the `oname' in the table, check if the property
1838 1868 * name begins with a leading protocol.
1839 1869 */
1840 1870 str = oname;
1841 1871 switch (*proto) {
1842 1872 case MOD_PROTO_TCP:
1843 1873 if (strstr(oname, "tcp_") == oname)
1844 1874 str += strlen("tcp");
1845 1875 break;
1846 1876 case MOD_PROTO_SCTP:
1847 1877 if (strstr(oname, "sctp_") == oname)
1848 1878 str += strlen("sctp");
1849 1879 break;
1850 1880 case MOD_PROTO_UDP:
1851 1881 if (strstr(oname, "udp_") == oname)
1852 1882 str += strlen("udp");
1853 1883 break;
1854 1884 case MOD_PROTO_RAWIP:
1855 1885 if (strstr(oname, "icmp_") == oname)
1856 1886 str += strlen("icmp");
1857 1887 break;
1858 1888 case MOD_PROTO_IP:
1859 1889 case MOD_PROTO_IPV4:
1860 1890 case MOD_PROTO_IPV6:
1861 1891 if (strstr(oname, "ip6_") == oname) {
1862 1892 *proto = MOD_PROTO_IPV6;
1863 1893 str += strlen("ip6");
1864 1894 } else {
1865 1895 for (ionmp = name_map; ionmp->iom_oname != NULL;
1866 1896 ionmp++) {
1867 1897 if (strcmp(oname, ionmp->iom_oname) == 0) {
1868 1898 str = ionmp->iom_nname;
1869 1899 *proto = ionmp->iom_proto;
1870 1900 break;
1871 1901 }
1872 1902 }
1873 1903 if (ionmp->iom_oname != NULL)
1874 1904 break;
1875 1905
1876 1906 if (strstr(oname, "ip_") == oname) {
1877 1907 *proto = MOD_PROTO_IP;
1878 1908 str += strlen("ip");
1879 1909 }
1880 1910 }
1881 1911 break;
1882 1912 default:
1883 1913 return (-1);
1884 1914 }
1885 1915 (void) snprintf(nname, nnamelen, "%s", str);
1886 1916 return (0);
1887 1917 }
1888 1918
1889 1919 /*
1890 1920 * Following API is required for ndd.c alone. To maintain backward
1891 1921 * compatibility with ndd output, we need to print the legacy name
1892 1922 * for the new name.
1893 1923 */
1894 1924 int
1895 1925 ipadm_new2legacy_propname(const char *oname, char *nname,
1896 1926 uint_t nnamelen, uint_t proto)
1897 1927 {
1898 1928 char *prefix;
1899 1929 ipadm_oname2nname_map_t *ionmp;
1900 1930
1901 1931 /* if it's a public property, there is nothing to prepend */
1902 1932 if (i_ipadm_get_prop_desc(oname, proto, NULL) != NULL)
1903 1933 return (-1);
1904 1934
1905 1935 switch (proto) {
1906 1936 case MOD_PROTO_TCP:
1907 1937 prefix = "tcp";
1908 1938 break;
1909 1939 case MOD_PROTO_SCTP:
1910 1940 prefix = "sctp";
1911 1941 break;
1912 1942 case MOD_PROTO_UDP:
1913 1943 prefix = "udp";
1914 1944 break;
1915 1945 case MOD_PROTO_RAWIP:
1916 1946 prefix = "icmp";
1917 1947 break;
1918 1948 case MOD_PROTO_IP:
1919 1949 case MOD_PROTO_IPV4:
1920 1950 case MOD_PROTO_IPV6:
1921 1951 /* handle special case for IP */
1922 1952 for (ionmp = name_map; ionmp->iom_oname != NULL; ionmp++) {
1923 1953 if (strcmp(oname, ionmp->iom_nname) == 0 &&
1924 1954 ionmp->iom_proto == proto) {
1925 1955 (void) strlcpy(nname, ionmp->iom_oname,
1926 1956 nnamelen);
1927 1957 return (0);
1928 1958 }
1929 1959 }
1930 1960 if (proto == MOD_PROTO_IPV6)
1931 1961 prefix = "ip6";
1932 1962 else
1933 1963 prefix = "ip";
1934 1964 break;
1935 1965 default:
1936 1966 return (-1);
1937 1967 }
1938 1968 (void) snprintf(nname, nnamelen, "%s%s", prefix, oname);
1939 1969 return (0);
1940 1970 }
↓ open down ↓ |
1582 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX