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) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <strings.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <stddef.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/dld.h>
34 #include <sys/zone.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <libdevinfo.h>
38 #include <zone.h>
39 #include <libdllink.h>
40 #include <libdladm_impl.h>
41 #include <libdlwlan_impl.h>
42 #include <libdlwlan.h>
43 #include <libdlvlan.h>
44 #include <libdlvnic.h>
45 #include <libdlib.h>
46 #include <libintl.h>
47 #include <dlfcn.h>
48 #include <link.h>
49 #include <inet/wifi_ioctl.h>
50 #include <libdladm.h>
51 #include <libdlstat.h>
52 #include <sys/param.h>
53 #include <sys/debug.h>
54 #include <sys/dld.h>
55 #include <inttypes.h>
56 #include <sys/ethernet.h>
57 #include <inet/iptun.h>
58 #include <net/wpa.h>
59 #include <sys/sysmacros.h>
60 #include <sys/vlan.h>
61 #include <libdlbridge.h>
62 #include <stp_in.h>
63 #include <netinet/dhcp.h>
64 #include <netinet/dhcp6.h>
65 #include <net/if_types.h>
66 #include <libinetutil.h>
67 #include <pool.h>
68
69 /*
70 * The linkprop get() callback.
71 * - pd: pointer to the prop_desc_t
72 * - propstrp: a property string array to keep the returned property.
73 * Caller allocated.
74 * - cntp: number of returned properties.
75 * Caller also uses it to indicate how many it expects.
76 */
77 struct prop_desc;
78 typedef struct prop_desc prop_desc_t;
79
80 typedef dladm_status_t pd_getf_t(dladm_handle_t, prop_desc_t *pdp,
81 datalink_id_t, char **propstp, uint_t *cntp,
82 datalink_media_t, uint_t, uint_t *);
83
84 /*
85 * The linkprop set() callback.
86 * - propval: a val_desc_t array which keeps the property values to be set.
87 * - cnt: number of properties to be set.
88 * - flags: additional flags passed down the system call.
89 *
90 * pd_set takes val_desc_t given by pd_check(), translates it into
91 * a format suitable for kernel consumption. This may require allocation
92 * of ioctl buffers etc. pd_set() may call another common routine (used
93 * by all other pd_sets) which invokes the ioctl.
94 */
95 typedef dladm_status_t pd_setf_t(dladm_handle_t, prop_desc_t *, datalink_id_t,
96 val_desc_t *propval, uint_t cnt, uint_t flags,
97 datalink_media_t);
98
99 /*
100 * The linkprop check() callback.
101 * - propstrp: property string array which keeps the property to be checked.
102 * - cnt: number of properties.
103 * - propval: return value; the property values of the given property strings.
104 *
105 * pd_check checks that the input values are valid. It does so by
106 * iteraring through the pd_modval list for the property. If
107 * the modifiable values cannot be expressed as a list, a pd_check
108 * specific to this property can be used. If the input values are
109 * verified to be valid, pd_check allocates a val_desc_t and fills it
110 * with either a val_desc_t found on the pd_modval list or something
111 * generated on the fly.
112 */
113 typedef dladm_status_t pd_checkf_t(dladm_handle_t, prop_desc_t *pdp,
114 datalink_id_t, char **propstrp, uint_t *cnt,
115 uint_t flags, val_desc_t **propval,
116 datalink_media_t);
117
118 typedef struct link_attr_s {
119 mac_prop_id_t pp_id;
120 size_t pp_valsize;
121 char *pp_name;
122 } link_attr_t;
123
124 typedef struct dladm_linkprop_args_s {
125 dladm_status_t dla_status;
126 uint_t dla_flags;
127 } dladm_linkprop_args_t;
128
129 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t,
130 const char *, uint_t, dladm_status_t *);
131 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t,
132 mac_prop_id_t, uint_t, dladm_status_t *);
133 static dladm_status_t i_dladm_get_public_prop(dladm_handle_t, datalink_id_t,
134 char *, uint_t, uint_t *, void *, size_t);
135
136 static dladm_status_t i_dladm_set_private_prop(dladm_handle_t, datalink_id_t,
137 const char *, char **, uint_t, uint_t);
138 static dladm_status_t i_dladm_get_priv_prop(dladm_handle_t, datalink_id_t,
139 const char *, char **, uint_t *, dladm_prop_type_t,
140 uint_t);
141 static dladm_status_t i_dladm_macprop(dladm_handle_t, void *, boolean_t);
142 static const char *dladm_perm2str(uint_t, char *);
143 static link_attr_t *dladm_name2prop(const char *);
144 static link_attr_t *dladm_id2prop(mac_prop_id_t);
145
146 static pd_getf_t get_zone, get_autopush, get_rate_mod, get_rate,
147 get_speed, get_channel, get_powermode, get_radio,
148 get_duplex, get_link_state, get_binary, get_uint32,
149 get_flowctl, get_maxbw, get_cpus, get_priority,
150 get_tagmode, get_range, get_stp, get_bridge_forward,
151 get_bridge_pvid, get_protection, get_rxrings,
152 get_txrings, get_cntavail,
153 get_allowedips, get_allowedcids, get_pool,
154 get_rings_range, get_linkmode_prop;
155
156 static pd_setf_t set_zone, set_rate, set_powermode, set_radio,
157 set_public_prop, set_resource, set_stp_prop,
158 set_bridge_forward, set_bridge_pvid;
159
160 static pd_checkf_t check_zone, check_autopush, check_rate, check_hoplimit,
161 check_encaplim, check_uint32, check_maxbw, check_cpus,
162 check_stp_prop, check_bridge_pvid, check_allowedips,
163 check_allowedcids, check_rings,
164 check_pool, check_prop;
165
166 struct prop_desc {
167 /*
168 * link property name
169 */
170 char *pd_name;
171
172 /*
173 * default property value, can be set to { "", NULL }
174 */
175 val_desc_t pd_defval;
176
177 /*
178 * list of optional property values, can be NULL.
179 *
180 * This is set to non-NULL if there is a list of possible property
181 * values. pd_optval would point to the array of possible values.
182 */
183 val_desc_t *pd_optval;
184
185 /*
186 * count of the above optional property values. 0 if pd_optval is NULL.
187 */
188 uint_t pd_noptval;
189
190 /*
191 * callback to set link property; set to NULL if this property is
192 * read-only and may be called before or after permanent update; see
193 * flags.
194 */
195 pd_setf_t *pd_set;
196
197 /*
198 * callback to get modifiable link property
199 */
200 pd_getf_t *pd_getmod;
201
202 /*
203 * callback to get current link property
204 */
205 pd_getf_t *pd_get;
206
207 /*
208 * callback to validate link property value, set to NULL if pd_optval
209 * is not NULL. In that case, validate the value by comparing it with
210 * the pd_optval. Return a val_desc_t array pointer if the value is
211 * valid.
212 */
213 pd_checkf_t *pd_check;
214
215 uint_t pd_flags;
216 #define PD_TEMPONLY 0x1 /* property is temporary only */
217 #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */
218 #define PD_AFTER_PERM 0x4 /* pd_set after db update; no temporary */
219 /*
220 * indicate link classes this property applies to.
221 */
222 datalink_class_t pd_class;
223
224 /*
225 * indicate link media type this property applies to.
226 */
227 datalink_media_t pd_dmedia;
228 };
229
230 #define MAC_PROP_BUFSIZE(v) sizeof (dld_ioc_macprop_t) + (v) - 1
231
232 /*
233 * Supported link properties enumerated in the prop_table[] array are
234 * computed using the callback functions in that array. To compute the
235 * property value, multiple distinct system calls may be needed (e.g.,
236 * for wifi speed, we need to issue system calls to get desired/supported
237 * rates). The link_attr[] table enumerates the interfaces to the kernel,
238 * and the type/size of the data passed in the user-kernel interface.
239 */
240 static link_attr_t link_attr[] = {
241 { MAC_PROP_DUPLEX, sizeof (link_duplex_t), "duplex"},
242
243 { MAC_PROP_SPEED, sizeof (uint64_t), "speed"},
244
245 { MAC_PROP_STATUS, sizeof (link_state_t), "state"},
246
247 { MAC_PROP_AUTONEG, sizeof (uint8_t), "adv_autoneg_cap"},
248
249 { MAC_PROP_MTU, sizeof (uint32_t), "mtu"},
250
251 { MAC_PROP_FLOWCTRL, sizeof (link_flowctrl_t), "flowctrl"},
252
253 { MAC_PROP_ZONE, sizeof (dld_ioc_zid_t), "zone"},
254
255 { MAC_PROP_AUTOPUSH, sizeof (struct dlautopush), "autopush"},
256
257 { MAC_PROP_ADV_10GFDX_CAP, sizeof (uint8_t), "adv_10gfdx_cap"},
258
259 { MAC_PROP_EN_10GFDX_CAP, sizeof (uint8_t), "en_10gfdx_cap"},
260
261 { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), "adv_1000fdx_cap"},
262
263 { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t), "en_1000fdx_cap"},
264
265 { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), "adv_1000hdx_cap"},
266
267 { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t), "en_1000hdx_cap"},
268
269 { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t), "adv_100fdx_cap"},
270
271 { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t), "en_100fdx_cap"},
272
273 { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t), "adv_100hdx_cap"},
274
275 { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t), "en_100hdx_cap"},
276
277 { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t), "adv_10fdx_cap"},
278
279 { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t), "en_10fdx_cap"},
280
281 { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t), "adv_10hdx_cap"},
282
283 { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t), "en_10hdx_cap"},
284
285 { MAC_PROP_WL_ESSID, sizeof (wl_linkstatus_t), "essid"},
286
287 { MAC_PROP_WL_BSSID, sizeof (wl_bssid_t), "bssid"},
288
289 { MAC_PROP_WL_BSSTYPE, sizeof (wl_bss_type_t), "bsstype"},
290
291 { MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
292
293 /* wl_rates_t has variable length */
294 { MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
295
296 /* wl_rates_t has variable length */
297 { MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
298
299 { MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
300
301 { MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
302
303 { MAC_PROP_WL_RSSI, sizeof (wl_rssi_t), "signal"},
304
305 { MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
306
307 { MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
308
309 { MAC_PROP_WL_WPA, sizeof (wl_wpa_t), "wpa"},
310
311 /* wl_wpa_ess_t has variable length */
312 { MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
313
314 { MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
315
316 { MAC_PROP_WL_RADIO, sizeof (dladm_wlan_radio_t), "wl_radio"},
317
318 { MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t), "wl_ess_list"},
319
320 { MAC_PROP_WL_KEY_TAB, sizeof (wl_wep_key_tab_t), "wl_wep_key"},
321
322 { MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
323
324 /* wl_wpa_ie_t has variable length */
325 { MAC_PROP_WL_SETOPTIE, sizeof (wl_wpa_ie_t), "set_ie"},
326
327 { MAC_PROP_WL_DELKEY, sizeof (wl_del_key_t), "wpa_del_key"},
328
329 { MAC_PROP_WL_KEY, sizeof (wl_key_t), "wl_key"},
330
331 { MAC_PROP_WL_MLME, sizeof (wl_mlme_t), "mlme"},
332
333 { MAC_PROP_TAGMODE, sizeof (link_tagmode_t), "tagmode"},
334
335 { MAC_PROP_IPTUN_HOPLIMIT, sizeof (uint32_t), "hoplimit"},
336
337 { MAC_PROP_IPTUN_ENCAPLIMIT, sizeof (uint32_t), "encaplimit"},
338
339 { MAC_PROP_PVID, sizeof (uint16_t), "default_tag"},
340
341 { MAC_PROP_LLIMIT, sizeof (uint32_t), "learn_limit"},
342
343 { MAC_PROP_LDECAY, sizeof (uint32_t), "learn_decay"},
344
345 { MAC_PROP_RESOURCE, sizeof (mac_resource_props_t), "resource"},
346
347 { MAC_PROP_RESOURCE_EFF, sizeof (mac_resource_props_t),
348 "resource-effective"},
349
350 { MAC_PROP_RXRINGSRANGE, sizeof (mac_propval_range_t), "rxrings"},
351
352 { MAC_PROP_TXRINGSRANGE, sizeof (mac_propval_range_t), "txrings"},
353
354 { MAC_PROP_MAX_TX_RINGS_AVAIL, sizeof (uint_t),
355 "txrings-available"},
356
357 { MAC_PROP_MAX_RX_RINGS_AVAIL, sizeof (uint_t),
358 "rxrings-available"},
359
360 { MAC_PROP_MAX_RXHWCLNT_AVAIL, sizeof (uint_t), "rxhwclnt-available"},
361
362 { MAC_PROP_MAX_TXHWCLNT_AVAIL, sizeof (uint_t), "txhwclnt-available"},
363
364 { MAC_PROP_IB_LINKMODE, sizeof (uint32_t), "linkmode"},
365
366 { MAC_PROP_PRIVATE, 0, "driver-private"}
367 };
368
369 typedef struct bridge_public_prop_s {
370 const char *bpp_name;
371 int bpp_code;
372 } bridge_public_prop_t;
373
374 static const bridge_public_prop_t bridge_prop[] = {
375 { "stp", PT_CFG_NON_STP },
376 { "stp_priority", PT_CFG_PRIO },
377 { "stp_cost", PT_CFG_COST },
378 { "stp_edge", PT_CFG_EDGE },
379 { "stp_p2p", PT_CFG_P2P },
380 { "stp_mcheck", PT_CFG_MCHECK },
381 { NULL, 0 }
382 };
383
384 static val_desc_t link_duplex_vals[] = {
385 { "half", LINK_DUPLEX_HALF },
386 { "full", LINK_DUPLEX_HALF }
387 };
388 static val_desc_t link_status_vals[] = {
389 { "up", LINK_STATE_UP },
390 { "down", LINK_STATE_DOWN }
391 };
392 static val_desc_t link_01_vals[] = {
393 { "1", 1 },
394 { "0", 0 }
395 };
396 static val_desc_t link_flow_vals[] = {
397 { "no", LINK_FLOWCTRL_NONE },
398 { "tx", LINK_FLOWCTRL_TX },
399 { "rx", LINK_FLOWCTRL_RX },
400 { "bi", LINK_FLOWCTRL_BI }
401 };
402 static val_desc_t link_priority_vals[] = {
403 { "low", MPL_LOW },
404 { "medium", MPL_MEDIUM },
405 { "high", MPL_HIGH }
406 };
407
408 static val_desc_t link_tagmode_vals[] = {
409 { "normal", LINK_TAGMODE_NORMAL },
410 { "vlanonly", LINK_TAGMODE_VLANONLY }
411 };
412
413 static val_desc_t link_protect_vals[] = {
414 { "mac-nospoof", MPT_MACNOSPOOF },
415 { "restricted", MPT_RESTRICTED },
416 { "ip-nospoof", MPT_IPNOSPOOF },
417 { "dhcp-nospoof", MPT_DHCPNOSPOOF },
418 };
419
420 static val_desc_t dladm_wlan_radio_vals[] = {
421 { "on", DLADM_WLAN_RADIO_ON },
422 { "off", DLADM_WLAN_RADIO_OFF }
423 };
424
425 static val_desc_t dladm_wlan_powermode_vals[] = {
426 { "off", DLADM_WLAN_PM_OFF },
427 { "fast", DLADM_WLAN_PM_FAST },
428 { "max", DLADM_WLAN_PM_MAX }
429 };
430
431 static val_desc_t stp_p2p_vals[] = {
432 { "true", P2P_FORCE_TRUE },
433 { "false", P2P_FORCE_FALSE },
434 { "auto", P2P_AUTO }
435 };
436
437 static val_desc_t dladm_part_linkmode_vals[] = {
438 { "cm", DLADM_PART_CM_MODE },
439 { "ud", DLADM_PART_UD_MODE },
440 };
441
442 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t))
443 #define RESET_VAL ((uintptr_t)-1)
444 #define UNSPEC_VAL ((uintptr_t)-2)
445
446 static prop_desc_t prop_table[] = {
447 { "channel", { NULL, 0 },
448 NULL, 0, NULL, NULL,
449 get_channel, NULL, 0,
450 DATALINK_CLASS_PHYS, DL_WIFI },
451
452 { "powermode", { "off", DLADM_WLAN_PM_OFF },
453 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
454 set_powermode, NULL,
455 get_powermode, NULL, 0,
456 DATALINK_CLASS_PHYS, DL_WIFI },
457
458 { "radio", { "on", DLADM_WLAN_RADIO_ON },
459 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
460 set_radio, NULL,
461 get_radio, NULL, 0,
462 DATALINK_CLASS_PHYS, DL_WIFI },
463
464 { "linkmode", { "cm", DLADM_PART_CM_MODE },
465 dladm_part_linkmode_vals, VALCNT(dladm_part_linkmode_vals),
466 set_public_prop, NULL, get_linkmode_prop, NULL, 0,
467 DATALINK_CLASS_PART, DL_IB },
468
469 { "speed", { "", 0 }, NULL, 0,
470 set_rate, get_rate_mod,
471 get_rate, check_rate, 0,
472 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
473
474 { "autopush", { "", 0 }, NULL, 0,
475 set_public_prop, NULL,
476 get_autopush, check_autopush, PD_CHECK_ALLOC,
477 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
478
479 { "zone", { "", 0 }, NULL, 0,
480 set_zone, NULL,
481 get_zone, check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
482 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
483
484 { "duplex", { "", 0 },
485 link_duplex_vals, VALCNT(link_duplex_vals),
486 NULL, NULL, get_duplex, NULL,
487 0, DATALINK_CLASS_PHYS, DL_ETHER },
488
489 { "state", { "up", LINK_STATE_UP },
490 link_status_vals, VALCNT(link_status_vals),
491 NULL, NULL, get_link_state, NULL,
492 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
493
494 { "adv_autoneg_cap", { "", 0 },
495 link_01_vals, VALCNT(link_01_vals),
496 set_public_prop, NULL, get_binary, NULL,
497 0, DATALINK_CLASS_PHYS, DL_ETHER },
498
499 { "mtu", { "", 0 }, NULL, 0,
500 set_public_prop, get_range,
501 get_uint32, check_uint32, 0, DATALINK_CLASS_ALL,
502 DATALINK_ANY_MEDIATYPE },
503
504 { "flowctrl", { "", 0 },
505 link_flow_vals, VALCNT(link_flow_vals),
506 set_public_prop, NULL, get_flowctl, NULL,
507 0, DATALINK_CLASS_PHYS, DL_ETHER },
508
509 { "adv_10gfdx_cap", { "", 0 },
510 link_01_vals, VALCNT(link_01_vals),
511 NULL, NULL, get_binary, NULL,
512 0, DATALINK_CLASS_PHYS, DL_ETHER },
513
514 { "en_10gfdx_cap", { "", 0 },
515 link_01_vals, VALCNT(link_01_vals),
516 set_public_prop, NULL, get_binary, NULL,
517 0, DATALINK_CLASS_PHYS, DL_ETHER },
518
519 { "adv_1000fdx_cap", { "", 0 },
520 link_01_vals, VALCNT(link_01_vals),
521 NULL, NULL, get_binary, NULL,
522 0, DATALINK_CLASS_PHYS, DL_ETHER },
523
524 { "en_1000fdx_cap", { "", 0 },
525 link_01_vals, VALCNT(link_01_vals),
526 set_public_prop, NULL, get_binary, NULL,
527 0, DATALINK_CLASS_PHYS, DL_ETHER },
528
529 { "adv_1000hdx_cap", { "", 0 },
530 link_01_vals, VALCNT(link_01_vals),
531 NULL, NULL, get_binary, NULL,
532 0, DATALINK_CLASS_PHYS, DL_ETHER },
533
534 { "en_1000hdx_cap", { "", 0 },
535 link_01_vals, VALCNT(link_01_vals),
536 set_public_prop, NULL, get_binary, NULL,
537 0, DATALINK_CLASS_PHYS, DL_ETHER },
538
539 { "adv_100fdx_cap", { "", 0 },
540 link_01_vals, VALCNT(link_01_vals),
541 NULL, NULL, get_binary, NULL,
542 0, DATALINK_CLASS_PHYS, DL_ETHER },
543
544 { "en_100fdx_cap", { "", 0 },
545 link_01_vals, VALCNT(link_01_vals),
546 set_public_prop, NULL, get_binary, NULL,
547 0, DATALINK_CLASS_PHYS, DL_ETHER },
548
549 { "adv_100hdx_cap", { "", 0 },
550 link_01_vals, VALCNT(link_01_vals),
551 NULL, NULL, get_binary, NULL,
552 0, DATALINK_CLASS_PHYS, DL_ETHER },
553
554 { "en_100hdx_cap", { "", 0 },
555 link_01_vals, VALCNT(link_01_vals),
556 set_public_prop, NULL, get_binary, NULL,
557 0, DATALINK_CLASS_PHYS, DL_ETHER },
558
559 { "adv_10fdx_cap", { "", 0 },
560 link_01_vals, VALCNT(link_01_vals),
561 NULL, NULL, get_binary, NULL,
562 0, DATALINK_CLASS_PHYS, DL_ETHER },
563
564 { "en_10fdx_cap", { "", 0 },
565 link_01_vals, VALCNT(link_01_vals),
566 set_public_prop, NULL, get_binary, NULL,
567 0, DATALINK_CLASS_PHYS, DL_ETHER },
568
569 { "adv_10hdx_cap", { "", 0 },
570 link_01_vals, VALCNT(link_01_vals),
571 NULL, NULL, get_binary, NULL,
572 0, DATALINK_CLASS_PHYS, DL_ETHER },
573
574 { "en_10hdx_cap", { "", 0 },
575 link_01_vals, VALCNT(link_01_vals),
576 set_public_prop, NULL, get_binary, NULL,
577 0, DATALINK_CLASS_PHYS, DL_ETHER },
578
579 { "maxbw", { "--", RESET_VAL }, NULL, 0,
580 set_resource, NULL,
581 get_maxbw, check_maxbw, PD_CHECK_ALLOC,
582 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
583
584 { "cpus", { "--", RESET_VAL }, NULL, 0,
585 set_resource, NULL,
586 get_cpus, check_cpus, 0,
587 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
588
589 { "cpus-effective", { "--", 0 },
590 NULL, 0, NULL, NULL,
591 get_cpus, 0, 0,
592 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
593
594 { "pool", { "--", RESET_VAL }, NULL, 0,
595 set_resource, NULL,
596 get_pool, check_pool, 0,
597 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
598
599 { "pool-effective", { "--", 0 },
600 NULL, 0, NULL, NULL,
601 get_pool, 0, 0,
602 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
603
604 { "priority", { "high", MPL_RESET },
605 link_priority_vals, VALCNT(link_priority_vals), set_resource,
606 NULL, get_priority, check_prop, 0,
607 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
608
609 { "tagmode", { "vlanonly", LINK_TAGMODE_VLANONLY },
610 link_tagmode_vals, VALCNT(link_tagmode_vals),
611 set_public_prop, NULL, get_tagmode,
612 NULL, 0,
613 DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC,
614 DL_ETHER },
615
616 { "hoplimit", { "", 0 }, NULL, 0,
617 set_public_prop, get_range, get_uint32,
618 check_hoplimit, 0, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE},
619
620 { "encaplimit", { "", 0 }, NULL, 0,
621 set_public_prop, get_range, get_uint32,
622 check_encaplim, 0, DATALINK_CLASS_IPTUN, DL_IPV6},
623
624 { "forward", { "1", 1 },
625 link_01_vals, VALCNT(link_01_vals),
626 set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM,
627 DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER },
628
629 { "default_tag", { "1", 1 }, NULL, 0,
630 set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid,
631 0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
632 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
633
634 { "learn_limit", { "1000", 1000 }, NULL, 0,
635 set_public_prop, NULL, get_uint32,
636 check_uint32, 0,
637 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
638 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
639
640 { "learn_decay", { "200", 200 }, NULL, 0,
641 set_public_prop, NULL, get_uint32,
642 check_uint32, 0,
643 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
644 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
645
646 { "stp", { "1", 1 },
647 link_01_vals, VALCNT(link_01_vals),
648 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
649 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
650 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
651
652 { "stp_priority", { "128", 128 }, NULL, 0,
653 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
654 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
655 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
656
657 { "stp_cost", { "auto", 0 }, NULL, 0,
658 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
659 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
660 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
661
662 { "stp_edge", { "1", 1 },
663 link_01_vals, VALCNT(link_01_vals),
664 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
665 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
666 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
667
668 { "stp_p2p", { "auto", P2P_AUTO },
669 stp_p2p_vals, VALCNT(stp_p2p_vals),
670 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
671 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
672 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
673
674 { "stp_mcheck", { "0", 0 },
675 link_01_vals, VALCNT(link_01_vals),
676 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
677 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
678 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
679
680 { "protection", { "--", RESET_VAL },
681 link_protect_vals, VALCNT(link_protect_vals),
682 set_resource, NULL, get_protection, check_prop, 0,
683 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
684
685 { "allowed-ips", { "--", 0 },
686 NULL, 0, set_resource, NULL,
687 get_allowedips, check_allowedips, PD_CHECK_ALLOC,
688 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
689
690 { "allowed-dhcp-cids", { "--", 0 },
691 NULL, 0, set_resource, NULL,
692 get_allowedcids, check_allowedcids, PD_CHECK_ALLOC,
693 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
694
695 { "rxrings", { "--", RESET_VAL }, NULL, 0,
696 set_resource, get_rings_range, get_rxrings, check_rings, 0,
697 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
698
699 { "rxrings-effective", { "--", 0 },
700 NULL, 0, NULL, NULL,
701 get_rxrings, NULL, 0,
702 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
703
704 { "txrings", { "--", RESET_VAL }, NULL, 0,
705 set_resource, get_rings_range, get_txrings, check_rings, 0,
706 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
707
708 { "txrings-effective", { "--", 0 },
709 NULL, 0, NULL, NULL,
710 get_txrings, NULL, 0,
711 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
712
713 { "txrings-available", { "", 0 }, NULL, 0,
714 NULL, NULL, get_cntavail, NULL, 0,
715 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
716
717 { "rxrings-available", { "", 0 }, NULL, 0,
718 NULL, NULL, get_cntavail, NULL, 0,
719 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
720
721 { "rxhwclnt-available", { "", 0 }, NULL, 0,
722 NULL, NULL, get_cntavail, NULL, 0,
723 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
724
725 { "txhwclnt-available", { "", 0 }, NULL, 0,
726 NULL, NULL, get_cntavail, NULL, 0,
727 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
728
729 };
730
731 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t))
732
733 static resource_prop_t rsrc_prop_table[] = {
734 {"maxbw", extract_maxbw},
735 {"priority", extract_priority},
736 {"cpus", extract_cpus},
737 {"cpus-effective", extract_cpus},
738 {"pool", extract_pool},
739 {"pool-effective", extract_pool},
740 {"protection", extract_protection},
741 {"allowed-ips", extract_allowedips},
742 {"allowed-dhcp-cids", extract_allowedcids},
743 {"rxrings", extract_rxrings},
744 {"rxrings-effective", extract_rxrings},
745 {"txrings", extract_txrings},
746 {"txrings-effective", extract_txrings}
747 };
748 #define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
749 sizeof (resource_prop_t))
750
751 /*
752 * when retrieving private properties, we pass down a buffer with
753 * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
754 */
755 #define DLADM_PROP_BUF_CHUNK 1024
756
757 static dladm_status_t i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t,
758 const char *, char **, uint_t);
759 static dladm_status_t i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t,
760 const char *, char **, uint_t *);
761 static dladm_status_t i_dladm_walk_linkprop_priv_db(dladm_handle_t,
762 datalink_id_t, void *, int (*)(dladm_handle_t,
763 datalink_id_t, const char *, void *));
764 static dladm_status_t i_dladm_set_single_prop(dladm_handle_t, datalink_id_t,
765 datalink_class_t, uint32_t, prop_desc_t *, char **,
766 uint_t, uint_t);
767 static dladm_status_t i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
768 const char *, char **, uint_t, uint_t);
769 static dladm_status_t i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
770 datalink_id_t, datalink_media_t, uint_t);
771
772 /*
773 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
774 * rates to be retrieved. However, we cannot increase it at this
775 * time because it will break binary compatibility with unbundled
776 * WiFi drivers and utilities. So for now we define an additional
777 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
778 */
779 #define MAX_SUPPORT_RATES 64
780
781 #define AP_ANCHOR "[anchor]"
782 #define AP_DELIMITER '.'
783
784 /* ARGSUSED */
785 static dladm_status_t
check_prop(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)786 check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
787 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
788 datalink_media_t media)
789 {
790 int i, j;
791 uint_t val_cnt = *val_cntp;
792 val_desc_t *vdp = *vdpp;
793
794 for (j = 0; j < val_cnt; j++) {
795 for (i = 0; i < pdp->pd_noptval; i++) {
796 if (strcasecmp(prop_val[j],
797 pdp->pd_optval[i].vd_name) == 0) {
798 break;
799 }
800 }
801 if (i == pdp->pd_noptval)
802 return (DLADM_STATUS_BADVAL);
803
804 (void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t));
805 }
806 return (DLADM_STATUS_OK);
807 }
808
809 static dladm_status_t
i_dladm_set_single_prop(dladm_handle_t handle,datalink_id_t linkid,datalink_class_t class,uint32_t media,prop_desc_t * pdp,char ** prop_val,uint_t val_cnt,uint_t flags)810 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid,
811 datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val,
812 uint_t val_cnt, uint_t flags)
813 {
814 dladm_status_t status = DLADM_STATUS_OK;
815 val_desc_t *vdp = NULL;
816 boolean_t needfree = B_FALSE;
817 uint_t cnt, i;
818
819 if (!(pdp->pd_class & class))
820 return (DLADM_STATUS_BADARG);
821
822 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
823 return (DLADM_STATUS_BADARG);
824
825 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
826 return (DLADM_STATUS_TEMPONLY);
827
828 if (!(flags & DLADM_OPT_ACTIVE))
829 return (DLADM_STATUS_OK);
830
831 if (pdp->pd_set == NULL)
832 return (DLADM_STATUS_PROPRDONLY);
833
834 if (prop_val != NULL) {
835 vdp = calloc(val_cnt, sizeof (val_desc_t));
836 if (vdp == NULL)
837 return (DLADM_STATUS_NOMEM);
838
839 if (pdp->pd_check != NULL) {
840 needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
841 status = pdp->pd_check(handle, pdp, linkid, prop_val,
842 &val_cnt, flags, &vdp, media);
843 } else if (pdp->pd_optval != NULL) {
844 status = check_prop(handle, pdp, linkid, prop_val,
845 &val_cnt, flags, &vdp, media);
846 } else {
847 status = DLADM_STATUS_BADARG;
848 }
849
850 if (status != DLADM_STATUS_OK)
851 goto done;
852
853 cnt = val_cnt;
854 } else {
855 boolean_t defval = B_FALSE;
856
857 if (pdp->pd_defval.vd_name == NULL)
858 return (DLADM_STATUS_NOTSUP);
859
860 cnt = 1;
861 defval = (strlen(pdp->pd_defval.vd_name) > 0);
862 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) {
863 if ((vdp = calloc(1, sizeof (val_desc_t))) == NULL)
864 return (DLADM_STATUS_NOMEM);
865
866 if (defval) {
867 (void) memcpy(vdp, &pdp->pd_defval,
868 sizeof (val_desc_t));
869 } else if (pdp->pd_check != NULL) {
870 status = pdp->pd_check(handle, pdp, linkid,
871 prop_val, &cnt, flags, &vdp, media);
872 if (status != DLADM_STATUS_OK)
873 goto done;
874 }
875 } else {
876 status = i_dladm_getset_defval(handle, pdp, linkid,
877 media, flags);
878 return (status);
879 }
880 }
881 if (pdp->pd_flags & PD_AFTER_PERM)
882 status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK :
883 DLADM_STATUS_PERMONLY;
884 else
885 status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags,
886 media);
887 if (needfree) {
888 for (i = 0; i < cnt; i++)
889 free((void *)((val_desc_t *)vdp + i)->vd_val);
890 }
891 done:
892 free(vdp);
893 return (status);
894 }
895
896 static dladm_status_t
i_dladm_set_linkprop(dladm_handle_t handle,datalink_id_t linkid,const char * prop_name,char ** prop_val,uint_t val_cnt,uint_t flags)897 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
898 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
899 {
900 int i;
901 boolean_t found = B_FALSE;
902 datalink_class_t class;
903 uint32_t media;
904 dladm_status_t status = DLADM_STATUS_OK;
905
906 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
907 NULL, 0);
908 if (status != DLADM_STATUS_OK)
909 return (status);
910
911 for (i = 0; i < DLADM_MAX_PROPS; i++) {
912 prop_desc_t *pdp = &prop_table[i];
913 dladm_status_t s;
914
915 if (prop_name != NULL &&
916 (strcasecmp(prop_name, pdp->pd_name) != 0))
917 continue;
918 found = B_TRUE;
919 s = i_dladm_set_single_prop(handle, linkid, class, media, pdp,
920 prop_val, val_cnt, flags);
921
922 if (prop_name != NULL) {
923 status = s;
924 break;
925 } else {
926 if (s != DLADM_STATUS_OK &&
927 s != DLADM_STATUS_NOTSUP)
928 status = s;
929 }
930 }
931 if (!found) {
932 if (prop_name[0] == '_') {
933 /* other private properties */
934 status = i_dladm_set_private_prop(handle, linkid,
935 prop_name, prop_val, val_cnt, flags);
936 } else {
937 status = DLADM_STATUS_NOTFOUND;
938 }
939 }
940 return (status);
941 }
942
943 /*
944 * Set/reset link property for specific link
945 */
946 dladm_status_t
dladm_set_linkprop(dladm_handle_t handle,datalink_id_t linkid,const char * prop_name,char ** prop_val,uint_t val_cnt,uint_t flags)947 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
948 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
949 {
950 dladm_status_t status = DLADM_STATUS_OK;
951
952 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
953 (prop_val == NULL && val_cnt > 0) ||
954 (prop_val != NULL && val_cnt == 0) ||
955 (prop_name == NULL && prop_val != NULL)) {
956 return (DLADM_STATUS_BADARG);
957 }
958
959 /*
960 * Check for valid link property against the flags passed
961 * and set the link property when active flag is passed.
962 */
963 status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
964 val_cnt, flags);
965 if (status != DLADM_STATUS_OK)
966 return (status);
967
968 if (flags & DLADM_OPT_PERSIST) {
969 status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
970 prop_val, val_cnt);
971
972 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
973 prop_desc_t *pdp = prop_table;
974 int i;
975
976 for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) {
977 if (!(pdp->pd_flags & PD_AFTER_PERM))
978 continue;
979 if (prop_name != NULL &&
980 strcasecmp(prop_name, pdp->pd_name) != 0)
981 continue;
982 status = pdp->pd_set(handle, pdp, linkid, NULL,
983 0, flags, 0);
984 }
985 }
986 }
987 return (status);
988 }
989
990 /*
991 * Walk all link properties of the given specific link.
992 *
993 * Note: this function currently lacks the ability to walk _all_ private
994 * properties if the link, because there is no kernel interface to
995 * retrieve all known private property names. Once such an interface
996 * is added, this function should be fixed accordingly.
997 */
998 dladm_status_t
dladm_walk_linkprop(dladm_handle_t handle,datalink_id_t linkid,void * arg,int (* func)(dladm_handle_t,datalink_id_t,const char *,void *))999 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg,
1000 int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
1001 {
1002 dladm_status_t status;
1003 datalink_class_t class;
1004 uint_t media;
1005 int i;
1006
1007 if (linkid == DATALINK_INVALID_LINKID || func == NULL)
1008 return (DLADM_STATUS_BADARG);
1009
1010 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1011 NULL, 0);
1012 if (status != DLADM_STATUS_OK)
1013 return (status);
1014
1015 /* public */
1016 for (i = 0; i < DLADM_MAX_PROPS; i++) {
1017 if (!(prop_table[i].pd_class & class))
1018 continue;
1019
1020 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
1021 continue;
1022
1023 if (func(handle, linkid, prop_table[i].pd_name, arg) ==
1024 DLADM_WALK_TERMINATE) {
1025 break;
1026 }
1027 }
1028
1029 /* private */
1030 status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func);
1031
1032 return (status);
1033 }
1034
1035 /*
1036 * Get linkprop of the given specific link.
1037 */
1038 dladm_status_t
dladm_get_linkprop(dladm_handle_t handle,datalink_id_t linkid,dladm_prop_type_t type,const char * prop_name,char ** prop_val,uint_t * val_cntp)1039 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1040 dladm_prop_type_t type, const char *prop_name, char **prop_val,
1041 uint_t *val_cntp)
1042 {
1043 dladm_status_t status = DLADM_STATUS_OK;
1044 datalink_class_t class;
1045 uint_t media;
1046 prop_desc_t *pdp;
1047 uint_t cnt, dld_flags = 0;
1048 int i;
1049 uint_t perm_flags;
1050
1051 if (type == DLADM_PROP_VAL_DEFAULT)
1052 dld_flags |= DLD_PROP_DEFAULT;
1053 else if (type == DLADM_PROP_VAL_MODIFIABLE)
1054 dld_flags |= DLD_PROP_POSSIBLE;
1055
1056 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1057 prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
1058 return (DLADM_STATUS_BADARG);
1059
1060 for (i = 0; i < DLADM_MAX_PROPS; i++)
1061 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
1062 break;
1063
1064 if (i == DLADM_MAX_PROPS) {
1065 if (prop_name[0] == '_') {
1066 /*
1067 * private property.
1068 */
1069 if (type == DLADM_PROP_VAL_PERSISTENT)
1070 return (i_dladm_get_linkprop_db(handle, linkid,
1071 prop_name, prop_val, val_cntp));
1072 else
1073 return (i_dladm_get_priv_prop(handle, linkid,
1074 prop_name, prop_val, val_cntp, type,
1075 dld_flags));
1076 } else {
1077 return (DLADM_STATUS_NOTFOUND);
1078 }
1079 }
1080
1081 pdp = &prop_table[i];
1082
1083 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1084 NULL, 0);
1085 if (status != DLADM_STATUS_OK)
1086 return (status);
1087
1088 if (!(pdp->pd_class & class))
1089 return (DLADM_STATUS_BADARG);
1090
1091 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1092 return (DLADM_STATUS_BADARG);
1093
1094 switch (type) {
1095 case DLADM_PROP_VAL_CURRENT:
1096 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1097 media, dld_flags, &perm_flags);
1098 break;
1099
1100 case DLADM_PROP_VAL_PERM:
1101 if (pdp->pd_set == NULL) {
1102 perm_flags = MAC_PROP_PERM_READ;
1103 } else {
1104 status = pdp->pd_get(handle, pdp, linkid, prop_val,
1105 val_cntp, media, dld_flags, &perm_flags);
1106 }
1107
1108 *prop_val[0] = '\0';
1109 *val_cntp = 1;
1110 if (status == DLADM_STATUS_OK)
1111 (void) dladm_perm2str(perm_flags, *prop_val);
1112 break;
1113
1114 case DLADM_PROP_VAL_DEFAULT:
1115 /*
1116 * If defaults are not defined for the property,
1117 * pd_defval.vd_name should be null. If the driver
1118 * has to be contacted for the value, vd_name should
1119 * be the empty string (""). Otherwise, dladm will
1120 * just print whatever is in the table.
1121 */
1122 if (pdp->pd_defval.vd_name == NULL) {
1123 status = DLADM_STATUS_NOTSUP;
1124 break;
1125 }
1126
1127 if (strlen(pdp->pd_defval.vd_name) == 0) {
1128 status = pdp->pd_get(handle, pdp, linkid, prop_val,
1129 val_cntp, media, dld_flags, &perm_flags);
1130 } else {
1131 (void) strcpy(*prop_val, pdp->pd_defval.vd_name);
1132 }
1133 *val_cntp = 1;
1134 break;
1135
1136 case DLADM_PROP_VAL_MODIFIABLE:
1137 if (pdp->pd_getmod != NULL) {
1138 status = pdp->pd_getmod(handle, pdp, linkid, prop_val,
1139 val_cntp, media, dld_flags, &perm_flags);
1140 break;
1141 }
1142 cnt = pdp->pd_noptval;
1143 if (cnt == 0) {
1144 status = DLADM_STATUS_NOTSUP;
1145 } else if (cnt > *val_cntp) {
1146 status = DLADM_STATUS_TOOSMALL;
1147 } else {
1148 for (i = 0; i < cnt; i++) {
1149 (void) strcpy(prop_val[i],
1150 pdp->pd_optval[i].vd_name);
1151 }
1152 *val_cntp = cnt;
1153 }
1154 break;
1155 case DLADM_PROP_VAL_PERSISTENT:
1156 if (pdp->pd_flags & PD_TEMPONLY)
1157 return (DLADM_STATUS_TEMPONLY);
1158 status = i_dladm_get_linkprop_db(handle, linkid, prop_name,
1159 prop_val, val_cntp);
1160 break;
1161 default:
1162 status = DLADM_STATUS_BADARG;
1163 break;
1164 }
1165
1166 return (status);
1167 }
1168
1169 /*
1170 * Get linkprop of the given specific link and run any possible conversion
1171 * of the values using the check function for the property. Fails if the
1172 * check function doesn't succeed for the property value.
1173 */
1174 dladm_status_t
dladm_get_linkprop_values(dladm_handle_t handle,datalink_id_t linkid,dladm_prop_type_t type,const char * prop_name,uint_t * ret_val,uint_t * val_cntp)1175 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid,
1176 dladm_prop_type_t type, const char *prop_name, uint_t *ret_val,
1177 uint_t *val_cntp)
1178 {
1179 dladm_status_t status;
1180 datalink_class_t class;
1181 uint_t media;
1182 prop_desc_t *pdp;
1183 uint_t dld_flags;
1184 int valc, i;
1185 char **prop_val;
1186 uint_t perm_flags;
1187
1188 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1189 ret_val == NULL || val_cntp == NULL || *val_cntp == 0)
1190 return (DLADM_STATUS_BADARG);
1191
1192 for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++)
1193 if (strcasecmp(prop_name, pdp->pd_name) == 0)
1194 break;
1195
1196 if (pdp == prop_table + DLADM_MAX_PROPS)
1197 return (DLADM_STATUS_NOTFOUND);
1198
1199 if (pdp->pd_flags & PD_CHECK_ALLOC)
1200 return (DLADM_STATUS_BADARG);
1201
1202 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1203 NULL, 0);
1204 if (status != DLADM_STATUS_OK)
1205 return (status);
1206
1207 if (!(pdp->pd_class & class))
1208 return (DLADM_STATUS_BADARG);
1209
1210 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1211 return (DLADM_STATUS_BADARG);
1212
1213 prop_val = malloc(*val_cntp * sizeof (*prop_val) +
1214 *val_cntp * DLADM_PROP_VAL_MAX);
1215 if (prop_val == NULL)
1216 return (DLADM_STATUS_NOMEM);
1217 for (valc = 0; valc < *val_cntp; valc++)
1218 prop_val[valc] = (char *)(prop_val + *val_cntp) +
1219 valc * DLADM_PROP_VAL_MAX;
1220
1221 dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? DLD_PROP_DEFAULT : 0;
1222
1223 switch (type) {
1224 case DLADM_PROP_VAL_CURRENT:
1225 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1226 media, dld_flags, &perm_flags);
1227 break;
1228
1229 case DLADM_PROP_VAL_DEFAULT:
1230 /*
1231 * If defaults are not defined for the property,
1232 * pd_defval.vd_name should be null. If the driver
1233 * has to be contacted for the value, vd_name should
1234 * be the empty string (""). Otherwise, dladm will
1235 * just print whatever is in the table.
1236 */
1237 if (pdp->pd_defval.vd_name == NULL) {
1238 status = DLADM_STATUS_NOTSUP;
1239 break;
1240 }
1241
1242 if (pdp->pd_defval.vd_name[0] != '\0') {
1243 *val_cntp = 1;
1244 *ret_val = pdp->pd_defval.vd_val;
1245 free(prop_val);
1246 return (DLADM_STATUS_OK);
1247 }
1248 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1249 media, dld_flags, &perm_flags);
1250 break;
1251
1252 case DLADM_PROP_VAL_PERSISTENT:
1253 if (pdp->pd_flags & PD_TEMPONLY)
1254 status = DLADM_STATUS_TEMPONLY;
1255 else
1256 status = i_dladm_get_linkprop_db(handle, linkid,
1257 prop_name, prop_val, val_cntp);
1258 break;
1259
1260 default:
1261 status = DLADM_STATUS_BADARG;
1262 break;
1263 }
1264
1265 if (status == DLADM_STATUS_OK) {
1266 if (pdp->pd_check != NULL) {
1267 val_desc_t *vdp;
1268
1269 vdp = malloc(sizeof (val_desc_t) * *val_cntp);
1270 if (vdp == NULL)
1271 status = DLADM_STATUS_NOMEM;
1272 else
1273 status = pdp->pd_check(handle, pdp, linkid,
1274 prop_val, val_cntp, 0, &vdp, media);
1275 if (status == DLADM_STATUS_OK) {
1276 for (valc = 0; valc < *val_cntp; valc++)
1277 ret_val[valc] = vdp[valc].vd_val;
1278 }
1279 free(vdp);
1280 } else {
1281 for (valc = 0; valc < *val_cntp; valc++) {
1282 for (i = 0; i < pdp->pd_noptval; i++) {
1283 if (strcmp(pdp->pd_optval[i].vd_name,
1284 prop_val[valc]) == 0) {
1285 ret_val[valc] =
1286 pdp->pd_optval[i].vd_val;
1287 break;
1288 }
1289 }
1290 if (i == pdp->pd_noptval) {
1291 status = DLADM_STATUS_FAILED;
1292 break;
1293 }
1294 }
1295 }
1296 }
1297
1298 free(prop_val);
1299
1300 return (status);
1301 }
1302
1303 /*ARGSUSED*/
1304 static int
i_dladm_init_one_prop(dladm_handle_t handle,datalink_id_t linkid,const char * prop_name,void * arg)1305 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid,
1306 const char *prop_name, void *arg)
1307 {
1308 char *buf, **propvals;
1309 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT;
1310 dladm_status_t status;
1311 dladm_linkprop_args_t *dla = arg;
1312
1313 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
1314 DLADM_MAX_PROP_VALCNT)) == NULL) {
1315 return (DLADM_WALK_CONTINUE);
1316 }
1317
1318 propvals = (char **)(void *)buf;
1319 for (i = 0; i < valcnt; i++) {
1320 propvals[i] = buf +
1321 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1322 i * DLADM_PROP_VAL_MAX;
1323 }
1324
1325 if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
1326 prop_name, propvals, &valcnt) != DLADM_STATUS_OK) {
1327 goto done;
1328 }
1329
1330 status = dladm_set_linkprop(handle, linkid, prop_name, propvals,
1331 valcnt, dla->dla_flags | DLADM_OPT_ACTIVE);
1332
1333 if (status != DLADM_STATUS_OK)
1334 dla->dla_status = status;
1335
1336 done:
1337 if (buf != NULL)
1338 free(buf);
1339
1340 return (DLADM_WALK_CONTINUE);
1341 }
1342
1343 /*ARGSUSED*/
1344 static int
i_dladm_init_linkprop(dladm_handle_t handle,datalink_id_t linkid,void * arg)1345 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1346 {
1347 datalink_class_t class;
1348 dladm_status_t status;
1349
1350 status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
1351 NULL, 0);
1352 if (status != DLADM_STATUS_OK)
1353 return (DLADM_WALK_TERMINATE);
1354
1355 if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
1356 (void) dladm_init_linkprop(handle, linkid, B_TRUE);
1357
1358 return (DLADM_WALK_CONTINUE);
1359 }
1360
1361 dladm_status_t
dladm_init_linkprop(dladm_handle_t handle,datalink_id_t linkid,boolean_t any_media)1362 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1363 boolean_t any_media)
1364 {
1365 dladm_status_t status = DLADM_STATUS_OK;
1366 datalink_media_t dmedia;
1367 uint32_t media;
1368 dladm_linkprop_args_t *dla;
1369
1370 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
1371
1372 dla = malloc(sizeof (dladm_linkprop_args_t));
1373 if (dla == NULL)
1374 return (DLADM_STATUS_NOMEM);
1375 dla->dla_flags = DLADM_OPT_BOOT;
1376 dla->dla_status = DLADM_STATUS_OK;
1377
1378 if (linkid == DATALINK_ALL_LINKID) {
1379 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
1380 NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
1381 } else if (any_media ||
1382 ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL,
1383 0) == DLADM_STATUS_OK) &&
1384 DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
1385 (void) dladm_walk_linkprop(handle, linkid, (void *)dla,
1386 i_dladm_init_one_prop);
1387 status = dla->dla_status;
1388 }
1389 free(dla);
1390 return (status);
1391 }
1392
1393 /* ARGSUSED */
1394 static dladm_status_t
get_zone(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)1395 get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1396 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1397 uint_t flags, uint_t *perm_flags)
1398 {
1399 char zone_name[ZONENAME_MAX];
1400 zoneid_t zid;
1401 dladm_status_t status;
1402
1403 if (flags != 0)
1404 return (DLADM_STATUS_NOTSUP);
1405
1406 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1407 perm_flags, &zid, sizeof (zid));
1408 if (status != DLADM_STATUS_OK)
1409 return (status);
1410
1411 *val_cnt = 1;
1412 if (zid != GLOBAL_ZONEID) {
1413 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
1414 return (dladm_errno2status(errno));
1415 }
1416
1417 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
1418 } else {
1419 *prop_val[0] = '\0';
1420 }
1421
1422 return (DLADM_STATUS_OK);
1423 }
1424
1425 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
1426
1427 static int
i_dladm_get_zone_dev(char * zone_name,char * dev,size_t devlen)1428 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
1429 {
1430 char root[MAXPATHLEN];
1431 zone_get_devroot_t real_zone_get_devroot;
1432 void *dlhandle;
1433 void *sym;
1434 int ret;
1435
1436 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
1437 return (-1);
1438
1439 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
1440 (void) dlclose(dlhandle);
1441 return (-1);
1442 }
1443
1444 real_zone_get_devroot = (zone_get_devroot_t)sym;
1445
1446 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
1447 (void) snprintf(dev, devlen, "%s%s", root, "/dev");
1448 (void) dlclose(dlhandle);
1449 return (ret);
1450 }
1451
1452 static dladm_status_t
i_dladm_update_deventry(dladm_handle_t handle,zoneid_t zid,datalink_id_t linkid,boolean_t add)1453 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
1454 datalink_id_t linkid, boolean_t add)
1455 {
1456 char path[MAXPATHLEN];
1457 char name[MAXLINKNAMELEN];
1458 di_prof_t prof = NULL;
1459 char zone_name[ZONENAME_MAX];
1460 dladm_status_t status;
1461 int ret;
1462
1463 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
1464 return (dladm_errno2status(errno));
1465 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
1466 return (dladm_errno2status(errno));
1467 if (di_prof_init(path, &prof) != 0)
1468 return (dladm_errno2status(errno));
1469
1470 status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
1471 if (status != DLADM_STATUS_OK)
1472 goto cleanup;
1473
1474 if (add)
1475 ret = di_prof_add_dev(prof, name);
1476 else
1477 ret = di_prof_add_exclude(prof, name);
1478
1479 if (ret != 0) {
1480 status = dladm_errno2status(errno);
1481 goto cleanup;
1482 }
1483
1484 if (di_prof_commit(prof) != 0)
1485 status = dladm_errno2status(errno);
1486 cleanup:
1487 if (prof)
1488 di_prof_fini(prof);
1489
1490 return (status);
1491 }
1492
1493 /* ARGSUSED */
1494 static dladm_status_t
set_zone(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)1495 set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1496 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1497 {
1498 dladm_status_t status = DLADM_STATUS_OK;
1499 zoneid_t zid_old, zid_new;
1500 dld_ioc_zid_t *dzp;
1501
1502 if (val_cnt != 1)
1503 return (DLADM_STATUS_BADVALCNT);
1504
1505 dzp = (dld_ioc_zid_t *)vdp->vd_val;
1506
1507 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1508 NULL, &zid_old, sizeof (zid_old));
1509 if (status != DLADM_STATUS_OK)
1510 return (status);
1511
1512 zid_new = dzp->diz_zid;
1513 if (zid_new == zid_old)
1514 return (DLADM_STATUS_OK);
1515
1516 if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt,
1517 flags, media)) != DLADM_STATUS_OK)
1518 return (status);
1519
1520 /*
1521 * It is okay to fail to update the /dev entry (some vanity-named
1522 * links do not have a /dev entry).
1523 */
1524 if (zid_old != GLOBAL_ZONEID) {
1525 (void) i_dladm_update_deventry(handle, zid_old, linkid,
1526 B_FALSE);
1527 }
1528 if (zid_new != GLOBAL_ZONEID)
1529 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1530
1531 return (DLADM_STATUS_OK);
1532 }
1533
1534 /* ARGSUSED */
1535 static dladm_status_t
check_zone(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)1536 check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1537 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1538 datalink_media_t media)
1539 {
1540 char *zone_name;
1541 zoneid_t zoneid;
1542 dladm_status_t status = DLADM_STATUS_OK;
1543 dld_ioc_zid_t *dzp;
1544 uint_t val_cnt = *val_cntp;
1545 val_desc_t *vdp = *vdpp;
1546
1547 if (val_cnt != 1)
1548 return (DLADM_STATUS_BADVALCNT);
1549
1550 dzp = malloc(sizeof (dld_ioc_zid_t));
1551 if (dzp == NULL)
1552 return (DLADM_STATUS_NOMEM);
1553
1554 zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1555 if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1556 status = DLADM_STATUS_BADVAL;
1557 goto done;
1558 }
1559
1560 if (zoneid != GLOBAL_ZONEID) {
1561 ushort_t flags;
1562
1563 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1564 sizeof (flags)) < 0) {
1565 status = dladm_errno2status(errno);
1566 goto done;
1567 }
1568
1569 if (!(flags & ZF_NET_EXCL)) {
1570 status = DLADM_STATUS_BADVAL;
1571 goto done;
1572 }
1573 }
1574
1575 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1576
1577 dzp->diz_zid = zoneid;
1578 dzp->diz_linkid = linkid;
1579
1580 vdp->vd_val = (uintptr_t)dzp;
1581 return (DLADM_STATUS_OK);
1582 done:
1583 free(dzp);
1584 return (status);
1585 }
1586
1587 /* ARGSUSED */
1588 static dladm_status_t
get_maxbw(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)1589 get_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1590 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1591 uint_t flags, uint_t *perm_flags)
1592 {
1593 mac_resource_props_t mrp;
1594 dladm_status_t status;
1595
1596 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1597 perm_flags, &mrp, sizeof (mrp));
1598 if (status != DLADM_STATUS_OK)
1599 return (status);
1600
1601 if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1602 *val_cnt = 0;
1603 return (DLADM_STATUS_OK);
1604 }
1605
1606 (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1607 *val_cnt = 1;
1608 return (DLADM_STATUS_OK);
1609 }
1610
1611 /* ARGSUSED */
1612 static dladm_status_t
check_maxbw(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)1613 check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1614 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1615 datalink_media_t media)
1616 {
1617 uint64_t *maxbw;
1618 dladm_status_t status = DLADM_STATUS_OK;
1619 uint_t val_cnt = *val_cntp;
1620 val_desc_t *vdp = *vdpp;
1621
1622 if (val_cnt != 1)
1623 return (DLADM_STATUS_BADVALCNT);
1624
1625 maxbw = malloc(sizeof (uint64_t));
1626 if (maxbw == NULL)
1627 return (DLADM_STATUS_NOMEM);
1628
1629 status = dladm_str2bw(*prop_val, maxbw);
1630 if (status != DLADM_STATUS_OK) {
1631 free(maxbw);
1632 return (status);
1633 }
1634
1635 if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1636 free(maxbw);
1637 return (DLADM_STATUS_MINMAXBW);
1638 }
1639
1640 vdp->vd_val = (uintptr_t)maxbw;
1641 return (DLADM_STATUS_OK);
1642 }
1643
1644 /* ARGSUSED */
1645 dladm_status_t
extract_maxbw(val_desc_t * vdp,uint_t cnt,void * arg)1646 extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
1647 {
1648 mac_resource_props_t *mrp = arg;
1649
1650 if (vdp->vd_val == RESET_VAL) {
1651 mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
1652 } else {
1653 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1654 }
1655 mrp->mrp_mask |= MRP_MAXBW;
1656
1657 return (DLADM_STATUS_OK);
1658 }
1659
1660 /* ARGSUSED */
1661 static dladm_status_t
get_cpus(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)1662 get_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1663 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1664 uint_t flags, uint_t *perm_flags)
1665 {
1666 dladm_status_t status;
1667 mac_resource_props_t mrp;
1668 mac_propval_range_t *pv_range;
1669 int err;
1670
1671 if (strcmp(pdp->pd_name, "cpus-effective") == 0) {
1672 status = i_dladm_get_public_prop(handle, linkid,
1673 "resource-effective", flags, perm_flags, &mrp,
1674 sizeof (mrp));
1675 } else {
1676 status = i_dladm_get_public_prop(handle, linkid,
1677 "resource", flags, perm_flags, &mrp, sizeof (mrp));
1678 }
1679
1680 if (status != DLADM_STATUS_OK)
1681 return (status);
1682
1683 if (mrp.mrp_ncpus > *val_cnt)
1684 return (DLADM_STATUS_TOOSMALL);
1685
1686 if (mrp.mrp_ncpus == 0) {
1687 *val_cnt = 0;
1688 return (DLADM_STATUS_OK);
1689 }
1690
1691 /* Sort CPU list and convert it to a mac_propval_range */
1692 status = dladm_list2range(mrp.mrp_cpu, mrp.mrp_ncpus,
1693 MAC_PROPVAL_UINT32, &pv_range);
1694 if (status != DLADM_STATUS_OK)
1695 return (status);
1696
1697 /* Write CPU ranges and individual CPUs */
1698 err = dladm_range2strs(pv_range, prop_val);
1699 if (err != 0) {
1700 free(pv_range);
1701 return (dladm_errno2status(err));
1702 }
1703
1704 *val_cnt = pv_range->mpr_count;
1705 free(pv_range);
1706
1707 return (DLADM_STATUS_OK);
1708 }
1709
1710 /* ARGSUSED */
1711 static dladm_status_t
check_cpus(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)1712 check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1713 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1714 datalink_media_t media)
1715 {
1716 int i, j, rc;
1717 long nproc = sysconf(_SC_NPROCESSORS_CONF);
1718 mac_resource_props_t mrp;
1719 mac_propval_range_t *pv_range;
1720 uint_t perm_flags;
1721 uint32_t ncpus;
1722 uint32_t *cpus = mrp.mrp_cpu;
1723 val_desc_t *vdp = *vdpp;
1724 val_desc_t *newvdp;
1725 uint_t val_cnt = *val_cntp;
1726 dladm_status_t status = DLADM_STATUS_OK;
1727
1728 /* Get the current pool property */
1729 status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1730 &perm_flags, &mrp, sizeof (mrp));
1731
1732 if (status == DLADM_STATUS_OK) {
1733 /* Can't set cpus if a pool is set */
1734 if (strlen(mrp.mrp_pool) != 0)
1735 return (DLADM_STATUS_POOLCPU);
1736 }
1737
1738 /* Read ranges and convert to mac_propval_range */
1739 status = dladm_strs2range(prop_val, val_cnt, MAC_PROPVAL_UINT32,
1740 &pv_range);
1741 if (status != DLADM_STATUS_OK)
1742 goto done1;
1743
1744 /* Convert mac_propval_range to a single CPU list */
1745 ncpus = MRP_NCPUS;
1746 status = dladm_range2list(pv_range, cpus, &ncpus);
1747 if (status != DLADM_STATUS_OK)
1748 goto done1;
1749
1750 /*
1751 * If a range of CPUs was entered, update value count and reallocate
1752 * the array of val_desc_t's. The array allocated was sized for
1753 * indvidual elements, but needs to be reallocated to accomodate the
1754 * expanded list of CPUs.
1755 */
1756 if (val_cnt < ncpus) {
1757 newvdp = calloc(*val_cntp, sizeof (val_desc_t));
1758 if (newvdp == NULL) {
1759 status = DLADM_STATUS_NOMEM;
1760 goto done1;
1761 }
1762 vdp = newvdp;
1763 }
1764
1765 /* Check if all CPUs in the list are online */
1766 for (i = 0; i < ncpus; i++) {
1767 if (cpus[i] >= nproc) {
1768 status = DLADM_STATUS_BADCPUID;
1769 goto done2;
1770 }
1771
1772 rc = p_online(cpus[i], P_STATUS);
1773 if (rc < 1) {
1774 status = DLADM_STATUS_CPUERR;
1775 goto done2;
1776 }
1777
1778 if (rc != P_ONLINE) {
1779 status = DLADM_STATUS_CPUNOTONLINE;
1780 goto done2;
1781 }
1782
1783 vdp[i].vd_val = (uintptr_t)cpus[i];
1784 }
1785
1786 /* Check for duplicate CPUs */
1787 for (i = 0; i < *val_cntp; i++) {
1788 for (j = 0; j < *val_cntp; j++) {
1789 if (i != j && vdp[i].vd_val == vdp[j].vd_val) {
1790 status = DLADM_STATUS_BADVAL;
1791 goto done2;
1792 }
1793 }
1794 }
1795
1796 /* Update *val_cntp and *vdpp if everything was OK */
1797 if (val_cnt < ncpus) {
1798 *val_cntp = ncpus;
1799 free(*vdpp);
1800 *vdpp = newvdp;
1801 }
1802
1803 status = DLADM_STATUS_OK;
1804 goto done1;
1805
1806 done2:
1807 free(newvdp);
1808 done1:
1809 free(pv_range);
1810 return (status);
1811 }
1812
1813 /* ARGSUSED */
1814 dladm_status_t
extract_cpus(val_desc_t * vdp,uint_t cnt,void * arg)1815 extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
1816 {
1817 mac_resource_props_t *mrp = arg;
1818 int i;
1819
1820 if (vdp[0].vd_val == RESET_VAL) {
1821 bzero(&mrp->mrp_cpus, sizeof (mac_cpus_t));
1822 mrp->mrp_mask |= MRP_CPUS;
1823 return (DLADM_STATUS_OK);
1824 }
1825
1826 for (i = 0; i < cnt; i++)
1827 mrp->mrp_cpu[i] = (uint32_t)vdp[i].vd_val;
1828
1829 mrp->mrp_ncpus = cnt;
1830 mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1831 mrp->mrp_fanout_mode = MCM_CPUS;
1832 mrp->mrp_rx_intr_cpu = -1;
1833
1834 return (DLADM_STATUS_OK);
1835 }
1836
1837 /*
1838 * Get the pool datalink property from the kernel. This is used
1839 * for both the user specified pool and effective pool properties.
1840 */
1841 /* ARGSUSED */
1842 static dladm_status_t
get_pool(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)1843 get_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1844 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1845 uint_t flags, uint_t *perm_flags)
1846 {
1847 mac_resource_props_t mrp;
1848 dladm_status_t status;
1849
1850 if (strcmp(pdp->pd_name, "pool-effective") == 0) {
1851 status = i_dladm_get_public_prop(handle, linkid,
1852 "resource-effective", flags, perm_flags, &mrp,
1853 sizeof (mrp));
1854 } else {
1855 status = i_dladm_get_public_prop(handle, linkid,
1856 "resource", flags, perm_flags, &mrp, sizeof (mrp));
1857 }
1858
1859 if (status != DLADM_STATUS_OK)
1860 return (status);
1861
1862 if (strlen(mrp.mrp_pool) == 0) {
1863 (*prop_val)[0] = '\0';
1864 } else {
1865 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1866 "%s", mrp.mrp_pool);
1867 }
1868 *val_cnt = 1;
1869
1870 return (DLADM_STATUS_OK);
1871 }
1872
1873 /* ARGSUSED */
1874 static dladm_status_t
check_pool(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)1875 check_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1876 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1877 datalink_media_t media)
1878 {
1879 pool_conf_t *poolconf;
1880 pool_t *pool;
1881 mac_resource_props_t mrp;
1882 dladm_status_t status;
1883 uint_t perm_flags;
1884 char *poolname;
1885 val_desc_t *vdp = *vdpp;
1886
1887 /* Get the current cpus property */
1888 status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1889 &perm_flags, &mrp, sizeof (mrp));
1890
1891 if (status == DLADM_STATUS_OK) {
1892 /* Can't set pool if cpus are set */
1893 if (mrp.mrp_ncpus != 0)
1894 return (DLADM_STATUS_POOLCPU);
1895 }
1896
1897 poolname = malloc(sizeof (mrp.mrp_pool));
1898 if (poolname == NULL)
1899 return (DLADM_STATUS_NOMEM);
1900
1901 /* Check for pool's availability if not booting */
1902 if ((flags & DLADM_OPT_BOOT) == 0) {
1903
1904 /* Allocate and open pool configuration */
1905 if ((poolconf = pool_conf_alloc()) == NULL)
1906 return (DLADM_STATUS_BADVAL);
1907
1908 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY)
1909 != PO_SUCCESS) {
1910 pool_conf_free(poolconf);
1911 return (DLADM_STATUS_BADVAL);
1912 }
1913
1914 /* Look for pool name */
1915 if ((pool = pool_get_pool(poolconf, *prop_val)) == NULL) {
1916 pool_conf_free(poolconf);
1917 return (DLADM_STATUS_BADVAL);
1918 }
1919
1920 pool_conf_free(poolconf);
1921 free(pool);
1922 }
1923
1924 (void) strlcpy(poolname, *prop_val, sizeof (mrp.mrp_pool));
1925 vdp->vd_val = (uintptr_t)poolname;
1926
1927 return (DLADM_STATUS_OK);
1928 }
1929
1930 /* ARGSUSED */
1931 dladm_status_t
extract_pool(val_desc_t * vdp,uint_t cnt,void * arg)1932 extract_pool(val_desc_t *vdp, uint_t cnt, void *arg)
1933 {
1934 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
1935
1936 if (vdp->vd_val == RESET_VAL) {
1937 bzero(&mrp->mrp_pool, sizeof (mrp->mrp_pool));
1938 mrp->mrp_mask |= MRP_POOL;
1939 return (DLADM_STATUS_OK);
1940 }
1941
1942 (void) strlcpy(mrp->mrp_pool, (char *)vdp->vd_val,
1943 sizeof (mrp->mrp_pool));
1944 mrp->mrp_mask |= MRP_POOL;
1945 /*
1946 * Use MCM_CPUS since the fanout count is not user specified
1947 * and will be determined by the cpu list generated from the
1948 * pool.
1949 */
1950 mrp->mrp_fanout_mode = MCM_CPUS;
1951
1952 return (DLADM_STATUS_OK);
1953 }
1954
1955 /* ARGSUSED */
1956 static dladm_status_t
get_priority(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)1957 get_priority(dladm_handle_t handle, prop_desc_t *pdp,
1958 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1959 datalink_media_t media, uint_t flags, uint_t *perm_flags)
1960 {
1961 mac_resource_props_t mrp;
1962 mac_priority_level_t pri;
1963 dladm_status_t status;
1964
1965 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1966 perm_flags, &mrp, sizeof (mrp));
1967 if (status != DLADM_STATUS_OK)
1968 return (status);
1969
1970 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
1971 mrp.mrp_priority;
1972
1973 (void) dladm_pri2str(pri, prop_val[0]);
1974 *val_cnt = 1;
1975 return (DLADM_STATUS_OK);
1976 }
1977
1978 /* ARGSUSED */
1979 dladm_status_t
extract_priority(val_desc_t * vdp,uint_t cnt,void * arg)1980 extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
1981 {
1982 mac_resource_props_t *mrp = arg;
1983
1984 if (cnt != 1)
1985 return (DLADM_STATUS_BADVAL);
1986
1987 mrp->mrp_priority = (mac_priority_level_t)vdp->vd_val;
1988 mrp->mrp_mask |= MRP_PRIORITY;
1989
1990 return (DLADM_STATUS_OK);
1991 }
1992
1993 /*
1994 * Determines the size of the structure that needs to be sent to drivers
1995 * for retrieving the property range values.
1996 */
1997 static int
i_dladm_range_size(mac_propval_range_t * r,size_t * sz,uint_t * rcount)1998 i_dladm_range_size(mac_propval_range_t *r, size_t *sz, uint_t *rcount)
1999 {
2000 uint_t count = r->mpr_count;
2001
2002 *sz = sizeof (mac_propval_range_t);
2003 *rcount = count;
2004 --count;
2005
2006 switch (r->mpr_type) {
2007 case MAC_PROPVAL_UINT32:
2008 *sz += (count * sizeof (mac_propval_uint32_range_t));
2009 return (0);
2010 default:
2011 break;
2012 }
2013 *sz = 0;
2014 *rcount = 0;
2015 return (EINVAL);
2016 }
2017
2018
2019 /* ARGSUSED */
2020 static dladm_status_t
check_rings(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vp,datalink_media_t media)2021 check_rings(dladm_handle_t handle, prop_desc_t *pdp,
2022 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2023 val_desc_t **vp, datalink_media_t media)
2024 {
2025 uint_t val_cnt = *val_cntp;
2026 val_desc_t *v = *vp;
2027
2028 if (val_cnt != 1)
2029 return (DLADM_STATUS_BADVAL);
2030 if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) {
2031 v->vd_val = UNSPEC_VAL;
2032 } else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) {
2033 v->vd_val = 0;
2034 } else {
2035 v->vd_val = strtoul(prop_val[0], NULL, 0);
2036 if (v->vd_val == 0)
2037 return (DLADM_STATUS_BADVAL);
2038 }
2039 return (DLADM_STATUS_OK);
2040 }
2041
2042 /* ARGSUSED */
2043 static dladm_status_t
get_rings_range(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2044 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp,
2045 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2046 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2047 {
2048 dld_ioc_macprop_t *dip;
2049 dladm_status_t status = DLADM_STATUS_OK;
2050 mac_propval_range_t *rangep;
2051 size_t sz;
2052 mac_propval_uint32_range_t *ur;
2053
2054 sz = sizeof (mac_propval_range_t);
2055
2056 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
2057 &status)) == NULL)
2058 return (status);
2059
2060 status = i_dladm_macprop(handle, dip, B_FALSE);
2061 if (status != DLADM_STATUS_OK)
2062 return (status);
2063
2064 rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
2065 *val_cnt = 1;
2066 ur = &rangep->mpr_range_uint32[0];
2067 /* This is the case where the dev doesn't have any rings/groups */
2068 if (rangep->mpr_count == 0) {
2069 (*prop_val)[0] = '\0';
2070 /*
2071 * This is the case where the dev supports rings, but static
2072 * grouping.
2073 */
2074 } else if (ur->mpur_min == ur->mpur_max &&
2075 ur->mpur_max == 0) {
2076 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw");
2077 /*
2078 * This is the case where the dev supports rings and dynamic
2079 * grouping, but has only one value (say 2 rings and 2 groups).
2080 */
2081 } else if (ur->mpur_min == ur->mpur_max) {
2082 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d",
2083 ur->mpur_min);
2084 /*
2085 * This is the case where the dev supports rings and dynamic
2086 * grouping and has a range of rings.
2087 */
2088 } else {
2089 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX,
2090 "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max);
2091 }
2092 free(dip);
2093 return (status);
2094 }
2095
2096
2097 /* ARGSUSED */
2098 static dladm_status_t
get_rxrings(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2099 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2100 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2101 uint_t flags, uint_t *perm_flags)
2102 {
2103 mac_resource_props_t mrp;
2104 dladm_status_t status;
2105 uint32_t nrings = 0;
2106
2107 /*
2108 * Get the number of (effective-)rings from the resource property.
2109 */
2110 if (strcmp(pdp->pd_name, "rxrings-effective") == 0) {
2111 status = i_dladm_get_public_prop(handle, linkid,
2112 "resource-effective", flags, perm_flags, &mrp,
2113 sizeof (mrp));
2114 } else {
2115 /*
2116 * Get the permissions from the "rxrings" property.
2117 */
2118 status = i_dladm_get_public_prop(handle, linkid, "rxrings",
2119 flags, perm_flags, NULL, 0);
2120 if (status != DLADM_STATUS_OK)
2121 return (status);
2122
2123 status = i_dladm_get_public_prop(handle, linkid,
2124 "resource", flags, NULL, &mrp, sizeof (mrp));
2125 }
2126
2127 if (status != DLADM_STATUS_OK)
2128 return (status);
2129
2130 if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) {
2131 *val_cnt = 0;
2132 return (DLADM_STATUS_OK);
2133 }
2134 nrings = mrp.mrp_nrxrings;
2135 *val_cnt = 1;
2136 if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC)
2137 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2138 else if (nrings == 0)
2139 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2140 else
2141 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2142 return (DLADM_STATUS_OK);
2143 }
2144
2145 /* ARGSUSED */
2146 dladm_status_t
extract_rxrings(val_desc_t * vdp,uint_t cnt,void * arg)2147 extract_rxrings(val_desc_t *vdp, uint_t cnt, void *arg)
2148 {
2149 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2150
2151 mrp->mrp_nrxrings = 0;
2152 if (vdp->vd_val == RESET_VAL)
2153 mrp->mrp_mask = MRP_RINGS_RESET;
2154 else if (vdp->vd_val == UNSPEC_VAL)
2155 mrp->mrp_mask = MRP_RXRINGS_UNSPEC;
2156 else
2157 mrp->mrp_nrxrings = vdp->vd_val;
2158 mrp->mrp_mask |= MRP_RX_RINGS;
2159
2160 return (DLADM_STATUS_OK);
2161 }
2162
2163 /* ARGSUSED */
2164 static dladm_status_t
get_txrings(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2165 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2166 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2167 uint_t flags, uint_t *perm_flags)
2168 {
2169 mac_resource_props_t mrp;
2170 dladm_status_t status;
2171 uint32_t nrings = 0;
2172
2173
2174 /*
2175 * Get the number of (effective-)rings from the resource property.
2176 */
2177 if (strcmp(pdp->pd_name, "txrings-effective") == 0) {
2178 status = i_dladm_get_public_prop(handle, linkid,
2179 "resource-effective", flags, perm_flags, &mrp,
2180 sizeof (mrp));
2181 } else {
2182 /*
2183 * Get the permissions from the "txrings" property.
2184 */
2185 status = i_dladm_get_public_prop(handle, linkid, "txrings",
2186 flags, perm_flags, NULL, 0);
2187 if (status != DLADM_STATUS_OK)
2188 return (status);
2189
2190 /*
2191 * Get the number of rings from the "resource" property.
2192 */
2193 status = i_dladm_get_public_prop(handle, linkid, "resource",
2194 flags, NULL, &mrp, sizeof (mrp));
2195 }
2196
2197 if (status != DLADM_STATUS_OK)
2198 return (status);
2199
2200 if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) {
2201 *val_cnt = 0;
2202 return (DLADM_STATUS_OK);
2203 }
2204 nrings = mrp.mrp_ntxrings;
2205 *val_cnt = 1;
2206 if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC)
2207 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2208 else if (nrings == 0)
2209 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2210 else
2211 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2212 return (DLADM_STATUS_OK);
2213 }
2214
2215 /* ARGSUSED */
2216 dladm_status_t
extract_txrings(val_desc_t * vdp,uint_t cnt,void * arg)2217 extract_txrings(val_desc_t *vdp, uint_t cnt, void *arg)
2218 {
2219 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2220
2221 mrp->mrp_ntxrings = 0;
2222 if (vdp->vd_val == RESET_VAL)
2223 mrp->mrp_mask = MRP_RINGS_RESET;
2224 else if (vdp->vd_val == UNSPEC_VAL)
2225 mrp->mrp_mask = MRP_TXRINGS_UNSPEC;
2226 else
2227 mrp->mrp_ntxrings = vdp->vd_val;
2228 mrp->mrp_mask |= MRP_TX_RINGS;
2229
2230 return (DLADM_STATUS_OK);
2231 }
2232
2233 /* ARGSUSED */
2234 static dladm_status_t
get_cntavail(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2235 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2236 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2237 uint_t *perm_flags)
2238 {
2239 if (flags & DLD_PROP_DEFAULT)
2240 return (DLADM_STATUS_NOTDEFINED);
2241
2242 return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media,
2243 flags, perm_flags));
2244 }
2245
2246 /* ARGSUSED */
2247 static dladm_status_t
set_resource(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)2248 set_resource(dladm_handle_t handle, prop_desc_t *pdp,
2249 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
2250 uint_t flags, datalink_media_t media)
2251 {
2252 mac_resource_props_t mrp;
2253 dladm_status_t status = DLADM_STATUS_OK;
2254 dld_ioc_macprop_t *dip;
2255 int i;
2256
2257 bzero(&mrp, sizeof (mac_resource_props_t));
2258 dip = i_dladm_buf_alloc_by_name(0, linkid, "resource",
2259 flags, &status);
2260
2261 if (dip == NULL)
2262 return (status);
2263
2264 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
2265 resource_prop_t *rp = &rsrc_prop_table[i];
2266
2267 if (strcmp(pdp->pd_name, rp->rp_name) != 0)
2268 continue;
2269
2270 status = rp->rp_extract(vdp, val_cnt, &mrp);
2271 if (status != DLADM_STATUS_OK)
2272 goto done;
2273
2274 break;
2275 }
2276
2277 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
2278 status = i_dladm_macprop(handle, dip, B_TRUE);
2279
2280 done:
2281 free(dip);
2282 return (status);
2283 }
2284
2285 /* ARGSUSED */
2286 static dladm_status_t
get_protection(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2287 get_protection(dladm_handle_t handle, prop_desc_t *pdp,
2288 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2289 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2290 {
2291 mac_resource_props_t mrp;
2292 mac_protect_t *p;
2293 dladm_status_t status;
2294 uint32_t i, cnt = 0, setbits[32];
2295
2296 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2297 perm_flags, &mrp, sizeof (mrp));
2298 if (status != DLADM_STATUS_OK)
2299 return (status);
2300
2301 p = &mrp.mrp_protect;
2302 if ((mrp.mrp_mask & MRP_PROTECT) == 0) {
2303 *val_cnt = 0;
2304 return (DLADM_STATUS_OK);
2305 }
2306 dladm_find_setbits32(p->mp_types, setbits, &cnt);
2307 if (cnt > *val_cnt)
2308 return (DLADM_STATUS_BADVALCNT);
2309
2310 for (i = 0; i < cnt; i++)
2311 (void) dladm_protect2str(setbits[i], prop_val[i]);
2312
2313 *val_cnt = cnt;
2314 return (DLADM_STATUS_OK);
2315 }
2316
2317 /* ARGSUSED */
2318 static dladm_status_t
get_allowedips(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2319 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2320 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2321 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2322 {
2323 mac_resource_props_t mrp;
2324 mac_protect_t *p;
2325 dladm_status_t status;
2326 int i;
2327
2328 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2329 perm_flags, &mrp, sizeof (mrp));
2330 if (status != DLADM_STATUS_OK)
2331 return (status);
2332
2333 p = &mrp.mrp_protect;
2334 if (p->mp_ipaddrcnt == 0) {
2335 *val_cnt = 0;
2336 return (DLADM_STATUS_OK);
2337 }
2338 if (p->mp_ipaddrcnt > *val_cnt)
2339 return (DLADM_STATUS_BADVALCNT);
2340
2341 for (i = 0; i < p->mp_ipaddrcnt; i++) {
2342 if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) {
2343 ipaddr_t v4addr;
2344
2345 v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr);
2346 (void) dladm_ipv4addr2str(&v4addr, prop_val[i]);
2347 } else {
2348 (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr,
2349 prop_val[i]);
2350 }
2351 }
2352 *val_cnt = p->mp_ipaddrcnt;
2353 return (DLADM_STATUS_OK);
2354 }
2355
2356 dladm_status_t
extract_protection(val_desc_t * vdp,uint_t cnt,void * arg)2357 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
2358 {
2359 mac_resource_props_t *mrp = arg;
2360 uint32_t types = 0;
2361 int i;
2362
2363 for (i = 0; i < cnt; i++)
2364 types |= (uint32_t)vdp[i].vd_val;
2365
2366 mrp->mrp_protect.mp_types = types;
2367 mrp->mrp_mask |= MRP_PROTECT;
2368 return (DLADM_STATUS_OK);
2369 }
2370
2371 dladm_status_t
extract_allowedips(val_desc_t * vdp,uint_t cnt,void * arg)2372 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
2373 {
2374 mac_resource_props_t *mrp = arg;
2375 mac_protect_t *p = &mrp->mrp_protect;
2376 int i;
2377
2378 if (vdp->vd_val == 0) {
2379 cnt = (uint_t)-1;
2380 } else {
2381 for (i = 0; i < cnt; i++) {
2382 bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i],
2383 sizeof (mac_ipaddr_t));
2384 }
2385 }
2386 p->mp_ipaddrcnt = cnt;
2387 mrp->mrp_mask |= MRP_PROTECT;
2388 return (DLADM_STATUS_OK);
2389 }
2390
2391 static dladm_status_t
check_single_ip(char * buf,mac_ipaddr_t * addr)2392 check_single_ip(char *buf, mac_ipaddr_t *addr)
2393 {
2394 dladm_status_t status;
2395 ipaddr_t v4addr;
2396 in6_addr_t v6addr;
2397 boolean_t isv4 = B_TRUE;
2398
2399 status = dladm_str2ipv4addr(buf, &v4addr);
2400 if (status == DLADM_STATUS_INVALID_IP) {
2401 status = dladm_str2ipv6addr(buf, &v6addr);
2402 if (status == DLADM_STATUS_OK)
2403 isv4 = B_FALSE;
2404 }
2405 if (status != DLADM_STATUS_OK)
2406 return (status);
2407
2408 if (isv4) {
2409 if (v4addr == INADDR_ANY)
2410 return (DLADM_STATUS_INVALID_IP);
2411
2412 IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr);
2413 addr->ip_version = IPV4_VERSION;
2414 } else {
2415 if (IN6_IS_ADDR_UNSPECIFIED(&v6addr))
2416 return (DLADM_STATUS_INVALID_IP);
2417
2418 addr->ip_addr = v6addr;
2419 addr->ip_version = IPV6_VERSION;
2420 }
2421 return (DLADM_STATUS_OK);
2422 }
2423
2424 /* ARGSUSED */
2425 static dladm_status_t
check_allowedips(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)2426 check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2427 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2428 val_desc_t **vdpp, datalink_media_t media)
2429 {
2430 dladm_status_t status;
2431 mac_ipaddr_t *addr;
2432 int i;
2433 uint_t val_cnt = *val_cntp;
2434 val_desc_t *vdp = *vdpp;
2435
2436 if (val_cnt > MPT_MAXIPADDR)
2437 return (DLADM_STATUS_BADVALCNT);
2438
2439 for (i = 0; i < val_cnt; i++) {
2440 if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) {
2441 status = DLADM_STATUS_NOMEM;
2442 goto fail;
2443 }
2444 vdp[i].vd_val = (uintptr_t)addr;
2445
2446 status = check_single_ip(prop_val[i], addr);
2447 if (status != DLADM_STATUS_OK)
2448 goto fail;
2449 }
2450 return (DLADM_STATUS_OK);
2451
2452 fail:
2453 for (i = 0; i < val_cnt; i++) {
2454 free((void *)vdp[i].vd_val);
2455 vdp[i].vd_val = NULL;
2456 }
2457 return (status);
2458 }
2459
2460 static void
dladm_cid2str(mac_dhcpcid_t * cid,char * buf)2461 dladm_cid2str(mac_dhcpcid_t *cid, char *buf)
2462 {
2463 char tmp_buf[DLADM_STRSIZE];
2464 uint_t hexlen;
2465
2466 switch (cid->dc_form) {
2467 case CIDFORM_TYPED: {
2468 uint16_t duidtype, hwtype;
2469 uint32_t timestamp, ennum;
2470 char *lladdr;
2471
2472 if (cid->dc_len < sizeof (duidtype))
2473 goto fail;
2474
2475 bcopy(cid->dc_id, &duidtype, sizeof (duidtype));
2476 duidtype = ntohs(duidtype);
2477 switch (duidtype) {
2478 case DHCPV6_DUID_LLT: {
2479 duid_llt_t llt;
2480
2481 if (cid->dc_len < sizeof (llt))
2482 goto fail;
2483
2484 bcopy(cid->dc_id, &llt, sizeof (llt));
2485 hwtype = ntohs(llt.dllt_hwtype);
2486 timestamp = ntohl(llt.dllt_time);
2487 lladdr = _link_ntoa(cid->dc_id + sizeof (llt),
2488 NULL, cid->dc_len - sizeof (llt), IFT_OTHER);
2489 if (lladdr == NULL)
2490 goto fail;
2491
2492 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s",
2493 duidtype, hwtype, timestamp, lladdr);
2494 free(lladdr);
2495 break;
2496 }
2497 case DHCPV6_DUID_EN: {
2498 duid_en_t en;
2499
2500 if (cid->dc_len < sizeof (en))
2501 goto fail;
2502
2503 bcopy(cid->dc_id, &en, sizeof (en));
2504 ennum = DHCPV6_GET_ENTNUM(&en);
2505 hexlen = sizeof (tmp_buf);
2506 if (octet_to_hexascii(cid->dc_id + sizeof (en),
2507 cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0)
2508 goto fail;
2509
2510 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2511 duidtype, ennum, tmp_buf);
2512 break;
2513 }
2514 case DHCPV6_DUID_LL: {
2515 duid_ll_t ll;
2516
2517 if (cid->dc_len < sizeof (ll))
2518 goto fail;
2519
2520 bcopy(cid->dc_id, &ll, sizeof (ll));
2521 hwtype = ntohs(ll.dll_hwtype);
2522 lladdr = _link_ntoa(cid->dc_id + sizeof (ll),
2523 NULL, cid->dc_len - sizeof (ll), IFT_OTHER);
2524 if (lladdr == NULL)
2525 goto fail;
2526
2527 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2528 duidtype, hwtype, lladdr);
2529 free(lladdr);
2530 break;
2531 }
2532 default: {
2533 hexlen = sizeof (tmp_buf);
2534 if (octet_to_hexascii(cid->dc_id + sizeof (duidtype),
2535 cid->dc_len - sizeof (duidtype),
2536 tmp_buf, &hexlen) != 0)
2537 goto fail;
2538
2539 (void) snprintf(buf, DLADM_STRSIZE, "%d.%s",
2540 duidtype, tmp_buf);
2541 }
2542 }
2543 break;
2544 }
2545 case CIDFORM_HEX: {
2546 hexlen = sizeof (tmp_buf);
2547 if (octet_to_hexascii(cid->dc_id, cid->dc_len,
2548 tmp_buf, &hexlen) != 0)
2549 goto fail;
2550
2551 (void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf);
2552 break;
2553 }
2554 case CIDFORM_STR: {
2555 int i;
2556
2557 for (i = 0; i < cid->dc_len; i++) {
2558 if (!isprint(cid->dc_id[i]))
2559 goto fail;
2560 }
2561 (void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id);
2562 break;
2563 }
2564 default:
2565 goto fail;
2566 }
2567 return;
2568
2569 fail:
2570 (void) snprintf(buf, DLADM_STRSIZE, "<unknown>");
2571 }
2572
2573 static dladm_status_t
dladm_str2cid(char * buf,mac_dhcpcid_t * cid)2574 dladm_str2cid(char *buf, mac_dhcpcid_t *cid)
2575 {
2576 char *ptr = buf;
2577 char tmp_buf[DLADM_STRSIZE];
2578 uint_t hexlen, cidlen;
2579
2580 bzero(cid, sizeof (*cid));
2581 if (isdigit(*ptr) &&
2582 ptr[strspn(ptr, "0123456789")] == '.') {
2583 char *cp;
2584 ulong_t duidtype;
2585 ulong_t subtype;
2586 ulong_t timestamp;
2587 uchar_t *lladdr;
2588 int addrlen;
2589
2590 errno = 0;
2591 duidtype = strtoul(ptr, &cp, 0);
2592 if (ptr == cp || errno != 0 || *cp != '.' ||
2593 duidtype > USHRT_MAX)
2594 return (DLADM_STATUS_BADARG);
2595 ptr = cp + 1;
2596
2597 if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) {
2598 errno = 0;
2599 subtype = strtoul(ptr, &cp, 0);
2600 if (ptr == cp || errno != 0 || *cp != '.')
2601 return (DLADM_STATUS_BADARG);
2602 ptr = cp + 1;
2603 }
2604 switch (duidtype) {
2605 case DHCPV6_DUID_LLT: {
2606 duid_llt_t llt;
2607
2608 errno = 0;
2609 timestamp = strtoul(ptr, &cp, 0);
2610 if (ptr == cp || errno != 0 || *cp != '.')
2611 return (DLADM_STATUS_BADARG);
2612
2613 ptr = cp + 1;
2614 lladdr = _link_aton(ptr, &addrlen);
2615 if (lladdr == NULL)
2616 return (DLADM_STATUS_BADARG);
2617
2618 cidlen = sizeof (llt) + addrlen;
2619 if (cidlen > sizeof (cid->dc_id)) {
2620 free(lladdr);
2621 return (DLADM_STATUS_TOOSMALL);
2622 }
2623 llt.dllt_dutype = htons(duidtype);
2624 llt.dllt_hwtype = htons(subtype);
2625 llt.dllt_time = htonl(timestamp);
2626 bcopy(&llt, cid->dc_id, sizeof (llt));
2627 bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen);
2628 free(lladdr);
2629 break;
2630 }
2631 case DHCPV6_DUID_LL: {
2632 duid_ll_t ll;
2633
2634 lladdr = _link_aton(ptr, &addrlen);
2635 if (lladdr == NULL)
2636 return (DLADM_STATUS_BADARG);
2637
2638 cidlen = sizeof (ll) + addrlen;
2639 if (cidlen > sizeof (cid->dc_id)) {
2640 free(lladdr);
2641 return (DLADM_STATUS_TOOSMALL);
2642 }
2643 ll.dll_dutype = htons(duidtype);
2644 ll.dll_hwtype = htons(subtype);
2645 bcopy(&ll, cid->dc_id, sizeof (ll));
2646 bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen);
2647 free(lladdr);
2648 break;
2649 }
2650 default: {
2651 hexlen = sizeof (tmp_buf);
2652 if (hexascii_to_octet(ptr, strlen(ptr),
2653 tmp_buf, &hexlen) != 0)
2654 return (DLADM_STATUS_BADARG);
2655
2656 if (duidtype == DHCPV6_DUID_EN) {
2657 duid_en_t en;
2658
2659 en.den_dutype = htons(duidtype);
2660 DHCPV6_SET_ENTNUM(&en, subtype);
2661
2662 cidlen = sizeof (en) + hexlen;
2663 if (cidlen > sizeof (cid->dc_id))
2664 return (DLADM_STATUS_TOOSMALL);
2665
2666 bcopy(&en, cid->dc_id, sizeof (en));
2667 bcopy(tmp_buf, cid->dc_id + sizeof (en),
2668 hexlen);
2669 } else {
2670 uint16_t dutype = htons(duidtype);
2671
2672 cidlen = sizeof (dutype) + hexlen;
2673 if (cidlen > sizeof (cid->dc_id))
2674 return (DLADM_STATUS_TOOSMALL);
2675
2676 bcopy(&dutype, cid->dc_id, sizeof (dutype));
2677 bcopy(tmp_buf, cid->dc_id + sizeof (dutype),
2678 hexlen);
2679 }
2680 break;
2681 }
2682 }
2683 cid->dc_form = CIDFORM_TYPED;
2684 } else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') {
2685 ptr += 2;
2686 hexlen = sizeof (tmp_buf);
2687 if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf,
2688 &hexlen) != 0) {
2689 return (DLADM_STATUS_BADARG);
2690 }
2691 cidlen = hexlen;
2692 if (cidlen > sizeof (cid->dc_id))
2693 return (DLADM_STATUS_TOOSMALL);
2694
2695 bcopy(tmp_buf, cid->dc_id, cidlen);
2696 cid->dc_form = CIDFORM_HEX;
2697 } else {
2698 cidlen = strlen(ptr);
2699 if (cidlen > sizeof (cid->dc_id))
2700 return (DLADM_STATUS_TOOSMALL);
2701
2702 bcopy(ptr, cid->dc_id, cidlen);
2703 cid->dc_form = CIDFORM_STR;
2704 }
2705 cid->dc_len = cidlen;
2706 return (DLADM_STATUS_OK);
2707 }
2708
2709 /* ARGSUSED */
2710 static dladm_status_t
get_allowedcids(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2711 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2712 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2713 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2714 {
2715 mac_resource_props_t mrp;
2716 mac_protect_t *p;
2717 dladm_status_t status;
2718 int i;
2719
2720 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2721 perm_flags, &mrp, sizeof (mrp));
2722 if (status != DLADM_STATUS_OK)
2723 return (status);
2724
2725 p = &mrp.mrp_protect;
2726 if (p->mp_cidcnt == 0) {
2727 *val_cnt = 0;
2728 return (DLADM_STATUS_OK);
2729 }
2730 if (p->mp_cidcnt > *val_cnt)
2731 return (DLADM_STATUS_BADVALCNT);
2732
2733 for (i = 0; i < p->mp_cidcnt; i++) {
2734 mac_dhcpcid_t *cid = &p->mp_cids[i];
2735
2736 dladm_cid2str(cid, prop_val[i]);
2737 }
2738 *val_cnt = p->mp_cidcnt;
2739 return (DLADM_STATUS_OK);
2740 }
2741
2742 dladm_status_t
extract_allowedcids(val_desc_t * vdp,uint_t cnt,void * arg)2743 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg)
2744 {
2745 mac_resource_props_t *mrp = arg;
2746 mac_protect_t *p = &mrp->mrp_protect;
2747 int i;
2748
2749 if (vdp->vd_val == 0) {
2750 cnt = (uint_t)-1;
2751 } else {
2752 for (i = 0; i < cnt; i++) {
2753 bcopy((void *)vdp[i].vd_val, &p->mp_cids[i],
2754 sizeof (mac_dhcpcid_t));
2755 }
2756 }
2757 p->mp_cidcnt = cnt;
2758 mrp->mrp_mask |= MRP_PROTECT;
2759 return (DLADM_STATUS_OK);
2760 }
2761
2762 /* ARGSUSED */
2763 static dladm_status_t
check_allowedcids(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)2764 check_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2765 datalink_id_t linkid, char **prop_val, uint_t *val_cntp,
2766 uint_t flags, val_desc_t **vdpp, datalink_media_t media)
2767 {
2768 dladm_status_t status;
2769 mac_dhcpcid_t *cid;
2770 int i;
2771 uint_t val_cnt = *val_cntp;
2772 val_desc_t *vdp = *vdpp;
2773
2774 if (val_cnt > MPT_MAXCID)
2775 return (DLADM_STATUS_BADVALCNT);
2776
2777 for (i = 0; i < val_cnt; i++) {
2778 if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) {
2779 status = DLADM_STATUS_NOMEM;
2780 goto fail;
2781 }
2782 vdp[i].vd_val = (uintptr_t)cid;
2783
2784 status = dladm_str2cid(prop_val[i], cid);
2785 if (status != DLADM_STATUS_OK)
2786 goto fail;
2787 }
2788 return (DLADM_STATUS_OK);
2789
2790 fail:
2791 for (i = 0; i < val_cnt; i++) {
2792 free((void *)vdp[i].vd_val);
2793 vdp[i].vd_val = NULL;
2794 }
2795 return (status);
2796 }
2797
2798 /* ARGSUSED */
2799 static dladm_status_t
get_autopush(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2800 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2801 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2802 uint_t flags, uint_t *perm_flags)
2803 {
2804 struct dlautopush dlap;
2805 int i, len;
2806 dladm_status_t status;
2807
2808 if (flags & DLD_PROP_DEFAULT)
2809 return (DLADM_STATUS_NOTDEFINED);
2810
2811 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2812 perm_flags, &dlap, sizeof (dlap));
2813 if (status != DLADM_STATUS_OK)
2814 return (status);
2815
2816 if (dlap.dap_npush == 0) {
2817 *val_cnt = 0;
2818 return (DLADM_STATUS_OK);
2819 }
2820 for (i = 0, len = 0; i < dlap.dap_npush; i++) {
2821 if (i != 0) {
2822 (void) snprintf(*prop_val + len,
2823 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
2824 len += 1;
2825 }
2826 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
2827 "%s", dlap.dap_aplist[i]);
2828 len += strlen(dlap.dap_aplist[i]);
2829 if (dlap.dap_anchor - 1 == i) {
2830 (void) snprintf(*prop_val + len,
2831 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
2832 AP_ANCHOR);
2833 len += (strlen(AP_ANCHOR) + 1);
2834 }
2835 }
2836 *val_cnt = 1;
2837 return (DLADM_STATUS_OK);
2838 }
2839
2840 /*
2841 * Add the specified module to the dlautopush structure; returns a
2842 * DLADM_STATUS_* code.
2843 */
2844 dladm_status_t
i_dladm_add_ap_module(const char * module,struct dlautopush * dlap)2845 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
2846 {
2847 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
2848 return (DLADM_STATUS_BADVAL);
2849
2850 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
2851 /*
2852 * We don't allow multiple anchors, and the anchor must
2853 * be after at least one module.
2854 */
2855 if (dlap->dap_anchor != 0)
2856 return (DLADM_STATUS_BADVAL);
2857 if (dlap->dap_npush == 0)
2858 return (DLADM_STATUS_BADVAL);
2859
2860 dlap->dap_anchor = dlap->dap_npush;
2861 return (DLADM_STATUS_OK);
2862 }
2863 if (dlap->dap_npush >= MAXAPUSH)
2864 return (DLADM_STATUS_BADVALCNT);
2865
2866 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
2867 FMNAMESZ + 1);
2868
2869 return (DLADM_STATUS_OK);
2870 }
2871
2872 /*
2873 * Currently, both '.' and ' '(space) can be used as the delimiters between
2874 * autopush modules. The former is used in dladm set-linkprop, and the
2875 * latter is used in the autopush(1M) file.
2876 */
2877 /* ARGSUSED */
2878 static dladm_status_t
check_autopush(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)2879 check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2880 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
2881 datalink_media_t media)
2882 {
2883 char *module;
2884 struct dlautopush *dlap;
2885 dladm_status_t status;
2886 char val[DLADM_PROP_VAL_MAX];
2887 char delimiters[4];
2888 uint_t val_cnt = *val_cntp;
2889 val_desc_t *vdp = *vdpp;
2890
2891 if (val_cnt != 1)
2892 return (DLADM_STATUS_BADVALCNT);
2893
2894 if (prop_val != NULL) {
2895 dlap = malloc(sizeof (struct dlautopush));
2896 if (dlap == NULL)
2897 return (DLADM_STATUS_NOMEM);
2898
2899 (void) memset(dlap, 0, sizeof (struct dlautopush));
2900 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
2901 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
2902 module = strtok(val, delimiters);
2903 while (module != NULL) {
2904 status = i_dladm_add_ap_module(module, dlap);
2905 if (status != DLADM_STATUS_OK)
2906 return (status);
2907 module = strtok(NULL, delimiters);
2908 }
2909
2910 vdp->vd_val = (uintptr_t)dlap;
2911 } else {
2912 vdp->vd_val = 0;
2913 }
2914 return (DLADM_STATUS_OK);
2915 }
2916
2917 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
2918
2919 /* ARGSUSED */
2920 static dladm_status_t
get_rate_common(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,uint_t id,uint_t * perm_flags)2921 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
2922 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
2923 uint_t *perm_flags)
2924 {
2925 wl_rates_t *wrp;
2926 uint_t i;
2927 dladm_status_t status = DLADM_STATUS_OK;
2928
2929 wrp = malloc(WLDP_BUFSIZE);
2930 if (wrp == NULL)
2931 return (DLADM_STATUS_NOMEM);
2932
2933 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
2934 B_FALSE);
2935 if (status != DLADM_STATUS_OK)
2936 goto done;
2937
2938 if (wrp->wl_rates_num > *val_cnt) {
2939 status = DLADM_STATUS_TOOSMALL;
2940 goto done;
2941 }
2942
2943 if (wrp->wl_rates_rates[0] == 0) {
2944 prop_val[0][0] = '\0';
2945 *val_cnt = 1;
2946 goto done;
2947 }
2948
2949 for (i = 0; i < wrp->wl_rates_num; i++) {
2950 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
2951 wrp->wl_rates_rates[i] % 2,
2952 (float)wrp->wl_rates_rates[i] / 2);
2953 }
2954 *val_cnt = wrp->wl_rates_num;
2955 *perm_flags = MAC_PROP_PERM_RW;
2956
2957 done:
2958 free(wrp);
2959 return (status);
2960 }
2961
2962 static dladm_status_t
get_rate(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2963 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2964 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2965 uint_t flags, uint_t *perm_flags)
2966 {
2967 if (media != DL_WIFI) {
2968 return (get_speed(handle, pdp, linkid, prop_val,
2969 val_cnt, media, flags, perm_flags));
2970 }
2971
2972 return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
2973 MAC_PROP_WL_DESIRED_RATES, perm_flags));
2974 }
2975
2976 /* ARGSUSED */
2977 static dladm_status_t
get_rate_mod(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)2978 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2979 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2980 uint_t flags, uint_t *perm_flags)
2981 {
2982 switch (media) {
2983 case DL_ETHER:
2984 /*
2985 * Speed for ethernet links is unbounded. E.g., 802.11b
2986 * links can have a speed of 5.5 Gbps.
2987 */
2988 return (DLADM_STATUS_NOTSUP);
2989
2990 case DL_WIFI:
2991 return (get_rate_common(handle, pdp, linkid, prop_val,
2992 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
2993 default:
2994 return (DLADM_STATUS_BADARG);
2995 }
2996 }
2997
2998 static dladm_status_t
set_wlan_rate(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_rates_t * rates)2999 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid,
3000 dladm_wlan_rates_t *rates)
3001 {
3002 int i;
3003 uint_t len;
3004 wl_rates_t *wrp;
3005 dladm_status_t status = DLADM_STATUS_OK;
3006
3007 wrp = malloc(WLDP_BUFSIZE);
3008 if (wrp == NULL)
3009 return (DLADM_STATUS_NOMEM);
3010
3011 bzero(wrp, WLDP_BUFSIZE);
3012 for (i = 0; i < rates->wr_cnt; i++)
3013 wrp->wl_rates_rates[i] = rates->wr_rates[i];
3014 wrp->wl_rates_num = rates->wr_cnt;
3015
3016 len = offsetof(wl_rates_t, wl_rates_rates) +
3017 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
3018 status = i_dladm_wlan_param(handle, linkid, wrp,
3019 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
3020
3021 free(wrp);
3022 return (status);
3023 }
3024
3025 /* ARGSUSED */
3026 static dladm_status_t
set_rate(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)3027 set_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3028 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3029 {
3030 dladm_wlan_rates_t rates;
3031 dladm_status_t status;
3032
3033 /*
3034 * can currently set rate on WIFI links only.
3035 */
3036 if (media != DL_WIFI)
3037 return (DLADM_STATUS_PROPRDONLY);
3038
3039 if (val_cnt != 1)
3040 return (DLADM_STATUS_BADVALCNT);
3041
3042 rates.wr_cnt = 1;
3043 rates.wr_rates[0] = vdp[0].vd_val;
3044
3045 status = set_wlan_rate(handle, linkid, &rates);
3046
3047 return (status);
3048 }
3049
3050 /* ARGSUSED */
3051 static dladm_status_t
check_rate(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)3052 check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3053 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3054 datalink_media_t media)
3055 {
3056 int i;
3057 uint_t modval_cnt = MAX_SUPPORT_RATES;
3058 char *buf, **modval;
3059 dladm_status_t status;
3060 uint_t perm_flags;
3061 uint_t val_cnt = *val_cntp;
3062 val_desc_t *vdp = *vdpp;
3063
3064 if (val_cnt != 1)
3065 return (DLADM_STATUS_BADVALCNT);
3066
3067 buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
3068 MAX_SUPPORT_RATES);
3069 if (buf == NULL) {
3070 status = DLADM_STATUS_NOMEM;
3071 goto done;
3072 }
3073
3074 modval = (char **)(void *)buf;
3075 for (i = 0; i < MAX_SUPPORT_RATES; i++) {
3076 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
3077 i * DLADM_STRSIZE;
3078 }
3079
3080 status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
3081 media, 0, &perm_flags);
3082 if (status != DLADM_STATUS_OK)
3083 goto done;
3084
3085 for (i = 0; i < modval_cnt; i++) {
3086 if (strcasecmp(*prop_val, modval[i]) == 0) {
3087 vdp->vd_val = (uintptr_t)(uint_t)
3088 (atof(*prop_val) * 2);
3089 status = DLADM_STATUS_OK;
3090 break;
3091 }
3092 }
3093 if (i == modval_cnt)
3094 status = DLADM_STATUS_BADVAL;
3095 done:
3096 free(buf);
3097 return (status);
3098 }
3099
3100 static dladm_status_t
get_phyconf(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)3101 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
3102 int buflen)
3103 {
3104 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
3105 buflen, B_FALSE));
3106 }
3107
3108 /* ARGSUSED */
3109 static dladm_status_t
get_channel(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3110 get_channel(dladm_handle_t handle, prop_desc_t *pdp,
3111 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3112 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3113 {
3114 uint32_t channel;
3115 char buf[WLDP_BUFSIZE];
3116 dladm_status_t status;
3117 wl_phy_conf_t wl_phy_conf;
3118
3119 if ((status = get_phyconf(handle, linkid, buf, sizeof (buf)))
3120 != DLADM_STATUS_OK)
3121 return (status);
3122
3123 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
3124 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel))
3125 return (DLADM_STATUS_NOTFOUND);
3126
3127 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
3128 *val_cnt = 1;
3129 *perm_flags = MAC_PROP_PERM_READ;
3130 return (DLADM_STATUS_OK);
3131 }
3132
3133 /* ARGSUSED */
3134 static dladm_status_t
get_powermode(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3135 get_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3136 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3137 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3138 {
3139 wl_ps_mode_t mode;
3140 const char *s;
3141 char buf[WLDP_BUFSIZE];
3142 dladm_status_t status;
3143
3144 if ((status = i_dladm_wlan_param(handle, linkid, buf,
3145 MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3146 return (status);
3147
3148 (void) memcpy(&mode, buf, sizeof (mode));
3149 switch (mode.wl_ps_mode) {
3150 case WL_PM_AM:
3151 s = "off";
3152 break;
3153 case WL_PM_MPS:
3154 s = "max";
3155 break;
3156 case WL_PM_FAST:
3157 s = "fast";
3158 break;
3159 default:
3160 return (DLADM_STATUS_NOTFOUND);
3161 }
3162 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3163 *val_cnt = 1;
3164 *perm_flags = MAC_PROP_PERM_RW;
3165 return (DLADM_STATUS_OK);
3166 }
3167
3168 /* ARGSUSED */
3169 static dladm_status_t
set_powermode(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)3170 set_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3171 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3172 datalink_media_t media)
3173 {
3174 dladm_wlan_powermode_t powermode = vdp->vd_val;
3175 wl_ps_mode_t ps_mode;
3176
3177 if (val_cnt != 1)
3178 return (DLADM_STATUS_BADVALCNT);
3179
3180 (void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3181
3182 switch (powermode) {
3183 case DLADM_WLAN_PM_OFF:
3184 ps_mode.wl_ps_mode = WL_PM_AM;
3185 break;
3186 case DLADM_WLAN_PM_MAX:
3187 ps_mode.wl_ps_mode = WL_PM_MPS;
3188 break;
3189 case DLADM_WLAN_PM_FAST:
3190 ps_mode.wl_ps_mode = WL_PM_FAST;
3191 break;
3192 default:
3193 return (DLADM_STATUS_NOTSUP);
3194 }
3195 return (i_dladm_wlan_param(handle, linkid, &ps_mode,
3196 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
3197 }
3198
3199 /* ARGSUSED */
3200 static dladm_status_t
get_radio(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3201 get_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3202 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3203 uint_t flags, uint_t *perm_flags)
3204 {
3205 wl_radio_t radio;
3206 const char *s;
3207 char buf[WLDP_BUFSIZE];
3208 dladm_status_t status;
3209
3210 if ((status = i_dladm_wlan_param(handle, linkid, buf,
3211 MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3212 return (status);
3213
3214 (void) memcpy(&radio, buf, sizeof (radio));
3215 switch (radio) {
3216 case B_TRUE:
3217 s = "on";
3218 break;
3219 case B_FALSE:
3220 s = "off";
3221 break;
3222 default:
3223 return (DLADM_STATUS_NOTFOUND);
3224 }
3225 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3226 *val_cnt = 1;
3227 *perm_flags = MAC_PROP_PERM_RW;
3228 return (DLADM_STATUS_OK);
3229 }
3230
3231 /* ARGSUSED */
3232 static dladm_status_t
set_radio(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)3233 set_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3234 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3235 {
3236 dladm_wlan_radio_t radio = vdp->vd_val;
3237 wl_radio_t r;
3238
3239 if (val_cnt != 1)
3240 return (DLADM_STATUS_BADVALCNT);
3241
3242 switch (radio) {
3243 case DLADM_WLAN_RADIO_ON:
3244 r = B_TRUE;
3245 break;
3246 case DLADM_WLAN_RADIO_OFF:
3247 r = B_FALSE;
3248 break;
3249 default:
3250 return (DLADM_STATUS_NOTSUP);
3251 }
3252 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
3253 sizeof (r), B_TRUE));
3254 }
3255
3256 /* ARGSUSED */
3257 static dladm_status_t
check_hoplimit(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)3258 check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp,
3259 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3260 val_desc_t **vdpp, datalink_media_t media)
3261 {
3262 int32_t hlim;
3263 char *ep;
3264 uint_t val_cnt = *val_cntp;
3265 val_desc_t *vdp = *vdpp;
3266
3267 if (val_cnt != 1)
3268 return (DLADM_STATUS_BADVALCNT);
3269
3270 errno = 0;
3271 hlim = strtol(*prop_val, &ep, 10);
3272 if (errno != 0 || ep == *prop_val || hlim < 1 ||
3273 hlim > (int32_t)UINT8_MAX)
3274 return (DLADM_STATUS_BADVAL);
3275 vdp->vd_val = hlim;
3276 return (DLADM_STATUS_OK);
3277 }
3278
3279 /* ARGSUSED */
3280 static dladm_status_t
check_encaplim(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)3281 check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3282 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3283 datalink_media_t media)
3284 {
3285 int32_t elim;
3286 char *ep;
3287 uint_t val_cnt = *val_cntp;
3288 val_desc_t *vdp = *vdpp;
3289
3290 if (media != DL_IPV6)
3291 return (DLADM_STATUS_BADARG);
3292
3293 if (val_cnt != 1)
3294 return (DLADM_STATUS_BADVALCNT);
3295
3296 errno = 0;
3297 elim = strtol(*prop_val, &ep, 10);
3298 if (errno != 0 || ep == *prop_val || elim < 0 ||
3299 elim > (int32_t)UINT8_MAX)
3300 return (DLADM_STATUS_BADVAL);
3301 vdp->vd_val = elim;
3302 return (DLADM_STATUS_OK);
3303 }
3304
3305 static dladm_status_t
i_dladm_set_linkprop_db(dladm_handle_t handle,datalink_id_t linkid,const char * prop_name,char ** prop_val,uint_t val_cnt)3306 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3307 const char *prop_name, char **prop_val, uint_t val_cnt)
3308 {
3309 char buf[MAXLINELEN];
3310 int i;
3311 dladm_conf_t conf;
3312 dladm_status_t status;
3313
3314 status = dladm_open_conf(handle, linkid, &conf);
3315 if (status != DLADM_STATUS_OK)
3316 return (status);
3317
3318 /*
3319 * reset case.
3320 */
3321 if (val_cnt == 0) {
3322 status = dladm_unset_conf_field(handle, conf, prop_name);
3323 if (status == DLADM_STATUS_OK)
3324 status = dladm_write_conf(handle, conf);
3325 goto done;
3326 }
3327
3328 buf[0] = '\0';
3329 for (i = 0; i < val_cnt; i++) {
3330 (void) strlcat(buf, prop_val[i], MAXLINELEN);
3331 if (i != val_cnt - 1)
3332 (void) strlcat(buf, ",", MAXLINELEN);
3333 }
3334
3335 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
3336 buf);
3337 if (status == DLADM_STATUS_OK)
3338 status = dladm_write_conf(handle, conf);
3339
3340 done:
3341 dladm_destroy_conf(handle, conf);
3342 return (status);
3343 }
3344
3345 static dladm_status_t
i_dladm_get_linkprop_db(dladm_handle_t handle,datalink_id_t linkid,const char * prop_name,char ** prop_val,uint_t * val_cntp)3346 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3347 const char *prop_name, char **prop_val, uint_t *val_cntp)
3348 {
3349 char buf[MAXLINELEN], *str;
3350 uint_t cnt = 0;
3351 dladm_conf_t conf;
3352 dladm_status_t status;
3353
3354 status = dladm_getsnap_conf(handle, linkid, &conf);
3355 if (status != DLADM_STATUS_OK)
3356 return (status);
3357
3358 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
3359 if (status != DLADM_STATUS_OK)
3360 goto done;
3361
3362 str = strtok(buf, ",");
3363 while (str != NULL) {
3364 if (cnt == *val_cntp) {
3365 status = DLADM_STATUS_TOOSMALL;
3366 goto done;
3367 }
3368 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
3369 str = strtok(NULL, ",");
3370 }
3371
3372 *val_cntp = cnt;
3373
3374 done:
3375 dladm_destroy_conf(handle, conf);
3376 return (status);
3377 }
3378
3379 /*
3380 * Walk persistent private link properties of a link.
3381 */
3382 static dladm_status_t
i_dladm_walk_linkprop_priv_db(dladm_handle_t handle,datalink_id_t linkid,void * arg,int (* func)(dladm_handle_t,datalink_id_t,const char *,void *))3383 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
3384 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
3385 {
3386 dladm_status_t status;
3387 dladm_conf_t conf;
3388 char last_attr[MAXLINKATTRLEN];
3389 char attr[MAXLINKATTRLEN];
3390 char attrval[MAXLINKATTRVALLEN];
3391 size_t attrsz;
3392
3393 if (linkid == DATALINK_INVALID_LINKID || func == NULL)
3394 return (DLADM_STATUS_BADARG);
3395
3396 status = dladm_getsnap_conf(handle, linkid, &conf);
3397 if (status != DLADM_STATUS_OK)
3398 return (status);
3399
3400 last_attr[0] = '\0';
3401 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
3402 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
3403 if (attr[0] == '_') {
3404 if (func(handle, linkid, attr, arg) ==
3405 DLADM_WALK_TERMINATE)
3406 break;
3407 }
3408 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
3409 }
3410
3411 dladm_destroy_conf(handle, conf);
3412 return (DLADM_STATUS_OK);
3413 }
3414
3415 static link_attr_t *
dladm_name2prop(const char * prop_name)3416 dladm_name2prop(const char *prop_name)
3417 {
3418 link_attr_t *p;
3419
3420 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3421 if (strcmp(p->pp_name, prop_name) == 0)
3422 break;
3423 }
3424 return (p);
3425 }
3426
3427 static link_attr_t *
dladm_id2prop(mac_prop_id_t propid)3428 dladm_id2prop(mac_prop_id_t propid)
3429 {
3430 link_attr_t *p;
3431
3432 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3433 if (p->pp_id == propid)
3434 break;
3435 }
3436 return (p);
3437 }
3438
3439 static dld_ioc_macprop_t *
i_dladm_buf_alloc_impl(size_t valsize,datalink_id_t linkid,const char * prop_name,mac_prop_id_t propid,uint_t flags,dladm_status_t * status)3440 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
3441 const char *prop_name, mac_prop_id_t propid, uint_t flags,
3442 dladm_status_t *status)
3443 {
3444 int dsize;
3445 dld_ioc_macprop_t *dip;
3446
3447 *status = DLADM_STATUS_OK;
3448 dsize = MAC_PROP_BUFSIZE(valsize);
3449 dip = malloc(dsize);
3450 if (dip == NULL) {
3451 *status = DLADM_STATUS_NOMEM;
3452 return (NULL);
3453 }
3454 bzero(dip, dsize);
3455 dip->pr_valsize = valsize;
3456 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
3457 dip->pr_linkid = linkid;
3458 dip->pr_num = propid;
3459 dip->pr_flags = flags;
3460 return (dip);
3461 }
3462
3463 static dld_ioc_macprop_t *
i_dladm_buf_alloc_by_name(size_t valsize,datalink_id_t linkid,const char * prop_name,uint_t flags,dladm_status_t * status)3464 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
3465 const char *prop_name, uint_t flags, dladm_status_t *status)
3466 {
3467 link_attr_t *p;
3468
3469 p = dladm_name2prop(prop_name);
3470 valsize = MAX(p->pp_valsize, valsize);
3471 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
3472 flags, status));
3473 }
3474
3475 static dld_ioc_macprop_t *
i_dladm_buf_alloc_by_id(size_t valsize,datalink_id_t linkid,mac_prop_id_t propid,uint_t flags,dladm_status_t * status)3476 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
3477 mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
3478 {
3479 link_attr_t *p;
3480
3481 p = dladm_id2prop(propid);
3482 valsize = MAX(p->pp_valsize, valsize);
3483 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
3484 flags, status));
3485 }
3486
3487 /* ARGSUSED */
3488 static dladm_status_t
set_public_prop(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)3489 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
3490 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3491 datalink_media_t media)
3492 {
3493 dld_ioc_macprop_t *dip;
3494 dladm_status_t status = DLADM_STATUS_OK;
3495 uint8_t u8;
3496 uint16_t u16;
3497 uint32_t u32;
3498 void *val;
3499
3500 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
3501 if (dip == NULL)
3502 return (status);
3503
3504 if (pdp->pd_flags & PD_CHECK_ALLOC)
3505 val = (void *)vdp->vd_val;
3506 else {
3507 /*
3508 * Currently all 1/2/4-byte size properties are byte/word/int.
3509 * No need (yet) to distinguish these from arrays of same size.
3510 */
3511 switch (dip->pr_valsize) {
3512 case 1:
3513 u8 = vdp->vd_val;
3514 val = &u8;
3515 break;
3516 case 2:
3517 u16 = vdp->vd_val;
3518 val = &u16;
3519 break;
3520 case 4:
3521 u32 = vdp->vd_val;
3522 val = &u32;
3523 break;
3524 default:
3525 val = &vdp->vd_val;
3526 break;
3527 }
3528 }
3529
3530 if (val != NULL)
3531 (void) memcpy(dip->pr_val, val, dip->pr_valsize);
3532 else
3533 dip->pr_valsize = 0;
3534
3535 status = i_dladm_macprop(handle, dip, B_TRUE);
3536
3537 done:
3538 free(dip);
3539 return (status);
3540 }
3541
3542 dladm_status_t
i_dladm_macprop(dladm_handle_t handle,void * dip,boolean_t set)3543 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
3544 {
3545 dladm_status_t status = DLADM_STATUS_OK;
3546
3547 if (ioctl(dladm_dld_fd(handle),
3548 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
3549 status = dladm_errno2status(errno);
3550
3551 return (status);
3552 }
3553
3554 static dladm_status_t
i_dladm_get_public_prop(dladm_handle_t handle,datalink_id_t linkid,char * prop_name,uint_t flags,uint_t * perm_flags,void * arg,size_t size)3555 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
3556 char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size)
3557 {
3558 dld_ioc_macprop_t *dip;
3559 dladm_status_t status;
3560
3561 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status);
3562 if (dip == NULL)
3563 return (DLADM_STATUS_NOMEM);
3564
3565 status = i_dladm_macprop(handle, dip, B_FALSE);
3566 if (status != DLADM_STATUS_OK) {
3567 free(dip);
3568 return (status);
3569 }
3570
3571 if (perm_flags != NULL)
3572 *perm_flags = dip->pr_perm_flags;
3573
3574 if (arg != NULL)
3575 (void) memcpy(arg, dip->pr_val, size);
3576 free(dip);
3577 return (DLADM_STATUS_OK);
3578 }
3579
3580 /* ARGSUSED */
3581 static dladm_status_t
check_uint32(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vp,datalink_media_t media)3582 check_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3583 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3584 val_desc_t **vp, datalink_media_t media)
3585 {
3586 uint_t val_cnt = *val_cntp;
3587 val_desc_t *v = *vp;
3588
3589 if (val_cnt != 1)
3590 return (DLADM_STATUS_BADVAL);
3591 v->vd_val = strtoul(prop_val[0], NULL, 0);
3592 return (DLADM_STATUS_OK);
3593 }
3594
3595 /* ARGSUSED */
3596 static dladm_status_t
get_duplex(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3597 get_duplex(dladm_handle_t handle, prop_desc_t *pdp,
3598 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3599 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3600 {
3601 link_duplex_t link_duplex;
3602 dladm_status_t status;
3603
3604 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
3605 KSTAT_DATA_UINT32, &link_duplex)) != 0)
3606 return (status);
3607
3608 switch (link_duplex) {
3609 case LINK_DUPLEX_FULL:
3610 (void) strcpy(*prop_val, "full");
3611 break;
3612 case LINK_DUPLEX_HALF:
3613 (void) strcpy(*prop_val, "half");
3614 break;
3615 default:
3616 (void) strcpy(*prop_val, "unknown");
3617 break;
3618 }
3619 *val_cnt = 1;
3620 return (DLADM_STATUS_OK);
3621 }
3622
3623 /* ARGSUSED */
3624 static dladm_status_t
get_speed(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3625 get_speed(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3626 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
3627 uint_t *perm_flags)
3628 {
3629 uint64_t ifspeed = 0;
3630 dladm_status_t status;
3631
3632 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
3633 KSTAT_DATA_UINT64, &ifspeed)) != 0)
3634 return (status);
3635
3636 if ((ifspeed % 1000000) != 0) {
3637 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3638 "%llf", ifspeed / (float)1000000); /* Mbps */
3639 } else {
3640 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3641 "%llu", ifspeed / 1000000); /* Mbps */
3642 }
3643 *val_cnt = 1;
3644 *perm_flags = MAC_PROP_PERM_READ;
3645 return (DLADM_STATUS_OK);
3646 }
3647
3648 /* ARGSUSED */
3649 static dladm_status_t
get_link_state(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3650 get_link_state(dladm_handle_t handle, prop_desc_t *pdp,
3651 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3652 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3653 {
3654 link_state_t link_state;
3655 dladm_status_t status;
3656
3657 status = dladm_get_state(handle, linkid, &link_state);
3658 if (status != DLADM_STATUS_OK)
3659 return (status);
3660
3661 switch (link_state) {
3662 case LINK_STATE_UP:
3663 (void) strcpy(*prop_val, "up");
3664 break;
3665 case LINK_STATE_DOWN:
3666 (void) strcpy(*prop_val, "down");
3667 break;
3668 default:
3669 (void) strcpy(*prop_val, "unknown");
3670 break;
3671 }
3672 *val_cnt = 1;
3673 *perm_flags = MAC_PROP_PERM_READ;
3674 return (DLADM_STATUS_OK);
3675 }
3676
3677 /* ARGSUSED */
3678 static dladm_status_t
get_binary(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3679 get_binary(dladm_handle_t handle, prop_desc_t *pdp,
3680 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3681 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3682 {
3683 dladm_status_t status;
3684 uint_t v = 0;
3685
3686 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3687 perm_flags, &v, sizeof (v));
3688 if (status != DLADM_STATUS_OK)
3689 return (status);
3690
3691 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0));
3692 *val_cnt = 1;
3693 return (DLADM_STATUS_OK);
3694 }
3695
3696 /* ARGSUSED */
3697 static dladm_status_t
get_uint32(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3698 get_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3699 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3700 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3701 {
3702 dladm_status_t status;
3703 uint32_t v = 0;
3704
3705 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3706 perm_flags, &v, sizeof (v));
3707 if (status != DLADM_STATUS_OK)
3708 return (status);
3709
3710 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
3711 *val_cnt = 1;
3712 return (DLADM_STATUS_OK);
3713 }
3714
3715 /* ARGSUSED */
3716 static dladm_status_t
get_range(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3717 get_range(dladm_handle_t handle, prop_desc_t *pdp,
3718 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3719 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3720 {
3721 dld_ioc_macprop_t *dip;
3722 dladm_status_t status = DLADM_STATUS_OK;
3723 size_t sz;
3724 uint_t rcount;
3725 mac_propval_range_t *rangep;
3726
3727 /*
3728 * As caller we don't know number of value ranges, the driver
3729 * supports. To begin with we assume that number to be 1. If the
3730 * buffer size is insufficient, driver returns back with the
3731 * actual count of value ranges. See mac.h for more details.
3732 */
3733 sz = sizeof (mac_propval_range_t);
3734 rcount = 1;
3735 retry:
3736 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
3737 &status)) == NULL)
3738 return (status);
3739
3740 rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
3741 rangep->mpr_count = rcount;
3742
3743 status = i_dladm_macprop(handle, dip, B_FALSE);
3744 if (status != DLADM_STATUS_OK) {
3745 if (status == DLADM_STATUS_TOOSMALL) {
3746 int err;
3747
3748 if ((err = i_dladm_range_size(rangep, &sz, &rcount))
3749 == 0) {
3750 free(dip);
3751 goto retry;
3752 } else {
3753 status = dladm_errno2status(err);
3754 }
3755 }
3756 free(dip);
3757 return (status);
3758 }
3759
3760 if (rangep->mpr_count == 0) {
3761 *val_cnt = 1;
3762 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--");
3763 goto done;
3764 }
3765
3766 switch (rangep->mpr_type) {
3767 case MAC_PROPVAL_UINT32: {
3768 mac_propval_uint32_range_t *ur;
3769 uint_t count = rangep->mpr_count, i;
3770
3771 ur = &rangep->mpr_range_uint32[0];
3772
3773 for (i = 0; i < count; i++, ur++) {
3774 if (ur->mpur_min == ur->mpur_max) {
3775 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
3776 "%ld", ur->mpur_min);
3777 } else {
3778 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
3779 "%ld-%ld", ur->mpur_min, ur->mpur_max);
3780 }
3781 }
3782 *val_cnt = count;
3783 break;
3784 }
3785 default:
3786 status = DLADM_STATUS_BADARG;
3787 break;
3788 }
3789 done:
3790 free(dip);
3791 return (status);
3792 }
3793
3794 /* ARGSUSED */
3795 static dladm_status_t
get_tagmode(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3796 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp,
3797 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3798 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3799 {
3800 link_tagmode_t mode;
3801 dladm_status_t status;
3802
3803 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3804 perm_flags, &mode, sizeof (mode));
3805 if (status != DLADM_STATUS_OK)
3806 return (status);
3807
3808 switch (mode) {
3809 case LINK_TAGMODE_NORMAL:
3810 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX);
3811 break;
3812 case LINK_TAGMODE_VLANONLY:
3813 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX);
3814 break;
3815 default:
3816 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX);
3817 }
3818 *val_cnt = 1;
3819 return (DLADM_STATUS_OK);
3820 }
3821
3822 /* ARGSUSED */
3823 static dladm_status_t
get_flowctl(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)3824 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp,
3825 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3826 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3827 {
3828 link_flowctrl_t v;
3829 dladm_status_t status;
3830
3831 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3832 perm_flags, &v, sizeof (v));
3833 if (status != DLADM_STATUS_OK)
3834 return (status);
3835
3836 switch (v) {
3837 case LINK_FLOWCTRL_NONE:
3838 (void) sprintf(*prop_val, "no");
3839 break;
3840 case LINK_FLOWCTRL_RX:
3841 (void) sprintf(*prop_val, "rx");
3842 break;
3843 case LINK_FLOWCTRL_TX:
3844 (void) sprintf(*prop_val, "tx");
3845 break;
3846 case LINK_FLOWCTRL_BI:
3847 (void) sprintf(*prop_val, "bi");
3848 break;
3849 }
3850 *val_cnt = 1;
3851 return (DLADM_STATUS_OK);
3852 }
3853
3854
3855 /* ARGSUSED */
3856 static dladm_status_t
i_dladm_set_private_prop(dladm_handle_t handle,datalink_id_t linkid,const char * prop_name,char ** prop_val,uint_t val_cnt,uint_t flags)3857 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid,
3858 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
3859
3860 {
3861 int i, slen;
3862 int bufsize = 0;
3863 dld_ioc_macprop_t *dip = NULL;
3864 uchar_t *dp;
3865 link_attr_t *p;
3866 dladm_status_t status = DLADM_STATUS_OK;
3867
3868 if ((prop_name == NULL && prop_val != NULL) ||
3869 (prop_val != NULL && val_cnt == 0))
3870 return (DLADM_STATUS_BADARG);
3871 p = dladm_name2prop(prop_name);
3872 if (p->pp_id != MAC_PROP_PRIVATE)
3873 return (DLADM_STATUS_BADARG);
3874
3875 if (!(flags & DLADM_OPT_ACTIVE))
3876 return (DLADM_STATUS_OK);
3877
3878 /*
3879 * private properties: all parsing is done in the kernel.
3880 * allocate a enough space for each property + its separator (',').
3881 */
3882 for (i = 0; i < val_cnt; i++) {
3883 bufsize += strlen(prop_val[i]) + 1;
3884 }
3885
3886 if (prop_val == NULL) {
3887 /*
3888 * getting default value. so use more buffer space.
3889 */
3890 bufsize += DLADM_PROP_BUF_CHUNK;
3891 }
3892
3893 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
3894 (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status);
3895 if (dip == NULL)
3896 return (status);
3897
3898 dp = (uchar_t *)dip->pr_val;
3899 slen = 0;
3900
3901 if (prop_val == NULL) {
3902 status = i_dladm_macprop(handle, dip, B_FALSE);
3903 dip->pr_flags = 0;
3904 } else {
3905 for (i = 0; i < val_cnt; i++) {
3906 int plen = 0;
3907
3908 plen = strlen(prop_val[i]);
3909 bcopy(prop_val[i], dp, plen);
3910 slen += plen;
3911 /*
3912 * add a "," separator and update dp.
3913 */
3914 if (i != (val_cnt -1))
3915 dp[slen++] = ',';
3916 dp += (plen + 1);
3917 }
3918 }
3919 if (status == DLADM_STATUS_OK)
3920 status = i_dladm_macprop(handle, dip, B_TRUE);
3921
3922 free(dip);
3923 return (status);
3924 }
3925
3926 static dladm_status_t
i_dladm_get_priv_prop(dladm_handle_t handle,datalink_id_t linkid,const char * prop_name,char ** prop_val,uint_t * val_cnt,dladm_prop_type_t type,uint_t dld_flags)3927 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
3928 const char *prop_name, char **prop_val, uint_t *val_cnt,
3929 dladm_prop_type_t type, uint_t dld_flags)
3930 {
3931 dladm_status_t status = DLADM_STATUS_OK;
3932 dld_ioc_macprop_t *dip = NULL;
3933 link_attr_t *p;
3934
3935 if ((prop_name == NULL && prop_val != NULL) ||
3936 (prop_val != NULL && val_cnt == 0))
3937 return (DLADM_STATUS_BADARG);
3938
3939 p = dladm_name2prop(prop_name);
3940 if (p->pp_id != MAC_PROP_PRIVATE)
3941 return (DLADM_STATUS_BADARG);
3942
3943 /*
3944 * private properties: all parsing is done in the kernel.
3945 */
3946 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
3947 dld_flags, &status);
3948 if (dip == NULL)
3949 return (status);
3950
3951 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
3952 DLADM_STATUS_OK) {
3953 if (type == DLADM_PROP_VAL_PERM) {
3954 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
3955 } else if (type == DLADM_PROP_VAL_MODIFIABLE) {
3956 *prop_val[0] = '\0';
3957 } else {
3958 (void) strncpy(*prop_val, dip->pr_val,
3959 DLADM_PROP_VAL_MAX);
3960 }
3961 *val_cnt = 1;
3962 } else if ((status == DLADM_STATUS_NOTSUP) &&
3963 (type == DLADM_PROP_VAL_CURRENT)) {
3964 status = DLADM_STATUS_NOTFOUND;
3965 }
3966 free(dip);
3967 return (status);
3968 }
3969
3970
3971 static dladm_status_t
i_dladm_getset_defval(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,datalink_media_t media,uint_t flags)3972 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
3973 datalink_id_t linkid, datalink_media_t media, uint_t flags)
3974 {
3975 dladm_status_t status;
3976 char **prop_vals = NULL, *buf;
3977 size_t bufsize;
3978 uint_t cnt;
3979 int i;
3980 uint_t perm_flags;
3981
3982 /*
3983 * Allocate buffer needed for prop_vals array. We can have at most
3984 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
3985 * each entry has max size DLADM_PROP_VAL_MAX
3986 */
3987 bufsize =
3988 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
3989 buf = malloc(bufsize);
3990 prop_vals = (char **)(void *)buf;
3991 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
3992 prop_vals[i] = buf +
3993 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
3994 i * DLADM_PROP_VAL_MAX;
3995 }
3996
3997 /*
3998 * For properties which have pdp->pd_defval.vd_name as a non-empty
3999 * string, the "" itself is used to reset the property (exceptions
4000 * are zone and autopush, which populate vdp->vd_val). So
4001 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
4002 * down on the setprop using the global values in the table. For
4003 * other cases (vd_name is ""), doing reset-linkprop will cause
4004 * libdladm to do a getprop to find the default value and then do
4005 * a setprop to reset the value to default.
4006 */
4007 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
4008 DLD_PROP_DEFAULT, &perm_flags);
4009 if (status == DLADM_STATUS_OK) {
4010 if (perm_flags == MAC_PROP_PERM_RW) {
4011 status = i_dladm_set_single_prop(handle, linkid,
4012 pdp->pd_class, media, pdp, prop_vals, cnt, flags);
4013 }
4014 else
4015 status = DLADM_STATUS_NOTSUP;
4016 }
4017 free(buf);
4018 return (status);
4019 }
4020
4021 /* ARGSUSED */
4022 static dladm_status_t
get_stp(dladm_handle_t handle,struct prop_desc * pd,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)4023 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid,
4024 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
4025 uint_t *perm_flags)
4026 {
4027 const bridge_public_prop_t *bpp;
4028 dladm_status_t retv;
4029 int val, i;
4030
4031 if (flags != 0)
4032 return (DLADM_STATUS_NOTSUP);
4033 *perm_flags = MAC_PROP_PERM_RW;
4034 *val_cnt = 1;
4035 for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++)
4036 if (strcmp(bpp->bpp_name, pd->pd_name) == 0)
4037 break;
4038 retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val);
4039 /* If the daemon isn't running, then return the persistent value */
4040 if (retv == DLADM_STATUS_NOTFOUND) {
4041 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4042 prop_val, val_cnt) != DLADM_STATUS_OK)
4043 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4044 DLADM_PROP_VAL_MAX);
4045 return (DLADM_STATUS_OK);
4046 }
4047 if (retv != DLADM_STATUS_OK) {
4048 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4049 return (retv);
4050 }
4051 if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') {
4052 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4053 DLADM_PROP_VAL_MAX);
4054 return (DLADM_STATUS_OK);
4055 }
4056 for (i = 0; i < pd->pd_noptval; i++) {
4057 if (val == pd->pd_optval[i].vd_val) {
4058 (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name,
4059 DLADM_PROP_VAL_MAX);
4060 return (DLADM_STATUS_OK);
4061 }
4062 }
4063 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val);
4064 return (DLADM_STATUS_OK);
4065 }
4066
4067 /* ARGSUSED1 */
4068 static dladm_status_t
set_stp_prop(dladm_handle_t handle,prop_desc_t * pd,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)4069 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4070 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4071 {
4072 /*
4073 * Special case for mcheck: the daemon resets the value to zero, and we
4074 * don't want the daemon to refresh itself; it leads to deadlock.
4075 */
4076 if (flags & DLADM_OPT_NOREFRESH)
4077 return (DLADM_STATUS_OK);
4078
4079 /* Tell the running daemon, if any */
4080 return (dladm_bridge_refresh(handle, linkid));
4081 }
4082
4083 /*
4084 * This is used only for stp_priority, stp_cost, and stp_mcheck.
4085 */
4086 /* ARGSUSED */
4087 static dladm_status_t
check_stp_prop(dladm_handle_t handle,struct prop_desc * pd,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)4088 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd,
4089 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4090 val_desc_t **vdpp, datalink_media_t media)
4091 {
4092 char *cp;
4093 boolean_t iscost;
4094 uint_t val_cnt = *val_cntp;
4095 val_desc_t *vdp = *vdpp;
4096
4097 if (val_cnt != 1)
4098 return (DLADM_STATUS_BADVALCNT);
4099
4100 if (prop_val == NULL) {
4101 vdp->vd_val = 0;
4102 } else {
4103 /* Only stp_priority and stp_cost use this function */
4104 iscost = strcmp(pd->pd_name, "stp_cost") == 0;
4105
4106 if (iscost && strcmp(prop_val[0], "auto") == 0) {
4107 /* Illegal value 0 is allowed to mean "automatic" */
4108 vdp->vd_val = 0;
4109 } else {
4110 errno = 0;
4111 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4112 if (errno != 0 || *cp != '\0')
4113 return (DLADM_STATUS_BADVAL);
4114 }
4115 }
4116
4117 if (iscost) {
4118 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL :
4119 DLADM_STATUS_OK);
4120 } else {
4121 if (vdp->vd_val > 255)
4122 return (DLADM_STATUS_BADVAL);
4123 /*
4124 * If the user is setting stp_mcheck non-zero, then (per the
4125 * IEEE management standards and UNH testing) we need to check
4126 * whether this link is part of a bridge that is running RSTP.
4127 * If it's not, then setting the flag is an error. Note that
4128 * errors are intentionally discarded here; it's the value
4129 * that's the problem -- it's not a bad value, merely one that
4130 * can't be used now.
4131 */
4132 if (strcmp(pd->pd_name, "stp_mcheck") == 0 &&
4133 vdp->vd_val != 0) {
4134 char bridge[MAXLINKNAMELEN];
4135 UID_STP_CFG_T cfg;
4136 dladm_bridge_prot_t brprot;
4137
4138 if (dladm_bridge_getlink(handle, linkid, bridge,
4139 sizeof (bridge)) != DLADM_STATUS_OK ||
4140 dladm_bridge_get_properties(bridge, &cfg,
4141 &brprot) != DLADM_STATUS_OK)
4142 return (DLADM_STATUS_FAILED);
4143 if (cfg.force_version <= 1)
4144 return (DLADM_STATUS_FAILED);
4145 }
4146 return (DLADM_STATUS_OK);
4147 }
4148 }
4149
4150 /* ARGSUSED */
4151 static dladm_status_t
get_bridge_forward(dladm_handle_t handle,struct prop_desc * pd,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)4152 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd,
4153 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4154 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4155 {
4156 dladm_status_t retv;
4157 uint_t val;
4158
4159 if (flags != 0)
4160 return (DLADM_STATUS_NOTSUP);
4161 *perm_flags = MAC_PROP_PERM_RW;
4162 *val_cnt = 1;
4163 retv = dladm_bridge_get_forwarding(handle, linkid, &val);
4164 if (retv == DLADM_STATUS_NOTFOUND) {
4165 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4166 prop_val, val_cnt) != DLADM_STATUS_OK)
4167 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4168 DLADM_PROP_VAL_MAX);
4169 return (DLADM_STATUS_OK);
4170 }
4171 if (retv == DLADM_STATUS_OK)
4172 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val);
4173 else
4174 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4175 return (retv);
4176 }
4177
4178 /* ARGSUSED */
4179 static dladm_status_t
set_bridge_forward(dladm_handle_t handle,prop_desc_t * pd,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)4180 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4181 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4182 {
4183 /* Tell the running daemon, if any */
4184 return (dladm_bridge_refresh(handle, linkid));
4185 }
4186
4187 /* ARGSUSED */
4188 static dladm_status_t
get_bridge_pvid(dladm_handle_t handle,struct prop_desc * pd,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)4189 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4190 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4191 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4192 {
4193 dladm_status_t status;
4194 dld_ioc_macprop_t *dip;
4195 uint16_t pvid;
4196
4197 if (flags != 0)
4198 return (DLADM_STATUS_NOTSUP);
4199 *perm_flags = MAC_PROP_PERM_RW;
4200 *val_cnt = 1;
4201 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4202 0, &status);
4203 if (dip == NULL)
4204 return (status);
4205 status = i_dladm_macprop(handle, dip, B_FALSE);
4206 if (status == DLADM_STATUS_OK) {
4207 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid));
4208 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid);
4209 } else {
4210 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4211 }
4212 free(dip);
4213 return (status);
4214 }
4215
4216 /* ARGSUSED */
4217 static dladm_status_t
set_bridge_pvid(dladm_handle_t handle,prop_desc_t * pd,datalink_id_t linkid,val_desc_t * vdp,uint_t val_cnt,uint_t flags,datalink_media_t media)4218 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4219 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4220 {
4221 dladm_status_t status;
4222 dld_ioc_macprop_t *dip;
4223 uint16_t pvid;
4224
4225 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4226 0, &status);
4227 if (dip == NULL)
4228 return (status);
4229 pvid = vdp->vd_val;
4230 (void) memcpy(dip->pr_val, &pvid, sizeof (pvid));
4231 status = i_dladm_macprop(handle, dip, B_TRUE);
4232 free(dip);
4233 if (status != DLADM_STATUS_OK)
4234 return (status);
4235
4236 /* Tell the running daemon, if any */
4237 return (dladm_bridge_refresh(handle, linkid));
4238 }
4239
4240 /* ARGSUSED */
4241 static dladm_status_t
check_bridge_pvid(dladm_handle_t handle,struct prop_desc * pd,datalink_id_t linkid,char ** prop_val,uint_t * val_cntp,uint_t flags,val_desc_t ** vdpp,datalink_media_t media)4242 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4243 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4244 val_desc_t **vdpp, datalink_media_t media)
4245 {
4246 char *cp;
4247 uint_t val_cnt = *val_cntp;
4248 val_desc_t *vdp = *vdpp;
4249
4250 if (val_cnt != 1)
4251 return (DLADM_STATUS_BADVALCNT);
4252
4253 if (prop_val == NULL) {
4254 vdp->vd_val = 1;
4255 } else {
4256 errno = 0;
4257 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4258 if (errno != 0 || *cp != '\0')
4259 return (DLADM_STATUS_BADVAL);
4260 }
4261
4262 return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL :
4263 DLADM_STATUS_OK);
4264 }
4265
4266 dladm_status_t
i_dladm_wlan_param(dladm_handle_t handle,datalink_id_t linkid,void * buf,mac_prop_id_t cmd,size_t len,boolean_t set)4267 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
4268 mac_prop_id_t cmd, size_t len, boolean_t set)
4269 {
4270 uint32_t flags;
4271 dladm_status_t status;
4272 uint32_t media;
4273 dld_ioc_macprop_t *dip;
4274 void *dp;
4275
4276 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
4277 &media, NULL, 0)) != DLADM_STATUS_OK) {
4278 return (status);
4279 }
4280
4281 if (media != DL_WIFI)
4282 return (DLADM_STATUS_BADARG);
4283
4284 if (!(flags & DLADM_OPT_ACTIVE))
4285 return (DLADM_STATUS_TEMPONLY);
4286
4287 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
4288 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
4289
4290 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
4291 if (dip == NULL)
4292 return (DLADM_STATUS_NOMEM);
4293
4294 dp = (uchar_t *)dip->pr_val;
4295 if (set)
4296 (void) memcpy(dp, buf, len);
4297
4298 status = i_dladm_macprop(handle, dip, set);
4299 if (status == DLADM_STATUS_OK) {
4300 if (!set)
4301 (void) memcpy(buf, dp, len);
4302 }
4303
4304 free(dip);
4305 return (status);
4306 }
4307
4308 dladm_status_t
dladm_parse_link_props(char * str,dladm_arg_list_t ** listp,boolean_t novalues)4309 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
4310 {
4311 return (dladm_parse_args(str, listp, novalues));
4312 }
4313
4314 /*
4315 * Retrieve the one link property from the database
4316 */
4317 /*ARGSUSED*/
4318 static int
i_dladm_get_one_prop(dladm_handle_t handle,datalink_id_t linkid,const char * prop_name,void * arg)4319 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
4320 const char *prop_name, void *arg)
4321 {
4322 dladm_arg_list_t *proplist = arg;
4323 dladm_arg_info_t *aip = NULL;
4324
4325 aip = &proplist->al_info[proplist->al_count];
4326 /*
4327 * it is fine to point to prop_name since prop_name points to the
4328 * prop_table[n].pd_name.
4329 */
4330 aip->ai_name = prop_name;
4331
4332 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
4333 prop_name, aip->ai_val, &aip->ai_count);
4334
4335 if (aip->ai_count != 0)
4336 proplist->al_count++;
4337
4338 return (DLADM_WALK_CONTINUE);
4339 }
4340
4341
4342 /*
4343 * Retrieve all link properties for a link from the database and
4344 * return a property list.
4345 */
4346 dladm_status_t
dladm_link_get_proplist(dladm_handle_t handle,datalink_id_t linkid,dladm_arg_list_t ** listp)4347 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
4348 dladm_arg_list_t **listp)
4349 {
4350 dladm_arg_list_t *list;
4351 dladm_status_t status = DLADM_STATUS_OK;
4352
4353 list = calloc(1, sizeof (dladm_arg_list_t));
4354 if (list == NULL)
4355 return (dladm_errno2status(errno));
4356
4357 status = dladm_walk_linkprop(handle, linkid, list,
4358 i_dladm_get_one_prop);
4359
4360 *listp = list;
4361 return (status);
4362 }
4363
4364 /*
4365 * Retrieve the named property from a proplist, check the value and
4366 * convert to a kernel structure.
4367 */
4368 static dladm_status_t
i_dladm_link_proplist_extract_one(dladm_handle_t handle,dladm_arg_list_t * proplist,const char * name,uint_t flags,void * arg)4369 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
4370 dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg)
4371 {
4372 dladm_status_t status;
4373 dladm_arg_info_t *aip = NULL;
4374 int i, j;
4375
4376 /* Find named property in proplist */
4377 for (i = 0; i < proplist->al_count; i++) {
4378 aip = &proplist->al_info[i];
4379 if (strcasecmp(aip->ai_name, name) == 0)
4380 break;
4381 }
4382
4383 /* Property not in list */
4384 if (i == proplist->al_count)
4385 return (DLADM_STATUS_OK);
4386
4387 for (i = 0; i < DLADM_MAX_PROPS; i++) {
4388 prop_desc_t *pdp = &prop_table[i];
4389 val_desc_t *vdp;
4390
4391 vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
4392 if (vdp == NULL)
4393 return (DLADM_STATUS_NOMEM);
4394
4395 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
4396 continue;
4397
4398 if (aip->ai_val == NULL)
4399 return (DLADM_STATUS_BADARG);
4400
4401 /* Check property value */
4402 if (pdp->pd_check != NULL) {
4403 status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
4404 &(aip->ai_count), flags, &vdp, 0);
4405 } else {
4406 status = DLADM_STATUS_BADARG;
4407 }
4408
4409 if (status != DLADM_STATUS_OK)
4410 return (status);
4411
4412 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
4413 resource_prop_t *rpp = &rsrc_prop_table[j];
4414
4415 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
4416 continue;
4417
4418 /* Extract kernel structure */
4419 if (rpp->rp_extract != NULL) {
4420 status = rpp->rp_extract(vdp,
4421 aip->ai_count, arg);
4422 } else {
4423 status = DLADM_STATUS_BADARG;
4424 }
4425 break;
4426 }
4427
4428 if (status != DLADM_STATUS_OK)
4429 return (status);
4430
4431 break;
4432 }
4433 return (status);
4434 }
4435
4436 /*
4437 * Extract properties from a proplist and convert to mac_resource_props_t.
4438 */
4439 dladm_status_t
dladm_link_proplist_extract(dladm_handle_t handle,dladm_arg_list_t * proplist,mac_resource_props_t * mrp,uint_t flags)4440 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
4441 mac_resource_props_t *mrp, uint_t flags)
4442 {
4443 dladm_status_t status;
4444 int i;
4445
4446 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
4447 status = i_dladm_link_proplist_extract_one(handle,
4448 proplist, rsrc_prop_table[i].rp_name, flags, mrp);
4449 if (status != DLADM_STATUS_OK)
4450 return (status);
4451 }
4452 return (status);
4453 }
4454
4455 static const char *
dladm_perm2str(uint_t perm,char * buf)4456 dladm_perm2str(uint_t perm, char *buf)
4457 {
4458 (void) snprintf(buf, DLADM_STRSIZE, "%c%c",
4459 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
4460 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
4461 return (buf);
4462 }
4463
4464 dladm_status_t
dladm_get_state(dladm_handle_t handle,datalink_id_t linkid,link_state_t * state)4465 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
4466 link_state_t *state)
4467 {
4468 uint_t perms;
4469
4470 return (i_dladm_get_public_prop(handle, linkid, "state", 0,
4471 &perms, state, sizeof (*state)));
4472 }
4473
4474 boolean_t
dladm_attr_is_linkprop(const char * name)4475 dladm_attr_is_linkprop(const char *name)
4476 {
4477 /* non-property attribute names */
4478 const char *nonprop[] = {
4479 /* dlmgmtd core attributes */
4480 "name",
4481 "class",
4482 "media",
4483 FPHYMAJ,
4484 FPHYINST,
4485 FDEVNAME,
4486
4487 /* other attributes for vlan, aggr, etc */
4488 DLADM_ATTR_NAMES
4489 };
4490 boolean_t is_nonprop = B_FALSE;
4491 int i;
4492
4493 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
4494 if (strcmp(name, nonprop[i]) == 0) {
4495 is_nonprop = B_TRUE;
4496 break;
4497 }
4498 }
4499
4500 return (!is_nonprop);
4501 }
4502
4503 dladm_status_t
dladm_linkprop_is_set(dladm_handle_t handle,datalink_id_t linkid,dladm_prop_type_t type,const char * prop_name,boolean_t * is_set)4504 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid,
4505 dladm_prop_type_t type, const char *prop_name, boolean_t *is_set)
4506 {
4507 char *buf, **propvals;
4508 uint_t valcnt = DLADM_MAX_PROP_VALCNT;
4509 int i;
4510 dladm_status_t status = DLADM_STATUS_OK;
4511 size_t bufsize;
4512
4513 *is_set = B_FALSE;
4514
4515 bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) *
4516 DLADM_MAX_PROP_VALCNT;
4517 if ((buf = calloc(1, bufsize)) == NULL)
4518 return (DLADM_STATUS_NOMEM);
4519
4520 propvals = (char **)(void *)buf;
4521 for (i = 0; i < valcnt; i++) {
4522 propvals[i] = buf +
4523 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4524 i * DLADM_PROP_VAL_MAX;
4525 }
4526
4527 if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals,
4528 &valcnt) != DLADM_STATUS_OK) {
4529 goto done;
4530 }
4531
4532 /*
4533 * valcnt is always set to 1 by get_pool(), hence we need to check
4534 * for a non-null string to see if it is set. For protection and
4535 * allowed-ips, we can check either the *propval or the valcnt.
4536 */
4537 if ((strcmp(prop_name, "pool") == 0 ||
4538 strcmp(prop_name, "protection") == 0 ||
4539 strcmp(prop_name, "allowed-ips") == 0) &&
4540 (strlen(*propvals) != 0)) {
4541 *is_set = B_TRUE;
4542 } else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) {
4543 *is_set = B_TRUE;
4544 } else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) &&
4545 (strcmp(propvals[0], "true") == 0)) {
4546 *is_set = B_TRUE;
4547 }
4548
4549 done:
4550 if (buf != NULL)
4551 free(buf);
4552 return (status);
4553 }
4554
4555 /* ARGSUSED */
4556 static dladm_status_t
get_linkmode_prop(dladm_handle_t handle,prop_desc_t * pdp,datalink_id_t linkid,char ** prop_val,uint_t * val_cnt,datalink_media_t media,uint_t flags,uint_t * perm_flags)4557 get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp,
4558 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4559 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4560 {
4561 char *s;
4562 uint32_t v;
4563 dladm_status_t status;
4564
4565 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4566 perm_flags, &v, sizeof (v));
4567 if (status != DLADM_STATUS_OK)
4568 return (status);
4569
4570 switch (v) {
4571 case DLADM_PART_CM_MODE:
4572 s = "cm";
4573 break;
4574 case DLADM_PART_UD_MODE:
4575 s = "ud";
4576 break;
4577 default:
4578 s = "";
4579 break;
4580 }
4581 (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s);
4582
4583 *val_cnt = 1;
4584 return (DLADM_STATUS_OK);
4585 }
4586