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