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