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