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