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