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