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