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 (flags & DLADM_OPT_TRANSIENT)
1533 dzp->diz_transient = B_TRUE;
1534
1535 if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt,
1536 flags, media)) != DLADM_STATUS_OK)
1537 return (status);
1538
1539 /*
1540 * It is okay to fail to update the /dev entry (some vanity-named
1541 * links do not have a /dev entry).
1542 */
1543 if (zid_old != GLOBAL_ZONEID) {
1544 (void) i_dladm_update_deventry(handle, zid_old, linkid,
1545 B_FALSE);
1546 }
1547 if (zid_new != GLOBAL_ZONEID)
1548 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1549
1550 return (DLADM_STATUS_OK);
1551 }
1552
1553 /* ARGSUSED */
1554 static dladm_status_t
1555 check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1556 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1557 datalink_media_t media)
1558 {
1559 char *zone_name;
1560 zoneid_t zoneid;
1561 dladm_status_t status = DLADM_STATUS_OK;
1562 dld_ioc_zid_t *dzp;
1563 uint_t val_cnt = *val_cntp;
1564 val_desc_t *vdp = *vdpp;
1565
1566 if (val_cnt != 1)
1567 return (DLADM_STATUS_BADVALCNT);
1568
1569 dzp = malloc(sizeof (dld_ioc_zid_t));
1570 if (dzp == NULL)
1571 return (DLADM_STATUS_NOMEM);
1572
1573 zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1574 if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1575 status = DLADM_STATUS_BADVAL;
1576 goto done;
1577 }
1578
1579 if (zoneid != GLOBAL_ZONEID) {
1580 ushort_t flags;
1581
1582 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1583 sizeof (flags)) < 0) {
1584 status = dladm_errno2status(errno);
1585 goto done;
1586 }
1587
1588 if (!(flags & ZF_NET_EXCL)) {
1589 status = DLADM_STATUS_BADVAL;
1590 goto done;
1591 }
1592 }
1593
1594 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1595
1596 dzp->diz_zid = zoneid;
1597 dzp->diz_linkid = linkid;
1598
1599 vdp->vd_val = (uintptr_t)dzp;
1600 return (DLADM_STATUS_OK);
1601 done:
1602 free(dzp);
1603 return (status);
1604 }
1605
1606 /* ARGSUSED */
1607 static dladm_status_t
1608 get_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1609 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1610 uint_t flags, uint_t *perm_flags)
1611 {
1612 mac_resource_props_t mrp;
1613 dladm_status_t status;
1614
1615 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1616 perm_flags, &mrp, sizeof (mrp));
1617 if (status != DLADM_STATUS_OK)
1618 return (status);
1619
1620 if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1621 *val_cnt = 0;
1622 return (DLADM_STATUS_OK);
1623 }
1624
1625 (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1626 *val_cnt = 1;
1627 return (DLADM_STATUS_OK);
1628 }
1629
1630 /* ARGSUSED */
1631 static dladm_status_t
1632 check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1633 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1634 datalink_media_t media)
1635 {
1636 uint64_t *maxbw;
1637 dladm_status_t status = DLADM_STATUS_OK;
1638 uint_t val_cnt = *val_cntp;
1639 val_desc_t *vdp = *vdpp;
1640
1641 if (val_cnt != 1)
1642 return (DLADM_STATUS_BADVALCNT);
1643
1644 maxbw = malloc(sizeof (uint64_t));
1645 if (maxbw == NULL)
1646 return (DLADM_STATUS_NOMEM);
1647
1648 status = dladm_str2bw(*prop_val, maxbw);
1649 if (status != DLADM_STATUS_OK) {
1650 free(maxbw);
1651 return (status);
1652 }
1653
1654 if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1655 free(maxbw);
1656 return (DLADM_STATUS_MINMAXBW);
1657 }
1658
1659 vdp->vd_val = (uintptr_t)maxbw;
1660 return (DLADM_STATUS_OK);
1661 }
1662
1663 /* ARGSUSED */
1664 dladm_status_t
1665 extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
1666 {
1667 mac_resource_props_t *mrp = arg;
1668
1669 if (vdp->vd_val == RESET_VAL) {
1670 mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
1671 } else {
1672 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1673 }
1674 mrp->mrp_mask |= MRP_MAXBW;
1675
1676 return (DLADM_STATUS_OK);
1677 }
1678
1679 /* ARGSUSED */
1680 static dladm_status_t
1681 get_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1682 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1683 uint_t flags, uint_t *perm_flags)
1684 {
1685 dladm_status_t status;
1686 mac_resource_props_t mrp;
1687 mac_propval_range_t *pv_range;
1688 int err;
1689
1690 if (strcmp(pdp->pd_name, "cpus-effective") == 0) {
1691 status = i_dladm_get_public_prop(handle, linkid,
1692 "resource-effective", flags, perm_flags, &mrp,
1693 sizeof (mrp));
1694 } else {
1695 status = i_dladm_get_public_prop(handle, linkid,
1696 "resource", flags, perm_flags, &mrp, sizeof (mrp));
1697 }
1698
1699 if (status != DLADM_STATUS_OK)
1700 return (status);
1701
1702 if (mrp.mrp_ncpus > *val_cnt)
1703 return (DLADM_STATUS_TOOSMALL);
1704
1705 if (mrp.mrp_ncpus == 0) {
1706 *val_cnt = 0;
1707 return (DLADM_STATUS_OK);
1708 }
1709
1710 /* Sort CPU list and convert it to a mac_propval_range */
1711 status = dladm_list2range(mrp.mrp_cpu, mrp.mrp_ncpus,
1712 MAC_PROPVAL_UINT32, &pv_range);
1713 if (status != DLADM_STATUS_OK)
1714 return (status);
1715
1716 /* Write CPU ranges and individual CPUs */
1717 err = dladm_range2strs(pv_range, prop_val);
1718 if (err != 0) {
1719 free(pv_range);
1720 return (dladm_errno2status(err));
1721 }
1722
1723 *val_cnt = pv_range->mpr_count;
1724 free(pv_range);
1725
1726 return (DLADM_STATUS_OK);
1727 }
1728
1729 /* ARGSUSED */
1730 static dladm_status_t
1731 check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1732 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1733 datalink_media_t media)
1734 {
1735 int i, j, rc;
1736 long nproc = sysconf(_SC_NPROCESSORS_CONF);
1737 mac_resource_props_t mrp;
1738 mac_propval_range_t *pv_range;
1739 uint_t perm_flags;
1740 uint32_t ncpus;
1741 uint32_t *cpus = mrp.mrp_cpu;
1742 val_desc_t *vdp = *vdpp;
1743 val_desc_t *newvdp;
1744 uint_t val_cnt = *val_cntp;
1745 dladm_status_t status = DLADM_STATUS_OK;
1746
1747 /* Get the current pool property */
1748 status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1749 &perm_flags, &mrp, sizeof (mrp));
1750
1751 if (status == DLADM_STATUS_OK) {
1752 /* Can't set cpus if a pool is set */
1753 if (strlen(mrp.mrp_pool) != 0)
1754 return (DLADM_STATUS_POOLCPU);
1755 }
1756
1757 /* Read ranges and convert to mac_propval_range */
1758 status = dladm_strs2range(prop_val, val_cnt, MAC_PROPVAL_UINT32,
1759 &pv_range);
1760 if (status != DLADM_STATUS_OK)
1761 goto done1;
1762
1763 /* Convert mac_propval_range to a single CPU list */
1764 ncpus = MRP_NCPUS;
1765 status = dladm_range2list(pv_range, cpus, &ncpus);
1766 if (status != DLADM_STATUS_OK)
1767 goto done1;
1768
1769 /*
1770 * If a range of CPUs was entered, update value count and reallocate
1771 * the array of val_desc_t's. The array allocated was sized for
1772 * indvidual elements, but needs to be reallocated to accomodate the
1773 * expanded list of CPUs.
1774 */
1775 if (val_cnt < ncpus) {
1776 newvdp = calloc(*val_cntp, sizeof (val_desc_t));
1777 if (newvdp == NULL) {
1778 status = DLADM_STATUS_NOMEM;
1779 goto done1;
1780 }
1781 vdp = newvdp;
1782 }
1783
1784 /* Check if all CPUs in the list are online */
1785 for (i = 0; i < ncpus; i++) {
1786 if (cpus[i] >= nproc) {
1787 status = DLADM_STATUS_BADCPUID;
1788 goto done2;
1789 }
1790
1791 rc = p_online(cpus[i], P_STATUS);
1792 if (rc < 1) {
1793 status = DLADM_STATUS_CPUERR;
1794 goto done2;
1795 }
1796
1797 if (rc != P_ONLINE) {
1798 status = DLADM_STATUS_CPUNOTONLINE;
1799 goto done2;
1800 }
1801
1802 vdp[i].vd_val = (uintptr_t)cpus[i];
1803 }
1804
1805 /* Check for duplicate CPUs */
1806 for (i = 0; i < *val_cntp; i++) {
1807 for (j = 0; j < *val_cntp; j++) {
1808 if (i != j && vdp[i].vd_val == vdp[j].vd_val) {
1809 status = DLADM_STATUS_BADVAL;
1810 goto done2;
1811 }
1812 }
1813 }
1814
1815 /* Update *val_cntp and *vdpp if everything was OK */
1816 if (val_cnt < ncpus) {
1817 *val_cntp = ncpus;
1818 free(*vdpp);
1819 *vdpp = newvdp;
1820 }
1821
1822 status = DLADM_STATUS_OK;
1823 goto done1;
1824
1825 done2:
1826 free(newvdp);
1827 done1:
1828 free(pv_range);
1829 return (status);
1830 }
1831
1832 /* ARGSUSED */
1833 dladm_status_t
1834 extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
1835 {
1836 mac_resource_props_t *mrp = arg;
1837 int i;
1838
1839 if (vdp[0].vd_val == RESET_VAL) {
1840 bzero(&mrp->mrp_cpus, sizeof (mac_cpus_t));
1841 mrp->mrp_mask |= MRP_CPUS;
1842 return (DLADM_STATUS_OK);
1843 }
1844
1845 for (i = 0; i < cnt; i++)
1846 mrp->mrp_cpu[i] = (uint32_t)vdp[i].vd_val;
1847
1848 mrp->mrp_ncpus = cnt;
1849 mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1850 mrp->mrp_fanout_mode = MCM_CPUS;
1851 mrp->mrp_rx_intr_cpu = -1;
1852
1853 return (DLADM_STATUS_OK);
1854 }
1855
1856 /*
1857 * Get the pool datalink property from the kernel. This is used
1858 * for both the user specified pool and effective pool properties.
1859 */
1860 /* ARGSUSED */
1861 static dladm_status_t
1862 get_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1863 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1864 uint_t flags, uint_t *perm_flags)
1865 {
1866 mac_resource_props_t mrp;
1867 dladm_status_t status;
1868
1869 if (strcmp(pdp->pd_name, "pool-effective") == 0) {
1870 status = i_dladm_get_public_prop(handle, linkid,
1871 "resource-effective", flags, perm_flags, &mrp,
1872 sizeof (mrp));
1873 } else {
1874 status = i_dladm_get_public_prop(handle, linkid,
1875 "resource", flags, perm_flags, &mrp, sizeof (mrp));
1876 }
1877
1878 if (status != DLADM_STATUS_OK)
1879 return (status);
1880
1881 if (strlen(mrp.mrp_pool) == 0) {
1882 (*prop_val)[0] = '\0';
1883 } else {
1884 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1885 "%s", mrp.mrp_pool);
1886 }
1887 *val_cnt = 1;
1888
1889 return (DLADM_STATUS_OK);
1890 }
1891
1892 /* ARGSUSED */
1893 static dladm_status_t
1894 check_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1895 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1896 datalink_media_t media)
1897 {
1898 pool_conf_t *poolconf;
1899 pool_t *pool;
1900 mac_resource_props_t mrp;
1901 dladm_status_t status;
1902 uint_t perm_flags;
1903 char *poolname;
1904 val_desc_t *vdp = *vdpp;
1905
1906 /* Get the current cpus property */
1907 status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1908 &perm_flags, &mrp, sizeof (mrp));
1909
1910 if (status == DLADM_STATUS_OK) {
1911 /* Can't set pool if cpus are set */
1912 if (mrp.mrp_ncpus != 0)
1913 return (DLADM_STATUS_POOLCPU);
1914 }
1915
1916 poolname = malloc(sizeof (mrp.mrp_pool));
1917 if (poolname == NULL)
1918 return (DLADM_STATUS_NOMEM);
1919
1920 /* Check for pool's availability if not booting */
1921 if ((flags & DLADM_OPT_BOOT) == 0) {
1922
1923 /* Allocate and open pool configuration */
1924 if ((poolconf = pool_conf_alloc()) == NULL)
1925 return (DLADM_STATUS_BADVAL);
1926
1927 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY)
1928 != PO_SUCCESS) {
1929 pool_conf_free(poolconf);
1930 return (DLADM_STATUS_BADVAL);
1931 }
1932
1933 /* Look for pool name */
1934 if ((pool = pool_get_pool(poolconf, *prop_val)) == NULL) {
1935 pool_conf_free(poolconf);
1936 return (DLADM_STATUS_BADVAL);
1937 }
1938
1939 pool_conf_free(poolconf);
1940 free(pool);
1941 }
1942
1943 (void) strlcpy(poolname, *prop_val, sizeof (mrp.mrp_pool));
1944 vdp->vd_val = (uintptr_t)poolname;
1945
1946 return (DLADM_STATUS_OK);
1947 }
1948
1949 /* ARGSUSED */
1950 dladm_status_t
1951 extract_pool(val_desc_t *vdp, uint_t cnt, void *arg)
1952 {
1953 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
1954
1955 if (vdp->vd_val == RESET_VAL) {
1956 bzero(&mrp->mrp_pool, sizeof (mrp->mrp_pool));
1957 mrp->mrp_mask |= MRP_POOL;
1958 return (DLADM_STATUS_OK);
1959 }
1960
1961 (void) strlcpy(mrp->mrp_pool, (char *)vdp->vd_val,
1962 sizeof (mrp->mrp_pool));
1963 mrp->mrp_mask |= MRP_POOL;
1964 /*
1965 * Use MCM_CPUS since the fanout count is not user specified
1966 * and will be determined by the cpu list generated from the
1967 * pool.
1968 */
1969 mrp->mrp_fanout_mode = MCM_CPUS;
1970
1971 return (DLADM_STATUS_OK);
1972 }
1973
1974 /* ARGSUSED */
1975 static dladm_status_t
1976 get_priority(dladm_handle_t handle, prop_desc_t *pdp,
1977 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1978 datalink_media_t media, uint_t flags, uint_t *perm_flags)
1979 {
1980 mac_resource_props_t mrp;
1981 mac_priority_level_t pri;
1982 dladm_status_t status;
1983
1984 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1985 perm_flags, &mrp, sizeof (mrp));
1986 if (status != DLADM_STATUS_OK)
1987 return (status);
1988
1989 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
1990 mrp.mrp_priority;
1991
1992 (void) dladm_pri2str(pri, prop_val[0]);
1993 *val_cnt = 1;
1994 return (DLADM_STATUS_OK);
1995 }
1996
1997 /* ARGSUSED */
1998 dladm_status_t
1999 extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
2000 {
2001 mac_resource_props_t *mrp = arg;
2002
2003 if (cnt != 1)
2004 return (DLADM_STATUS_BADVAL);
2005
2006 mrp->mrp_priority = (mac_priority_level_t)vdp->vd_val;
2007 mrp->mrp_mask |= MRP_PRIORITY;
2008
2009 return (DLADM_STATUS_OK);
2010 }
2011
2012 /*
2013 * Determines the size of the structure that needs to be sent to drivers
2014 * for retrieving the property range values.
2015 */
2016 static int
2017 i_dladm_range_size(mac_propval_range_t *r, size_t *sz, uint_t *rcount)
2018 {
2019 uint_t count = r->mpr_count;
2020
2021 *sz = sizeof (mac_propval_range_t);
2022 *rcount = count;
2023 --count;
2024
2025 switch (r->mpr_type) {
2026 case MAC_PROPVAL_UINT32:
2027 *sz += (count * sizeof (mac_propval_uint32_range_t));
2028 return (0);
2029 default:
2030 break;
2031 }
2032 *sz = 0;
2033 *rcount = 0;
2034 return (EINVAL);
2035 }
2036
2037
2038 /* ARGSUSED */
2039 static dladm_status_t
2040 check_rings(dladm_handle_t handle, prop_desc_t *pdp,
2041 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2042 val_desc_t **vp, datalink_media_t media)
2043 {
2044 uint_t val_cnt = *val_cntp;
2045 val_desc_t *v = *vp;
2046
2047 if (val_cnt != 1)
2048 return (DLADM_STATUS_BADVAL);
2049 if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) {
2050 v->vd_val = UNSPEC_VAL;
2051 } else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) {
2052 v->vd_val = 0;
2053 } else {
2054 v->vd_val = strtoul(prop_val[0], NULL, 0);
2055 if (v->vd_val == 0)
2056 return (DLADM_STATUS_BADVAL);
2057 }
2058 return (DLADM_STATUS_OK);
2059 }
2060
2061 /* ARGSUSED */
2062 static dladm_status_t
2063 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp,
2064 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2065 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2066 {
2067 dld_ioc_macprop_t *dip;
2068 dladm_status_t status = DLADM_STATUS_OK;
2069 mac_propval_range_t *rangep;
2070 size_t sz;
2071 mac_propval_uint32_range_t *ur;
2072
2073 sz = sizeof (mac_propval_range_t);
2074
2075 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
2076 &status)) == NULL)
2077 return (status);
2078
2079 status = i_dladm_macprop(handle, dip, B_FALSE);
2080 if (status != DLADM_STATUS_OK)
2081 return (status);
2082
2083 rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
2084 *val_cnt = 1;
2085 ur = &rangep->mpr_range_uint32[0];
2086 /* This is the case where the dev doesn't have any rings/groups */
2087 if (rangep->mpr_count == 0) {
2088 (*prop_val)[0] = '\0';
2089 /*
2090 * This is the case where the dev supports rings, but static
2091 * grouping.
2092 */
2093 } else if (ur->mpur_min == ur->mpur_max &&
2094 ur->mpur_max == 0) {
2095 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw");
2096 /*
2097 * This is the case where the dev supports rings and dynamic
2098 * grouping, but has only one value (say 2 rings and 2 groups).
2099 */
2100 } else if (ur->mpur_min == ur->mpur_max) {
2101 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d",
2102 ur->mpur_min);
2103 /*
2104 * This is the case where the dev supports rings and dynamic
2105 * grouping and has a range of rings.
2106 */
2107 } else {
2108 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX,
2109 "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max);
2110 }
2111 free(dip);
2112 return (status);
2113 }
2114
2115
2116 /* ARGSUSED */
2117 static dladm_status_t
2118 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2119 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2120 uint_t flags, uint_t *perm_flags)
2121 {
2122 mac_resource_props_t mrp;
2123 dladm_status_t status;
2124 uint32_t nrings = 0;
2125
2126 /*
2127 * Get the number of (effective-)rings from the resource property.
2128 */
2129 if (strcmp(pdp->pd_name, "rxrings-effective") == 0) {
2130 status = i_dladm_get_public_prop(handle, linkid,
2131 "resource-effective", flags, perm_flags, &mrp,
2132 sizeof (mrp));
2133 } else {
2134 /*
2135 * Get the permissions from the "rxrings" property.
2136 */
2137 status = i_dladm_get_public_prop(handle, linkid, "rxrings",
2138 flags, perm_flags, NULL, 0);
2139 if (status != DLADM_STATUS_OK)
2140 return (status);
2141
2142 status = i_dladm_get_public_prop(handle, linkid,
2143 "resource", flags, NULL, &mrp, sizeof (mrp));
2144 }
2145
2146 if (status != DLADM_STATUS_OK)
2147 return (status);
2148
2149 if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) {
2150 *val_cnt = 0;
2151 return (DLADM_STATUS_OK);
2152 }
2153 nrings = mrp.mrp_nrxrings;
2154 *val_cnt = 1;
2155 if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC)
2156 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2157 else if (nrings == 0)
2158 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2159 else
2160 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2161 return (DLADM_STATUS_OK);
2162 }
2163
2164 /* ARGSUSED */
2165 dladm_status_t
2166 extract_rxrings(val_desc_t *vdp, uint_t cnt, void *arg)
2167 {
2168 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2169
2170 mrp->mrp_nrxrings = 0;
2171 if (vdp->vd_val == RESET_VAL)
2172 mrp->mrp_mask = MRP_RINGS_RESET;
2173 else if (vdp->vd_val == UNSPEC_VAL)
2174 mrp->mrp_mask = MRP_RXRINGS_UNSPEC;
2175 else
2176 mrp->mrp_nrxrings = vdp->vd_val;
2177 mrp->mrp_mask |= MRP_RX_RINGS;
2178
2179 return (DLADM_STATUS_OK);
2180 }
2181
2182 /* ARGSUSED */
2183 static dladm_status_t
2184 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2185 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2186 uint_t flags, uint_t *perm_flags)
2187 {
2188 mac_resource_props_t mrp;
2189 dladm_status_t status;
2190 uint32_t nrings = 0;
2191
2192
2193 /*
2194 * Get the number of (effective-)rings from the resource property.
2195 */
2196 if (strcmp(pdp->pd_name, "txrings-effective") == 0) {
2197 status = i_dladm_get_public_prop(handle, linkid,
2198 "resource-effective", flags, perm_flags, &mrp,
2199 sizeof (mrp));
2200 } else {
2201 /*
2202 * Get the permissions from the "txrings" property.
2203 */
2204 status = i_dladm_get_public_prop(handle, linkid, "txrings",
2205 flags, perm_flags, NULL, 0);
2206 if (status != DLADM_STATUS_OK)
2207 return (status);
2208
2209 /*
2210 * Get the number of rings from the "resource" property.
2211 */
2212 status = i_dladm_get_public_prop(handle, linkid, "resource",
2213 flags, NULL, &mrp, sizeof (mrp));
2214 }
2215
2216 if (status != DLADM_STATUS_OK)
2217 return (status);
2218
2219 if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) {
2220 *val_cnt = 0;
2221 return (DLADM_STATUS_OK);
2222 }
2223 nrings = mrp.mrp_ntxrings;
2224 *val_cnt = 1;
2225 if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC)
2226 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2227 else if (nrings == 0)
2228 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2229 else
2230 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2231 return (DLADM_STATUS_OK);
2232 }
2233
2234 /* ARGSUSED */
2235 dladm_status_t
2236 extract_txrings(val_desc_t *vdp, uint_t cnt, void *arg)
2237 {
2238 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2239
2240 mrp->mrp_ntxrings = 0;
2241 if (vdp->vd_val == RESET_VAL)
2242 mrp->mrp_mask = MRP_RINGS_RESET;
2243 else if (vdp->vd_val == UNSPEC_VAL)
2244 mrp->mrp_mask = MRP_TXRINGS_UNSPEC;
2245 else
2246 mrp->mrp_ntxrings = vdp->vd_val;
2247 mrp->mrp_mask |= MRP_TX_RINGS;
2248
2249 return (DLADM_STATUS_OK);
2250 }
2251
2252 /* ARGSUSED */
2253 static dladm_status_t
2254 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2255 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2256 uint_t *perm_flags)
2257 {
2258 if (flags & DLD_PROP_DEFAULT)
2259 return (DLADM_STATUS_NOTDEFINED);
2260
2261 return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media,
2262 flags, perm_flags));
2263 }
2264
2265 /* ARGSUSED */
2266 static dladm_status_t
2267 set_resource(dladm_handle_t handle, prop_desc_t *pdp,
2268 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
2269 uint_t flags, datalink_media_t media)
2270 {
2271 mac_resource_props_t mrp;
2272 dladm_status_t status = DLADM_STATUS_OK;
2273 dld_ioc_macprop_t *dip;
2274 int i;
2275
2276 bzero(&mrp, sizeof (mac_resource_props_t));
2277 dip = i_dladm_buf_alloc_by_name(0, linkid, "resource",
2278 flags, &status);
2279
2280 if (dip == NULL)
2281 return (status);
2282
2283 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
2284 resource_prop_t *rp = &rsrc_prop_table[i];
2285
2286 if (strcmp(pdp->pd_name, rp->rp_name) != 0)
2287 continue;
2288
2289 status = rp->rp_extract(vdp, val_cnt, &mrp);
2290 if (status != DLADM_STATUS_OK)
2291 goto done;
2292
2293 break;
2294 }
2295
2296 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
2297 status = i_dladm_macprop(handle, dip, B_TRUE);
2298
2299 done:
2300 free(dip);
2301 return (status);
2302 }
2303
2304 /* ARGSUSED */
2305 static dladm_status_t
2306 get_protection(dladm_handle_t handle, prop_desc_t *pdp,
2307 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2308 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2309 {
2310 mac_resource_props_t mrp;
2311 mac_protect_t *p;
2312 dladm_status_t status;
2313 uint32_t i, cnt = 0, setbits[32];
2314
2315 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2316 perm_flags, &mrp, sizeof (mrp));
2317 if (status != DLADM_STATUS_OK)
2318 return (status);
2319
2320 p = &mrp.mrp_protect;
2321 if ((mrp.mrp_mask & MRP_PROTECT) == 0) {
2322 *val_cnt = 0;
2323 return (DLADM_STATUS_OK);
2324 }
2325 dladm_find_setbits32(p->mp_types, setbits, &cnt);
2326 if (cnt > *val_cnt)
2327 return (DLADM_STATUS_BADVALCNT);
2328
2329 for (i = 0; i < cnt; i++)
2330 (void) dladm_protect2str(setbits[i], prop_val[i]);
2331
2332 *val_cnt = cnt;
2333 return (DLADM_STATUS_OK);
2334 }
2335
2336 /* ARGSUSED */
2337 static dladm_status_t
2338 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2339 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2340 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2341 {
2342 mac_resource_props_t mrp;
2343 mac_protect_t *p;
2344 dladm_status_t status;
2345 int i;
2346
2347 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2348 perm_flags, &mrp, sizeof (mrp));
2349 if (status != DLADM_STATUS_OK)
2350 return (status);
2351
2352 p = &mrp.mrp_protect;
2353 if (p->mp_ipaddrcnt == 0) {
2354 *val_cnt = 0;
2355 return (DLADM_STATUS_OK);
2356 }
2357 if (p->mp_ipaddrcnt > *val_cnt)
2358 return (DLADM_STATUS_BADVALCNT);
2359
2360 for (i = 0; i < p->mp_ipaddrcnt; i++) {
2361 int len;
2362 if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) {
2363 ipaddr_t v4addr;
2364
2365 v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr);
2366 (void) dladm_ipv4addr2str(&v4addr, prop_val[i]);
2367 } else {
2368 (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr,
2369 prop_val[i]);
2370 }
2371 len = strlen(prop_val[i]);
2372 (void) sprintf(prop_val[i] + len, "/%d",
2373 p->mp_ipaddrs[i].ip_netmask);
2374 }
2375 *val_cnt = p->mp_ipaddrcnt;
2376 return (DLADM_STATUS_OK);
2377 }
2378
2379 dladm_status_t
2380 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
2381 {
2382 mac_resource_props_t *mrp = arg;
2383 uint32_t types = 0;
2384 int i;
2385
2386 for (i = 0; i < cnt; i++)
2387 types |= (uint32_t)vdp[i].vd_val;
2388
2389 mrp->mrp_protect.mp_types = types;
2390 mrp->mrp_mask |= MRP_PROTECT;
2391 return (DLADM_STATUS_OK);
2392 }
2393
2394 dladm_status_t
2395 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
2396 {
2397 mac_resource_props_t *mrp = arg;
2398 mac_protect_t *p = &mrp->mrp_protect;
2399 int i;
2400
2401 if (vdp->vd_val == 0) {
2402 cnt = (uint_t)-1;
2403 } else {
2404 for (i = 0; i < cnt; i++) {
2405 bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i],
2406 sizeof (mac_ipaddr_t));
2407 }
2408 }
2409 p->mp_ipaddrcnt = cnt;
2410 mrp->mrp_mask |= MRP_PROTECT;
2411 return (DLADM_STATUS_OK);
2412 }
2413
2414 static dladm_status_t
2415 check_single_ip(char *buf, mac_ipaddr_t *addr)
2416 {
2417 dladm_status_t status;
2418 ipaddr_t v4addr;
2419 in6_addr_t v6addr;
2420 boolean_t isv4 = B_TRUE;
2421 char *p;
2422 uint32_t mask = 0;
2423
2424 /*
2425 * If the IP address is in CIDR format, parse the bits component
2426 * seperately. An address in this style will be used to indicate an
2427 * entire subnet, so it must be a network number with no host address.
2428 */
2429 if ((p = strchr(buf, '/')) != NULL) {
2430 char *end = NULL;
2431
2432 *p++ = '\0';
2433 if (!isdigit(*p))
2434 return (DLADM_STATUS_INVALID_IP);
2435 mask = strtol(p, &end, 10);
2436 if (end != NULL && *end != '\0')
2437 return (DLADM_STATUS_INVALID_IP);
2438 if (mask > 128|| mask < 1)
2439 return (DLADM_STATUS_INVALID_IP);
2440 }
2441
2442 status = dladm_str2ipv4addr(buf, &v4addr);
2443 if (status == DLADM_STATUS_INVALID_IP) {
2444 status = dladm_str2ipv6addr(buf, &v6addr);
2445 if (status == DLADM_STATUS_OK)
2446 isv4 = B_FALSE;
2447 }
2448 if (status != DLADM_STATUS_OK)
2449 return (status);
2450
2451 if (isv4) {
2452 if (v4addr == INADDR_ANY)
2453 return (DLADM_STATUS_INVALID_IP);
2454
2455 IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr);
2456 addr->ip_version = IPV4_VERSION;
2457 if (p != NULL) {
2458 uint32_t smask;
2459
2460 /*
2461 * Validate the netmask is in the proper range for v4
2462 */
2463 if (mask > 32 || mask < 1)
2464 return (DLADM_STATUS_INVALID_IP);
2465
2466 /*
2467 * We have a CIDR style address, confirm that only the
2468 * network number is set.
2469 */
2470 smask = 0xFFFFFFFFu << (32 - mask);
2471 if (htonl(v4addr) & ~smask)
2472 return (DLADM_STATUS_INVALID_IP);
2473 } else {
2474 mask = 32;
2475 }
2476 addr->ip_netmask = mask;
2477 } else {
2478 if (IN6_IS_ADDR_UNSPECIFIED(&v6addr))
2479 return (DLADM_STATUS_INVALID_IP);
2480
2481 if (IN6_IS_ADDR_V4MAPPED_ANY(&v6addr))
2482 return (DLADM_STATUS_INVALID_IP);
2483
2484 if (p != NULL) {
2485 int i, off, high;
2486
2487 /*
2488 * Note that the address in our buffer is stored in
2489 * network byte order.
2490 */
2491 off = 0;
2492 for (i = 3; i >= 0; i--) {
2493 high = ffsl(ntohl(v6addr._S6_un._S6_u32[i]));
2494 if (high != 0)
2495 break;
2496 off += 32;
2497 }
2498 off += high;
2499 if (128 - off >= mask)
2500 return (DLADM_STATUS_INVALID_IP);
2501 } else {
2502 mask = 128;
2503 }
2504
2505 addr->ip_addr = v6addr;
2506 addr->ip_version = IPV6_VERSION;
2507 addr->ip_netmask = mask;
2508 }
2509 return (DLADM_STATUS_OK);
2510 }
2511
2512 /* ARGSUSED */
2513 static dladm_status_t
2514 check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2515 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2516 val_desc_t **vdpp, datalink_media_t media)
2517 {
2518 dladm_status_t status;
2519 mac_ipaddr_t *addr;
2520 int i;
2521 uint_t val_cnt = *val_cntp;
2522 val_desc_t *vdp = *vdpp;
2523
2524 if (val_cnt > MPT_MAXIPADDR)
2525 return (DLADM_STATUS_BADVALCNT);
2526
2527 for (i = 0; i < val_cnt; i++) {
2528 if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) {
2529 status = DLADM_STATUS_NOMEM;
2530 goto fail;
2531 }
2532 vdp[i].vd_val = (uintptr_t)addr;
2533
2534 status = check_single_ip(prop_val[i], addr);
2535 if (status != DLADM_STATUS_OK)
2536 goto fail;
2537 }
2538 return (DLADM_STATUS_OK);
2539
2540 fail:
2541 for (i = 0; i < val_cnt; i++) {
2542 free((void *)vdp[i].vd_val);
2543 vdp[i].vd_val = NULL;
2544 }
2545 return (status);
2546 }
2547
2548 static void
2549 dladm_cid2str(mac_dhcpcid_t *cid, char *buf)
2550 {
2551 char tmp_buf[DLADM_STRSIZE];
2552 uint_t hexlen;
2553
2554 switch (cid->dc_form) {
2555 case CIDFORM_TYPED: {
2556 uint16_t duidtype, hwtype;
2557 uint32_t timestamp, ennum;
2558 char *lladdr;
2559
2560 if (cid->dc_len < sizeof (duidtype))
2561 goto fail;
2562
2563 bcopy(cid->dc_id, &duidtype, sizeof (duidtype));
2564 duidtype = ntohs(duidtype);
2565 switch (duidtype) {
2566 case DHCPV6_DUID_LLT: {
2567 duid_llt_t llt;
2568
2569 if (cid->dc_len < sizeof (llt))
2570 goto fail;
2571
2572 bcopy(cid->dc_id, &llt, sizeof (llt));
2573 hwtype = ntohs(llt.dllt_hwtype);
2574 timestamp = ntohl(llt.dllt_time);
2575 lladdr = _link_ntoa(cid->dc_id + sizeof (llt),
2576 NULL, cid->dc_len - sizeof (llt), IFT_OTHER);
2577 if (lladdr == NULL)
2578 goto fail;
2579
2580 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s",
2581 duidtype, hwtype, timestamp, lladdr);
2582 free(lladdr);
2583 break;
2584 }
2585 case DHCPV6_DUID_EN: {
2586 duid_en_t en;
2587
2588 if (cid->dc_len < sizeof (en))
2589 goto fail;
2590
2591 bcopy(cid->dc_id, &en, sizeof (en));
2592 ennum = DHCPV6_GET_ENTNUM(&en);
2593 hexlen = sizeof (tmp_buf);
2594 if (octet_to_hexascii(cid->dc_id + sizeof (en),
2595 cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0)
2596 goto fail;
2597
2598 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2599 duidtype, ennum, tmp_buf);
2600 break;
2601 }
2602 case DHCPV6_DUID_LL: {
2603 duid_ll_t ll;
2604
2605 if (cid->dc_len < sizeof (ll))
2606 goto fail;
2607
2608 bcopy(cid->dc_id, &ll, sizeof (ll));
2609 hwtype = ntohs(ll.dll_hwtype);
2610 lladdr = _link_ntoa(cid->dc_id + sizeof (ll),
2611 NULL, cid->dc_len - sizeof (ll), IFT_OTHER);
2612 if (lladdr == NULL)
2613 goto fail;
2614
2615 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2616 duidtype, hwtype, lladdr);
2617 free(lladdr);
2618 break;
2619 }
2620 default: {
2621 hexlen = sizeof (tmp_buf);
2622 if (octet_to_hexascii(cid->dc_id + sizeof (duidtype),
2623 cid->dc_len - sizeof (duidtype),
2624 tmp_buf, &hexlen) != 0)
2625 goto fail;
2626
2627 (void) snprintf(buf, DLADM_STRSIZE, "%d.%s",
2628 duidtype, tmp_buf);
2629 }
2630 }
2631 break;
2632 }
2633 case CIDFORM_HEX: {
2634 hexlen = sizeof (tmp_buf);
2635 if (octet_to_hexascii(cid->dc_id, cid->dc_len,
2636 tmp_buf, &hexlen) != 0)
2637 goto fail;
2638
2639 (void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf);
2640 break;
2641 }
2642 case CIDFORM_STR: {
2643 int i;
2644
2645 for (i = 0; i < cid->dc_len; i++) {
2646 if (!isprint(cid->dc_id[i]))
2647 goto fail;
2648 }
2649 (void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id);
2650 break;
2651 }
2652 default:
2653 goto fail;
2654 }
2655 return;
2656
2657 fail:
2658 (void) snprintf(buf, DLADM_STRSIZE, "<unknown>");
2659 }
2660
2661 static dladm_status_t
2662 dladm_str2cid(char *buf, mac_dhcpcid_t *cid)
2663 {
2664 char *ptr = buf;
2665 char tmp_buf[DLADM_STRSIZE];
2666 uint_t hexlen, cidlen;
2667
2668 bzero(cid, sizeof (*cid));
2669 if (isdigit(*ptr) &&
2670 ptr[strspn(ptr, "0123456789")] == '.') {
2671 char *cp;
2672 ulong_t duidtype;
2673 ulong_t subtype;
2674 ulong_t timestamp;
2675 uchar_t *lladdr;
2676 int addrlen;
2677
2678 errno = 0;
2679 duidtype = strtoul(ptr, &cp, 0);
2680 if (ptr == cp || errno != 0 || *cp != '.' ||
2681 duidtype > USHRT_MAX)
2682 return (DLADM_STATUS_BADARG);
2683 ptr = cp + 1;
2684
2685 if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) {
2686 errno = 0;
2687 subtype = strtoul(ptr, &cp, 0);
2688 if (ptr == cp || errno != 0 || *cp != '.')
2689 return (DLADM_STATUS_BADARG);
2690 ptr = cp + 1;
2691 }
2692 switch (duidtype) {
2693 case DHCPV6_DUID_LLT: {
2694 duid_llt_t llt;
2695
2696 errno = 0;
2697 timestamp = strtoul(ptr, &cp, 0);
2698 if (ptr == cp || errno != 0 || *cp != '.')
2699 return (DLADM_STATUS_BADARG);
2700
2701 ptr = cp + 1;
2702 lladdr = _link_aton(ptr, &addrlen);
2703 if (lladdr == NULL)
2704 return (DLADM_STATUS_BADARG);
2705
2706 cidlen = sizeof (llt) + addrlen;
2707 if (cidlen > sizeof (cid->dc_id)) {
2708 free(lladdr);
2709 return (DLADM_STATUS_TOOSMALL);
2710 }
2711 llt.dllt_dutype = htons(duidtype);
2712 llt.dllt_hwtype = htons(subtype);
2713 llt.dllt_time = htonl(timestamp);
2714 bcopy(&llt, cid->dc_id, sizeof (llt));
2715 bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen);
2716 free(lladdr);
2717 break;
2718 }
2719 case DHCPV6_DUID_LL: {
2720 duid_ll_t ll;
2721
2722 lladdr = _link_aton(ptr, &addrlen);
2723 if (lladdr == NULL)
2724 return (DLADM_STATUS_BADARG);
2725
2726 cidlen = sizeof (ll) + addrlen;
2727 if (cidlen > sizeof (cid->dc_id)) {
2728 free(lladdr);
2729 return (DLADM_STATUS_TOOSMALL);
2730 }
2731 ll.dll_dutype = htons(duidtype);
2732 ll.dll_hwtype = htons(subtype);
2733 bcopy(&ll, cid->dc_id, sizeof (ll));
2734 bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen);
2735 free(lladdr);
2736 break;
2737 }
2738 default: {
2739 hexlen = sizeof (tmp_buf);
2740 if (hexascii_to_octet(ptr, strlen(ptr),
2741 tmp_buf, &hexlen) != 0)
2742 return (DLADM_STATUS_BADARG);
2743
2744 if (duidtype == DHCPV6_DUID_EN) {
2745 duid_en_t en;
2746
2747 en.den_dutype = htons(duidtype);
2748 DHCPV6_SET_ENTNUM(&en, subtype);
2749
2750 cidlen = sizeof (en) + hexlen;
2751 if (cidlen > sizeof (cid->dc_id))
2752 return (DLADM_STATUS_TOOSMALL);
2753
2754 bcopy(&en, cid->dc_id, sizeof (en));
2755 bcopy(tmp_buf, cid->dc_id + sizeof (en),
2756 hexlen);
2757 } else {
2758 uint16_t dutype = htons(duidtype);
2759
2760 cidlen = sizeof (dutype) + hexlen;
2761 if (cidlen > sizeof (cid->dc_id))
2762 return (DLADM_STATUS_TOOSMALL);
2763
2764 bcopy(&dutype, cid->dc_id, sizeof (dutype));
2765 bcopy(tmp_buf, cid->dc_id + sizeof (dutype),
2766 hexlen);
2767 }
2768 break;
2769 }
2770 }
2771 cid->dc_form = CIDFORM_TYPED;
2772 } else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') {
2773 ptr += 2;
2774 hexlen = sizeof (tmp_buf);
2775 if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf,
2776 &hexlen) != 0) {
2777 return (DLADM_STATUS_BADARG);
2778 }
2779 cidlen = hexlen;
2780 if (cidlen > sizeof (cid->dc_id))
2781 return (DLADM_STATUS_TOOSMALL);
2782
2783 bcopy(tmp_buf, cid->dc_id, cidlen);
2784 cid->dc_form = CIDFORM_HEX;
2785 } else {
2786 cidlen = strlen(ptr);
2787 if (cidlen > sizeof (cid->dc_id))
2788 return (DLADM_STATUS_TOOSMALL);
2789
2790 bcopy(ptr, cid->dc_id, cidlen);
2791 cid->dc_form = CIDFORM_STR;
2792 }
2793 cid->dc_len = cidlen;
2794 return (DLADM_STATUS_OK);
2795 }
2796
2797 /* ARGSUSED */
2798 static dladm_status_t
2799 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2800 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2801 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2802 {
2803 mac_resource_props_t mrp;
2804 mac_protect_t *p;
2805 dladm_status_t status;
2806 int i;
2807
2808 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2809 perm_flags, &mrp, sizeof (mrp));
2810 if (status != DLADM_STATUS_OK)
2811 return (status);
2812
2813 p = &mrp.mrp_protect;
2814 if (p->mp_cidcnt == 0) {
2815 *val_cnt = 0;
2816 return (DLADM_STATUS_OK);
2817 }
2818 if (p->mp_cidcnt > *val_cnt)
2819 return (DLADM_STATUS_BADVALCNT);
2820
2821 for (i = 0; i < p->mp_cidcnt; i++) {
2822 mac_dhcpcid_t *cid = &p->mp_cids[i];
2823
2824 dladm_cid2str(cid, prop_val[i]);
2825 }
2826 *val_cnt = p->mp_cidcnt;
2827 return (DLADM_STATUS_OK);
2828 }
2829
2830 dladm_status_t
2831 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg)
2832 {
2833 mac_resource_props_t *mrp = arg;
2834 mac_protect_t *p = &mrp->mrp_protect;
2835 int i;
2836
2837 if (vdp->vd_val == 0) {
2838 cnt = (uint_t)-1;
2839 } else {
2840 for (i = 0; i < cnt; i++) {
2841 bcopy((void *)vdp[i].vd_val, &p->mp_cids[i],
2842 sizeof (mac_dhcpcid_t));
2843 }
2844 }
2845 p->mp_cidcnt = cnt;
2846 mrp->mrp_mask |= MRP_PROTECT;
2847 return (DLADM_STATUS_OK);
2848 }
2849
2850 /* ARGSUSED */
2851 static dladm_status_t
2852 check_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2853 datalink_id_t linkid, char **prop_val, uint_t *val_cntp,
2854 uint_t flags, val_desc_t **vdpp, datalink_media_t media)
2855 {
2856 dladm_status_t status;
2857 mac_dhcpcid_t *cid;
2858 int i;
2859 uint_t val_cnt = *val_cntp;
2860 val_desc_t *vdp = *vdpp;
2861
2862 if (val_cnt > MPT_MAXCID)
2863 return (DLADM_STATUS_BADVALCNT);
2864
2865 for (i = 0; i < val_cnt; i++) {
2866 if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) {
2867 status = DLADM_STATUS_NOMEM;
2868 goto fail;
2869 }
2870 vdp[i].vd_val = (uintptr_t)cid;
2871
2872 status = dladm_str2cid(prop_val[i], cid);
2873 if (status != DLADM_STATUS_OK)
2874 goto fail;
2875 }
2876 return (DLADM_STATUS_OK);
2877
2878 fail:
2879 for (i = 0; i < val_cnt; i++) {
2880 free((void *)vdp[i].vd_val);
2881 vdp[i].vd_val = NULL;
2882 }
2883 return (status);
2884 }
2885
2886 /* ARGSUSED */
2887 static dladm_status_t
2888 get_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2889 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2890 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2891 {
2892 mac_secondary_addr_t sa;
2893 dladm_status_t status;
2894 int i;
2895
2896 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2897 perm_flags, &sa, sizeof (sa));
2898 if (status != DLADM_STATUS_OK)
2899 return (status);
2900
2901 if (sa.ms_addrcnt > *val_cnt)
2902 return (DLADM_STATUS_BADVALCNT);
2903
2904 for (i = 0; i < sa.ms_addrcnt; i++) {
2905 if (dladm_aggr_macaddr2str(
2906 (const unsigned char *)&sa.ms_addrs[i], prop_val[i]) ==
2907 NULL) {
2908 *val_cnt = i;
2909 return (DLADM_STATUS_NOMEM);
2910 }
2911 }
2912 *val_cnt = sa.ms_addrcnt;
2913 return (DLADM_STATUS_OK);
2914 }
2915
2916 /* ARGSUSED */
2917 static dladm_status_t
2918 check_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2919 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2920 val_desc_t **vdpp, datalink_media_t media)
2921 {
2922 dladm_status_t status;
2923 uchar_t *addr;
2924 uint_t len = 0;
2925 int i;
2926 uint_t val_cnt = *val_cntp;
2927 val_desc_t *vdp = *vdpp;
2928
2929 if (val_cnt >= MPT_MAXMACADDR)
2930 return (DLADM_STATUS_BADVALCNT);
2931
2932 for (i = 0; i < val_cnt; i++) {
2933 addr = _link_aton(prop_val[i], (int *)&len);
2934 if (addr == NULL) {
2935 if (len == (uint_t)-1)
2936 status = DLADM_STATUS_MACADDRINVAL;
2937 else
2938 status = DLADM_STATUS_NOMEM;
2939 goto fail;
2940 }
2941
2942 vdp[i].vd_val = (uintptr_t)addr;
2943 }
2944 return (DLADM_STATUS_OK);
2945
2946 fail:
2947 for (i = 0; i < val_cnt; i++) {
2948 free((void *)vdp[i].vd_val);
2949 vdp[i].vd_val = NULL;
2950 }
2951 return (status);
2952 }
2953
2954 /* ARGSUSED */
2955 static dladm_status_t
2956 set_secondary_macs(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
2957 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
2958 {
2959 dladm_status_t status;
2960 dld_ioc_macprop_t *dip;
2961 int i;
2962 mac_secondary_addr_t msa;
2963
2964 dip = i_dladm_buf_alloc_by_name(0, linkid, "secondary-macs", 0,
2965 &status);
2966 if (dip == NULL)
2967 return (status);
2968
2969 if (vdp->vd_val == 0) {
2970 val_cnt = (uint_t)-1;
2971 } else {
2972 for (i = 0; i < val_cnt; i++) {
2973 bcopy((void *)vdp[i].vd_val, msa.ms_addrs[i],
2974 MAXMACADDRLEN);
2975 }
2976 }
2977 msa.ms_addrcnt = val_cnt;
2978 bcopy(&msa, dip->pr_val, dip->pr_valsize);
2979
2980 status = i_dladm_macprop(handle, dip, B_TRUE);
2981
2982 free(dip);
2983 return (status);
2984 }
2985
2986 /* ARGSUSED */
2987 static dladm_status_t
2988 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2989 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2990 uint_t flags, uint_t *perm_flags)
2991 {
2992 struct dlautopush dlap;
2993 int i, len;
2994 dladm_status_t status;
2995
2996 if (flags & DLD_PROP_DEFAULT)
2997 return (DLADM_STATUS_NOTDEFINED);
2998
2999 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3000 perm_flags, &dlap, sizeof (dlap));
3001 if (status != DLADM_STATUS_OK)
3002 return (status);
3003
3004 if (dlap.dap_npush == 0) {
3005 *val_cnt = 0;
3006 return (DLADM_STATUS_OK);
3007 }
3008 for (i = 0, len = 0; i < dlap.dap_npush; i++) {
3009 if (i != 0) {
3010 (void) snprintf(*prop_val + len,
3011 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
3012 len += 1;
3013 }
3014 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
3015 "%s", dlap.dap_aplist[i]);
3016 len += strlen(dlap.dap_aplist[i]);
3017 if (dlap.dap_anchor - 1 == i) {
3018 (void) snprintf(*prop_val + len,
3019 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
3020 AP_ANCHOR);
3021 len += (strlen(AP_ANCHOR) + 1);
3022 }
3023 }
3024 *val_cnt = 1;
3025 return (DLADM_STATUS_OK);
3026 }
3027
3028 /*
3029 * Add the specified module to the dlautopush structure; returns a
3030 * DLADM_STATUS_* code.
3031 */
3032 dladm_status_t
3033 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
3034 {
3035 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
3036 return (DLADM_STATUS_BADVAL);
3037
3038 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
3039 /*
3040 * We don't allow multiple anchors, and the anchor must
3041 * be after at least one module.
3042 */
3043 if (dlap->dap_anchor != 0)
3044 return (DLADM_STATUS_BADVAL);
3045 if (dlap->dap_npush == 0)
3046 return (DLADM_STATUS_BADVAL);
3047
3048 dlap->dap_anchor = dlap->dap_npush;
3049 return (DLADM_STATUS_OK);
3050 }
3051 if (dlap->dap_npush >= MAXAPUSH)
3052 return (DLADM_STATUS_BADVALCNT);
3053
3054 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
3055 FMNAMESZ + 1);
3056
3057 return (DLADM_STATUS_OK);
3058 }
3059
3060 /*
3061 * Currently, both '.' and ' '(space) can be used as the delimiters between
3062 * autopush modules. The former is used in dladm set-linkprop, and the
3063 * latter is used in the autopush(1M) file.
3064 */
3065 /* ARGSUSED */
3066 static dladm_status_t
3067 check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3068 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3069 datalink_media_t media)
3070 {
3071 char *module;
3072 struct dlautopush *dlap;
3073 dladm_status_t status;
3074 char val[DLADM_PROP_VAL_MAX];
3075 char delimiters[4];
3076 uint_t val_cnt = *val_cntp;
3077 val_desc_t *vdp = *vdpp;
3078
3079 if (val_cnt != 1)
3080 return (DLADM_STATUS_BADVALCNT);
3081
3082 if (prop_val != NULL) {
3083 dlap = malloc(sizeof (struct dlautopush));
3084 if (dlap == NULL)
3085 return (DLADM_STATUS_NOMEM);
3086
3087 (void) memset(dlap, 0, sizeof (struct dlautopush));
3088 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
3089 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
3090 module = strtok(val, delimiters);
3091 while (module != NULL) {
3092 status = i_dladm_add_ap_module(module, dlap);
3093 if (status != DLADM_STATUS_OK)
3094 return (status);
3095 module = strtok(NULL, delimiters);
3096 }
3097
3098 vdp->vd_val = (uintptr_t)dlap;
3099 } else {
3100 vdp->vd_val = 0;
3101 }
3102 return (DLADM_STATUS_OK);
3103 }
3104
3105 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
3106
3107 /* ARGSUSED */
3108 static dladm_status_t
3109 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
3110 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
3111 uint_t *perm_flags)
3112 {
3113 wl_rates_t *wrp;
3114 uint_t i;
3115 dladm_status_t status = DLADM_STATUS_OK;
3116
3117 wrp = malloc(WLDP_BUFSIZE);
3118 if (wrp == NULL)
3119 return (DLADM_STATUS_NOMEM);
3120
3121 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
3122 B_FALSE);
3123 if (status != DLADM_STATUS_OK)
3124 goto done;
3125
3126 if (wrp->wl_rates_num > *val_cnt) {
3127 status = DLADM_STATUS_TOOSMALL;
3128 goto done;
3129 }
3130
3131 if (wrp->wl_rates_rates[0] == 0) {
3132 prop_val[0][0] = '\0';
3133 *val_cnt = 1;
3134 goto done;
3135 }
3136
3137 for (i = 0; i < wrp->wl_rates_num; i++) {
3138 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
3139 wrp->wl_rates_rates[i] % 2,
3140 (float)wrp->wl_rates_rates[i] / 2);
3141 }
3142 *val_cnt = wrp->wl_rates_num;
3143 *perm_flags = MAC_PROP_PERM_RW;
3144
3145 done:
3146 free(wrp);
3147 return (status);
3148 }
3149
3150 static dladm_status_t
3151 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3152 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3153 uint_t flags, uint_t *perm_flags)
3154 {
3155 if (media != DL_WIFI) {
3156 return (get_speed(handle, pdp, linkid, prop_val,
3157 val_cnt, media, flags, perm_flags));
3158 }
3159
3160 return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
3161 MAC_PROP_WL_DESIRED_RATES, perm_flags));
3162 }
3163
3164 /* ARGSUSED */
3165 static dladm_status_t
3166 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3167 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3168 uint_t flags, uint_t *perm_flags)
3169 {
3170 switch (media) {
3171 case DL_ETHER:
3172 /*
3173 * Speed for ethernet links is unbounded. E.g., 802.11b
3174 * links can have a speed of 5.5 Gbps.
3175 */
3176 return (DLADM_STATUS_NOTSUP);
3177
3178 case DL_WIFI:
3179 return (get_rate_common(handle, pdp, linkid, prop_val,
3180 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
3181 default:
3182 return (DLADM_STATUS_BADARG);
3183 }
3184 }
3185
3186 static dladm_status_t
3187 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid,
3188 dladm_wlan_rates_t *rates)
3189 {
3190 int i;
3191 uint_t len;
3192 wl_rates_t *wrp;
3193 dladm_status_t status = DLADM_STATUS_OK;
3194
3195 wrp = malloc(WLDP_BUFSIZE);
3196 if (wrp == NULL)
3197 return (DLADM_STATUS_NOMEM);
3198
3199 bzero(wrp, WLDP_BUFSIZE);
3200 for (i = 0; i < rates->wr_cnt; i++)
3201 wrp->wl_rates_rates[i] = rates->wr_rates[i];
3202 wrp->wl_rates_num = rates->wr_cnt;
3203
3204 len = offsetof(wl_rates_t, wl_rates_rates) +
3205 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
3206 status = i_dladm_wlan_param(handle, linkid, wrp,
3207 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
3208
3209 free(wrp);
3210 return (status);
3211 }
3212
3213 /* ARGSUSED */
3214 static dladm_status_t
3215 set_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3216 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3217 {
3218 dladm_wlan_rates_t rates;
3219 dladm_status_t status;
3220
3221 /*
3222 * can currently set rate on WIFI links only.
3223 */
3224 if (media != DL_WIFI)
3225 return (DLADM_STATUS_PROPRDONLY);
3226
3227 if (val_cnt != 1)
3228 return (DLADM_STATUS_BADVALCNT);
3229
3230 rates.wr_cnt = 1;
3231 rates.wr_rates[0] = vdp[0].vd_val;
3232
3233 status = set_wlan_rate(handle, linkid, &rates);
3234
3235 return (status);
3236 }
3237
3238 /* ARGSUSED */
3239 static dladm_status_t
3240 check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3241 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3242 datalink_media_t media)
3243 {
3244 int i;
3245 uint_t modval_cnt = MAX_SUPPORT_RATES;
3246 char *buf, **modval;
3247 dladm_status_t status;
3248 uint_t perm_flags;
3249 uint_t val_cnt = *val_cntp;
3250 val_desc_t *vdp = *vdpp;
3251
3252 if (val_cnt != 1)
3253 return (DLADM_STATUS_BADVALCNT);
3254
3255 buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
3256 MAX_SUPPORT_RATES);
3257 if (buf == NULL) {
3258 status = DLADM_STATUS_NOMEM;
3259 goto done;
3260 }
3261
3262 modval = (char **)(void *)buf;
3263 for (i = 0; i < MAX_SUPPORT_RATES; i++) {
3264 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
3265 i * DLADM_STRSIZE;
3266 }
3267
3268 status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
3269 media, 0, &perm_flags);
3270 if (status != DLADM_STATUS_OK)
3271 goto done;
3272
3273 for (i = 0; i < modval_cnt; i++) {
3274 if (strcasecmp(*prop_val, modval[i]) == 0) {
3275 vdp->vd_val = (uintptr_t)(uint_t)
3276 (atof(*prop_val) * 2);
3277 status = DLADM_STATUS_OK;
3278 break;
3279 }
3280 }
3281 if (i == modval_cnt)
3282 status = DLADM_STATUS_BADVAL;
3283 done:
3284 free(buf);
3285 return (status);
3286 }
3287
3288 static dladm_status_t
3289 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
3290 int buflen)
3291 {
3292 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
3293 buflen, B_FALSE));
3294 }
3295
3296 /* ARGSUSED */
3297 static dladm_status_t
3298 get_channel(dladm_handle_t handle, prop_desc_t *pdp,
3299 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3300 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3301 {
3302 uint32_t channel;
3303 char buf[WLDP_BUFSIZE];
3304 dladm_status_t status;
3305 wl_phy_conf_t wl_phy_conf;
3306
3307 if ((status = get_phyconf(handle, linkid, buf, sizeof (buf)))
3308 != DLADM_STATUS_OK)
3309 return (status);
3310
3311 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
3312 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel))
3313 return (DLADM_STATUS_NOTFOUND);
3314
3315 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
3316 *val_cnt = 1;
3317 *perm_flags = MAC_PROP_PERM_READ;
3318 return (DLADM_STATUS_OK);
3319 }
3320
3321 /* ARGSUSED */
3322 static dladm_status_t
3323 get_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3324 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3325 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3326 {
3327 wl_ps_mode_t mode;
3328 const char *s;
3329 char buf[WLDP_BUFSIZE];
3330 dladm_status_t status;
3331
3332 if ((status = i_dladm_wlan_param(handle, linkid, buf,
3333 MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3334 return (status);
3335
3336 (void) memcpy(&mode, buf, sizeof (mode));
3337 switch (mode.wl_ps_mode) {
3338 case WL_PM_AM:
3339 s = "off";
3340 break;
3341 case WL_PM_MPS:
3342 s = "max";
3343 break;
3344 case WL_PM_FAST:
3345 s = "fast";
3346 break;
3347 default:
3348 return (DLADM_STATUS_NOTFOUND);
3349 }
3350 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3351 *val_cnt = 1;
3352 *perm_flags = MAC_PROP_PERM_RW;
3353 return (DLADM_STATUS_OK);
3354 }
3355
3356 /* ARGSUSED */
3357 static dladm_status_t
3358 set_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3359 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3360 datalink_media_t media)
3361 {
3362 dladm_wlan_powermode_t powermode = vdp->vd_val;
3363 wl_ps_mode_t ps_mode;
3364
3365 if (val_cnt != 1)
3366 return (DLADM_STATUS_BADVALCNT);
3367
3368 (void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3369
3370 switch (powermode) {
3371 case DLADM_WLAN_PM_OFF:
3372 ps_mode.wl_ps_mode = WL_PM_AM;
3373 break;
3374 case DLADM_WLAN_PM_MAX:
3375 ps_mode.wl_ps_mode = WL_PM_MPS;
3376 break;
3377 case DLADM_WLAN_PM_FAST:
3378 ps_mode.wl_ps_mode = WL_PM_FAST;
3379 break;
3380 default:
3381 return (DLADM_STATUS_NOTSUP);
3382 }
3383 return (i_dladm_wlan_param(handle, linkid, &ps_mode,
3384 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
3385 }
3386
3387 /* ARGSUSED */
3388 static dladm_status_t
3389 get_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3390 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3391 uint_t flags, uint_t *perm_flags)
3392 {
3393 wl_radio_t radio;
3394 const char *s;
3395 char buf[WLDP_BUFSIZE];
3396 dladm_status_t status;
3397
3398 if ((status = i_dladm_wlan_param(handle, linkid, buf,
3399 MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3400 return (status);
3401
3402 (void) memcpy(&radio, buf, sizeof (radio));
3403 switch (radio) {
3404 case B_TRUE:
3405 s = "on";
3406 break;
3407 case B_FALSE:
3408 s = "off";
3409 break;
3410 default:
3411 return (DLADM_STATUS_NOTFOUND);
3412 }
3413 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3414 *val_cnt = 1;
3415 *perm_flags = MAC_PROP_PERM_RW;
3416 return (DLADM_STATUS_OK);
3417 }
3418
3419 /* ARGSUSED */
3420 static dladm_status_t
3421 set_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3422 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3423 {
3424 dladm_wlan_radio_t radio = vdp->vd_val;
3425 wl_radio_t r;
3426
3427 if (val_cnt != 1)
3428 return (DLADM_STATUS_BADVALCNT);
3429
3430 switch (radio) {
3431 case DLADM_WLAN_RADIO_ON:
3432 r = B_TRUE;
3433 break;
3434 case DLADM_WLAN_RADIO_OFF:
3435 r = B_FALSE;
3436 break;
3437 default:
3438 return (DLADM_STATUS_NOTSUP);
3439 }
3440 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
3441 sizeof (r), B_TRUE));
3442 }
3443
3444 /* ARGSUSED */
3445 static dladm_status_t
3446 check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp,
3447 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3448 val_desc_t **vdpp, datalink_media_t media)
3449 {
3450 int32_t hlim;
3451 char *ep;
3452 uint_t val_cnt = *val_cntp;
3453 val_desc_t *vdp = *vdpp;
3454
3455 if (val_cnt != 1)
3456 return (DLADM_STATUS_BADVALCNT);
3457
3458 errno = 0;
3459 hlim = strtol(*prop_val, &ep, 10);
3460 if (errno != 0 || ep == *prop_val || hlim < 1 ||
3461 hlim > (int32_t)UINT8_MAX)
3462 return (DLADM_STATUS_BADVAL);
3463 vdp->vd_val = hlim;
3464 return (DLADM_STATUS_OK);
3465 }
3466
3467 /* ARGSUSED */
3468 static dladm_status_t
3469 check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3470 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3471 datalink_media_t media)
3472 {
3473 int32_t elim;
3474 char *ep;
3475 uint_t val_cnt = *val_cntp;
3476 val_desc_t *vdp = *vdpp;
3477
3478 if (media != DL_IPV6)
3479 return (DLADM_STATUS_BADARG);
3480
3481 if (val_cnt != 1)
3482 return (DLADM_STATUS_BADVALCNT);
3483
3484 errno = 0;
3485 elim = strtol(*prop_val, &ep, 10);
3486 if (errno != 0 || ep == *prop_val || elim < 0 ||
3487 elim > (int32_t)UINT8_MAX)
3488 return (DLADM_STATUS_BADVAL);
3489 vdp->vd_val = elim;
3490 return (DLADM_STATUS_OK);
3491 }
3492
3493 static dladm_status_t
3494 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3495 const char *prop_name, char **prop_val, uint_t val_cnt)
3496 {
3497 char buf[MAXLINELEN];
3498 int i;
3499 dladm_conf_t conf;
3500 dladm_status_t status;
3501
3502 status = dladm_open_conf(handle, linkid, &conf);
3503 if (status != DLADM_STATUS_OK)
3504 return (status);
3505
3506 /*
3507 * reset case.
3508 */
3509 if (val_cnt == 0) {
3510 status = dladm_unset_conf_field(handle, conf, prop_name);
3511 if (status == DLADM_STATUS_OK)
3512 status = dladm_write_conf(handle, conf);
3513 goto done;
3514 }
3515
3516 buf[0] = '\0';
3517 for (i = 0; i < val_cnt; i++) {
3518 (void) strlcat(buf, prop_val[i], MAXLINELEN);
3519 if (i != val_cnt - 1)
3520 (void) strlcat(buf, ",", MAXLINELEN);
3521 }
3522
3523 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
3524 buf);
3525 if (status == DLADM_STATUS_OK)
3526 status = dladm_write_conf(handle, conf);
3527
3528 done:
3529 dladm_destroy_conf(handle, conf);
3530 return (status);
3531 }
3532
3533 static dladm_status_t
3534 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3535 const char *prop_name, char **prop_val, uint_t *val_cntp)
3536 {
3537 char buf[MAXLINELEN], *str;
3538 uint_t cnt = 0;
3539 dladm_conf_t conf;
3540 dladm_status_t status;
3541
3542 status = dladm_getsnap_conf(handle, linkid, &conf);
3543 if (status != DLADM_STATUS_OK)
3544 return (status);
3545
3546 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
3547 if (status != DLADM_STATUS_OK)
3548 goto done;
3549
3550 str = strtok(buf, ",");
3551 while (str != NULL) {
3552 if (cnt == *val_cntp) {
3553 status = DLADM_STATUS_TOOSMALL;
3554 goto done;
3555 }
3556 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
3557 str = strtok(NULL, ",");
3558 }
3559
3560 *val_cntp = cnt;
3561
3562 done:
3563 dladm_destroy_conf(handle, conf);
3564 return (status);
3565 }
3566
3567 /*
3568 * Walk persistent private link properties of a link.
3569 */
3570 static dladm_status_t
3571 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
3572 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
3573 {
3574 dladm_status_t status;
3575 dladm_conf_t conf;
3576 char last_attr[MAXLINKATTRLEN];
3577 char attr[MAXLINKATTRLEN];
3578 char attrval[MAXLINKATTRVALLEN];
3579 size_t attrsz;
3580
3581 if (linkid == DATALINK_INVALID_LINKID || func == NULL)
3582 return (DLADM_STATUS_BADARG);
3583
3584 status = dladm_getsnap_conf(handle, linkid, &conf);
3585 if (status != DLADM_STATUS_OK)
3586 return (status);
3587
3588 last_attr[0] = '\0';
3589 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
3590 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
3591 if (attr[0] == '_') {
3592 if (func(handle, linkid, attr, arg) ==
3593 DLADM_WALK_TERMINATE)
3594 break;
3595 }
3596 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
3597 }
3598
3599 dladm_destroy_conf(handle, conf);
3600 return (DLADM_STATUS_OK);
3601 }
3602
3603 static link_attr_t *
3604 dladm_name2prop(const char *prop_name)
3605 {
3606 link_attr_t *p;
3607
3608 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3609 if (strcmp(p->pp_name, prop_name) == 0)
3610 break;
3611 }
3612 return (p);
3613 }
3614
3615 static link_attr_t *
3616 dladm_id2prop(mac_prop_id_t propid)
3617 {
3618 link_attr_t *p;
3619
3620 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3621 if (p->pp_id == propid)
3622 break;
3623 }
3624 return (p);
3625 }
3626
3627 static dld_ioc_macprop_t *
3628 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
3629 const char *prop_name, mac_prop_id_t propid, uint_t flags,
3630 dladm_status_t *status)
3631 {
3632 int dsize;
3633 dld_ioc_macprop_t *dip;
3634
3635 *status = DLADM_STATUS_OK;
3636 dsize = MAC_PROP_BUFSIZE(valsize);
3637 dip = malloc(dsize);
3638 if (dip == NULL) {
3639 *status = DLADM_STATUS_NOMEM;
3640 return (NULL);
3641 }
3642 bzero(dip, dsize);
3643 dip->pr_valsize = valsize;
3644 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
3645 dip->pr_linkid = linkid;
3646 dip->pr_num = propid;
3647 dip->pr_flags = flags;
3648 return (dip);
3649 }
3650
3651 static dld_ioc_macprop_t *
3652 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
3653 const char *prop_name, uint_t flags, dladm_status_t *status)
3654 {
3655 link_attr_t *p;
3656
3657 p = dladm_name2prop(prop_name);
3658 valsize = MAX(p->pp_valsize, valsize);
3659 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
3660 flags, status));
3661 }
3662
3663 static dld_ioc_macprop_t *
3664 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
3665 mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
3666 {
3667 link_attr_t *p;
3668
3669 p = dladm_id2prop(propid);
3670 valsize = MAX(p->pp_valsize, valsize);
3671 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
3672 flags, status));
3673 }
3674
3675 /* ARGSUSED */
3676 static dladm_status_t
3677 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
3678 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3679 datalink_media_t media)
3680 {
3681 dld_ioc_macprop_t *dip;
3682 dladm_status_t status = DLADM_STATUS_OK;
3683 uint8_t u8;
3684 uint16_t u16;
3685 uint32_t u32;
3686 void *val;
3687
3688 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
3689 if (dip == NULL)
3690 return (status);
3691
3692 if (pdp->pd_flags & PD_CHECK_ALLOC)
3693 val = (void *)vdp->vd_val;
3694 else {
3695 /*
3696 * Currently all 1/2/4-byte size properties are byte/word/int.
3697 * No need (yet) to distinguish these from arrays of same size.
3698 */
3699 switch (dip->pr_valsize) {
3700 case 1:
3701 u8 = vdp->vd_val;
3702 val = &u8;
3703 break;
3704 case 2:
3705 u16 = vdp->vd_val;
3706 val = &u16;
3707 break;
3708 case 4:
3709 u32 = vdp->vd_val;
3710 val = &u32;
3711 break;
3712 default:
3713 val = &vdp->vd_val;
3714 break;
3715 }
3716 }
3717
3718 if (val != NULL)
3719 (void) memcpy(dip->pr_val, val, dip->pr_valsize);
3720 else
3721 dip->pr_valsize = 0;
3722
3723 status = i_dladm_macprop(handle, dip, B_TRUE);
3724
3725 done:
3726 free(dip);
3727 return (status);
3728 }
3729
3730 dladm_status_t
3731 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
3732 {
3733 dladm_status_t status = DLADM_STATUS_OK;
3734
3735 if (ioctl(dladm_dld_fd(handle),
3736 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
3737 status = dladm_errno2status(errno);
3738
3739 return (status);
3740 }
3741
3742 static dladm_status_t
3743 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
3744 char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size)
3745 {
3746 dld_ioc_macprop_t *dip;
3747 dladm_status_t status;
3748
3749 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status);
3750 if (dip == NULL)
3751 return (DLADM_STATUS_NOMEM);
3752
3753 status = i_dladm_macprop(handle, dip, B_FALSE);
3754 if (status != DLADM_STATUS_OK) {
3755 free(dip);
3756 return (status);
3757 }
3758
3759 if (perm_flags != NULL)
3760 *perm_flags = dip->pr_perm_flags;
3761
3762 if (arg != NULL)
3763 (void) memcpy(arg, dip->pr_val, size);
3764 free(dip);
3765 return (DLADM_STATUS_OK);
3766 }
3767
3768 /* ARGSUSED */
3769 static dladm_status_t
3770 check_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3771 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3772 val_desc_t **vp, datalink_media_t media)
3773 {
3774 uint_t val_cnt = *val_cntp;
3775 val_desc_t *v = *vp;
3776
3777 if (val_cnt != 1)
3778 return (DLADM_STATUS_BADVAL);
3779 v->vd_val = strtoul(prop_val[0], NULL, 0);
3780 return (DLADM_STATUS_OK);
3781 }
3782
3783 /* ARGSUSED */
3784 static dladm_status_t
3785 get_duplex(dladm_handle_t handle, prop_desc_t *pdp,
3786 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3787 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3788 {
3789 link_duplex_t link_duplex;
3790 dladm_status_t status;
3791
3792 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
3793 KSTAT_DATA_UINT32, &link_duplex)) != 0)
3794 return (status);
3795
3796 switch (link_duplex) {
3797 case LINK_DUPLEX_FULL:
3798 (void) strcpy(*prop_val, "full");
3799 break;
3800 case LINK_DUPLEX_HALF:
3801 (void) strcpy(*prop_val, "half");
3802 break;
3803 default:
3804 (void) strcpy(*prop_val, "unknown");
3805 break;
3806 }
3807 *val_cnt = 1;
3808 return (DLADM_STATUS_OK);
3809 }
3810
3811 /* ARGSUSED */
3812 static dladm_status_t
3813 get_speed(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3814 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
3815 uint_t *perm_flags)
3816 {
3817 uint64_t ifspeed = 0;
3818 dladm_status_t status;
3819
3820 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
3821 KSTAT_DATA_UINT64, &ifspeed)) != 0)
3822 return (status);
3823
3824 if ((ifspeed % 1000000) != 0) {
3825 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3826 "%llf", ifspeed / (float)1000000); /* Mbps */
3827 } else {
3828 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3829 "%llu", ifspeed / 1000000); /* Mbps */
3830 }
3831 *val_cnt = 1;
3832 *perm_flags = MAC_PROP_PERM_READ;
3833 return (DLADM_STATUS_OK);
3834 }
3835
3836 /* ARGSUSED */
3837 static dladm_status_t
3838 get_link_state(dladm_handle_t handle, prop_desc_t *pdp,
3839 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3840 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3841 {
3842 link_state_t link_state;
3843 dladm_status_t status;
3844
3845 status = dladm_get_state(handle, linkid, &link_state);
3846 if (status != DLADM_STATUS_OK)
3847 return (status);
3848
3849 switch (link_state) {
3850 case LINK_STATE_UP:
3851 (void) strcpy(*prop_val, "up");
3852 break;
3853 case LINK_STATE_DOWN:
3854 (void) strcpy(*prop_val, "down");
3855 break;
3856 default:
3857 (void) strcpy(*prop_val, "unknown");
3858 break;
3859 }
3860 *val_cnt = 1;
3861 *perm_flags = MAC_PROP_PERM_READ;
3862 return (DLADM_STATUS_OK);
3863 }
3864
3865 /* ARGSUSED */
3866 static dladm_status_t
3867 get_binary(dladm_handle_t handle, prop_desc_t *pdp,
3868 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3869 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3870 {
3871 dladm_status_t status;
3872 uint_t v = 0;
3873
3874 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3875 perm_flags, &v, sizeof (v));
3876 if (status != DLADM_STATUS_OK)
3877 return (status);
3878
3879 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0));
3880 *val_cnt = 1;
3881 return (DLADM_STATUS_OK);
3882 }
3883
3884 /* ARGSUSED */
3885 static dladm_status_t
3886 get_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3887 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3888 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3889 {
3890 dladm_status_t status;
3891 uint32_t v = 0;
3892
3893 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3894 perm_flags, &v, sizeof (v));
3895 if (status != DLADM_STATUS_OK)
3896 return (status);
3897
3898 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
3899 *val_cnt = 1;
3900 return (DLADM_STATUS_OK);
3901 }
3902
3903 /* ARGSUSED */
3904 static dladm_status_t
3905 get_range(dladm_handle_t handle, prop_desc_t *pdp,
3906 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3907 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3908 {
3909 dld_ioc_macprop_t *dip;
3910 dladm_status_t status = DLADM_STATUS_OK;
3911 size_t sz;
3912 uint_t rcount;
3913 mac_propval_range_t *rangep;
3914
3915 /*
3916 * As caller we don't know number of value ranges, the driver
3917 * supports. To begin with we assume that number to be 1. If the
3918 * buffer size is insufficient, driver returns back with the
3919 * actual count of value ranges. See mac.h for more details.
3920 */
3921 sz = sizeof (mac_propval_range_t);
3922 rcount = 1;
3923 retry:
3924 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
3925 &status)) == NULL)
3926 return (status);
3927
3928 rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
3929 rangep->mpr_count = rcount;
3930
3931 status = i_dladm_macprop(handle, dip, B_FALSE);
3932 if (status != DLADM_STATUS_OK) {
3933 if (status == DLADM_STATUS_TOOSMALL) {
3934 int err;
3935
3936 if ((err = i_dladm_range_size(rangep, &sz, &rcount))
3937 == 0) {
3938 free(dip);
3939 goto retry;
3940 } else {
3941 status = dladm_errno2status(err);
3942 }
3943 }
3944 free(dip);
3945 return (status);
3946 }
3947
3948 if (rangep->mpr_count == 0) {
3949 *val_cnt = 1;
3950 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--");
3951 goto done;
3952 }
3953
3954 switch (rangep->mpr_type) {
3955 case MAC_PROPVAL_UINT32: {
3956 mac_propval_uint32_range_t *ur;
3957 uint_t count = rangep->mpr_count, i;
3958
3959 ur = &rangep->mpr_range_uint32[0];
3960
3961 for (i = 0; i < count; i++, ur++) {
3962 if (ur->mpur_min == ur->mpur_max) {
3963 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
3964 "%ld", ur->mpur_min);
3965 } else {
3966 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
3967 "%ld-%ld", ur->mpur_min, ur->mpur_max);
3968 }
3969 }
3970 *val_cnt = count;
3971 break;
3972 }
3973 default:
3974 status = DLADM_STATUS_BADARG;
3975 break;
3976 }
3977 done:
3978 free(dip);
3979 return (status);
3980 }
3981
3982 /* ARGSUSED */
3983 static dladm_status_t
3984 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp,
3985 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3986 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3987 {
3988 link_tagmode_t mode;
3989 dladm_status_t status;
3990
3991 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3992 perm_flags, &mode, sizeof (mode));
3993 if (status != DLADM_STATUS_OK)
3994 return (status);
3995
3996 switch (mode) {
3997 case LINK_TAGMODE_NORMAL:
3998 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX);
3999 break;
4000 case LINK_TAGMODE_VLANONLY:
4001 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX);
4002 break;
4003 default:
4004 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX);
4005 }
4006 *val_cnt = 1;
4007 return (DLADM_STATUS_OK);
4008 }
4009
4010 /* ARGSUSED */
4011 static dladm_status_t
4012 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp,
4013 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4014 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4015 {
4016 link_flowctrl_t v;
4017 dladm_status_t status;
4018
4019 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4020 perm_flags, &v, sizeof (v));
4021 if (status != DLADM_STATUS_OK)
4022 return (status);
4023
4024 switch (v) {
4025 case LINK_FLOWCTRL_NONE:
4026 (void) sprintf(*prop_val, "no");
4027 break;
4028 case LINK_FLOWCTRL_RX:
4029 (void) sprintf(*prop_val, "rx");
4030 break;
4031 case LINK_FLOWCTRL_TX:
4032 (void) sprintf(*prop_val, "tx");
4033 break;
4034 case LINK_FLOWCTRL_BI:
4035 (void) sprintf(*prop_val, "bi");
4036 break;
4037 }
4038 *val_cnt = 1;
4039 return (DLADM_STATUS_OK);
4040 }
4041
4042
4043 /* ARGSUSED */
4044 static dladm_status_t
4045 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid,
4046 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
4047
4048 {
4049 int i, slen;
4050 int bufsize = 0;
4051 dld_ioc_macprop_t *dip = NULL;
4052 uchar_t *dp;
4053 link_attr_t *p;
4054 dladm_status_t status = DLADM_STATUS_OK;
4055
4056 if ((prop_name == NULL && prop_val != NULL) ||
4057 (prop_val != NULL && val_cnt == 0))
4058 return (DLADM_STATUS_BADARG);
4059 p = dladm_name2prop(prop_name);
4060 if (p->pp_id != MAC_PROP_PRIVATE)
4061 return (DLADM_STATUS_BADARG);
4062
4063 if (!(flags & DLADM_OPT_ACTIVE))
4064 return (DLADM_STATUS_OK);
4065
4066 /*
4067 * private properties: all parsing is done in the kernel.
4068 * allocate a enough space for each property + its separator (',').
4069 */
4070 for (i = 0; i < val_cnt; i++) {
4071 bufsize += strlen(prop_val[i]) + 1;
4072 }
4073
4074 if (prop_val == NULL) {
4075 /*
4076 * getting default value. so use more buffer space.
4077 */
4078 bufsize += DLADM_PROP_BUF_CHUNK;
4079 }
4080
4081 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
4082 (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status);
4083 if (dip == NULL)
4084 return (status);
4085
4086 dp = (uchar_t *)dip->pr_val;
4087 slen = 0;
4088
4089 if (prop_val == NULL) {
4090 status = i_dladm_macprop(handle, dip, B_FALSE);
4091 dip->pr_flags = 0;
4092 } else {
4093 for (i = 0; i < val_cnt; i++) {
4094 int plen = 0;
4095
4096 plen = strlen(prop_val[i]);
4097 bcopy(prop_val[i], dp, plen);
4098 slen += plen;
4099 /*
4100 * add a "," separator and update dp.
4101 */
4102 if (i != (val_cnt -1))
4103 dp[slen++] = ',';
4104 dp += (plen + 1);
4105 }
4106 }
4107 if (status == DLADM_STATUS_OK)
4108 status = i_dladm_macprop(handle, dip, B_TRUE);
4109
4110 free(dip);
4111 return (status);
4112 }
4113
4114 static dladm_status_t
4115 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
4116 const char *prop_name, char **prop_val, uint_t *val_cnt,
4117 dladm_prop_type_t type, uint_t dld_flags)
4118 {
4119 dladm_status_t status = DLADM_STATUS_OK;
4120 dld_ioc_macprop_t *dip = NULL;
4121 link_attr_t *p;
4122
4123 if ((prop_name == NULL && prop_val != NULL) ||
4124 (prop_val != NULL && val_cnt == 0))
4125 return (DLADM_STATUS_BADARG);
4126
4127 p = dladm_name2prop(prop_name);
4128 if (p->pp_id != MAC_PROP_PRIVATE)
4129 return (DLADM_STATUS_BADARG);
4130
4131 /*
4132 * private properties: all parsing is done in the kernel.
4133 */
4134 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
4135 dld_flags, &status);
4136 if (dip == NULL)
4137 return (status);
4138
4139 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
4140 DLADM_STATUS_OK) {
4141 if (type == DLADM_PROP_VAL_PERM) {
4142 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
4143 } else if (type == DLADM_PROP_VAL_MODIFIABLE) {
4144 *prop_val[0] = '\0';
4145 } else {
4146 (void) strncpy(*prop_val, dip->pr_val,
4147 DLADM_PROP_VAL_MAX);
4148 }
4149 *val_cnt = 1;
4150 } else if ((status == DLADM_STATUS_NOTSUP) &&
4151 (type == DLADM_PROP_VAL_CURRENT)) {
4152 status = DLADM_STATUS_NOTFOUND;
4153 }
4154 free(dip);
4155 return (status);
4156 }
4157
4158
4159 static dladm_status_t
4160 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
4161 datalink_id_t linkid, datalink_media_t media, uint_t flags)
4162 {
4163 dladm_status_t status;
4164 char **prop_vals = NULL, *buf;
4165 size_t bufsize;
4166 uint_t cnt;
4167 int i;
4168 uint_t perm_flags;
4169
4170 /*
4171 * Allocate buffer needed for prop_vals array. We can have at most
4172 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
4173 * each entry has max size DLADM_PROP_VAL_MAX
4174 */
4175 bufsize =
4176 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
4177 buf = malloc(bufsize);
4178 prop_vals = (char **)(void *)buf;
4179 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
4180 prop_vals[i] = buf +
4181 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4182 i * DLADM_PROP_VAL_MAX;
4183 }
4184
4185 /*
4186 * For properties which have pdp->pd_defval.vd_name as a non-empty
4187 * string, the "" itself is used to reset the property (exceptions
4188 * are zone and autopush, which populate vdp->vd_val). So
4189 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
4190 * down on the setprop using the global values in the table. For
4191 * other cases (vd_name is ""), doing reset-linkprop will cause
4192 * libdladm to do a getprop to find the default value and then do
4193 * a setprop to reset the value to default.
4194 */
4195 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
4196 DLD_PROP_DEFAULT, &perm_flags);
4197 if (status == DLADM_STATUS_OK) {
4198 if (perm_flags == MAC_PROP_PERM_RW) {
4199 status = i_dladm_set_single_prop(handle, linkid,
4200 pdp->pd_class, media, pdp, prop_vals, cnt, flags);
4201 }
4202 else
4203 status = DLADM_STATUS_NOTSUP;
4204 }
4205 free(buf);
4206 return (status);
4207 }
4208
4209 /* ARGSUSED */
4210 static dladm_status_t
4211 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid,
4212 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
4213 uint_t *perm_flags)
4214 {
4215 const bridge_public_prop_t *bpp;
4216 dladm_status_t retv;
4217 int val, i;
4218
4219 if (flags != 0)
4220 return (DLADM_STATUS_NOTSUP);
4221 *perm_flags = MAC_PROP_PERM_RW;
4222 *val_cnt = 1;
4223 for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++)
4224 if (strcmp(bpp->bpp_name, pd->pd_name) == 0)
4225 break;
4226 retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val);
4227 /* If the daemon isn't running, then return the persistent value */
4228 if (retv == DLADM_STATUS_NOTFOUND) {
4229 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4230 prop_val, val_cnt) != DLADM_STATUS_OK)
4231 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4232 DLADM_PROP_VAL_MAX);
4233 return (DLADM_STATUS_OK);
4234 }
4235 if (retv != DLADM_STATUS_OK) {
4236 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4237 return (retv);
4238 }
4239 if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') {
4240 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4241 DLADM_PROP_VAL_MAX);
4242 return (DLADM_STATUS_OK);
4243 }
4244 for (i = 0; i < pd->pd_noptval; i++) {
4245 if (val == pd->pd_optval[i].vd_val) {
4246 (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name,
4247 DLADM_PROP_VAL_MAX);
4248 return (DLADM_STATUS_OK);
4249 }
4250 }
4251 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val);
4252 return (DLADM_STATUS_OK);
4253 }
4254
4255 /* ARGSUSED1 */
4256 static dladm_status_t
4257 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4258 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4259 {
4260 /*
4261 * Special case for mcheck: the daemon resets the value to zero, and we
4262 * don't want the daemon to refresh itself; it leads to deadlock.
4263 */
4264 if (flags & DLADM_OPT_NOREFRESH)
4265 return (DLADM_STATUS_OK);
4266
4267 /* Tell the running daemon, if any */
4268 return (dladm_bridge_refresh(handle, linkid));
4269 }
4270
4271 /*
4272 * This is used only for stp_priority, stp_cost, and stp_mcheck.
4273 */
4274 /* ARGSUSED */
4275 static dladm_status_t
4276 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd,
4277 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4278 val_desc_t **vdpp, datalink_media_t media)
4279 {
4280 char *cp;
4281 boolean_t iscost;
4282 uint_t val_cnt = *val_cntp;
4283 val_desc_t *vdp = *vdpp;
4284
4285 if (val_cnt != 1)
4286 return (DLADM_STATUS_BADVALCNT);
4287
4288 if (prop_val == NULL) {
4289 vdp->vd_val = 0;
4290 } else {
4291 /* Only stp_priority and stp_cost use this function */
4292 iscost = strcmp(pd->pd_name, "stp_cost") == 0;
4293
4294 if (iscost && strcmp(prop_val[0], "auto") == 0) {
4295 /* Illegal value 0 is allowed to mean "automatic" */
4296 vdp->vd_val = 0;
4297 } else {
4298 errno = 0;
4299 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4300 if (errno != 0 || *cp != '\0')
4301 return (DLADM_STATUS_BADVAL);
4302 }
4303 }
4304
4305 if (iscost) {
4306 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL :
4307 DLADM_STATUS_OK);
4308 } else {
4309 if (vdp->vd_val > 255)
4310 return (DLADM_STATUS_BADVAL);
4311 /*
4312 * If the user is setting stp_mcheck non-zero, then (per the
4313 * IEEE management standards and UNH testing) we need to check
4314 * whether this link is part of a bridge that is running RSTP.
4315 * If it's not, then setting the flag is an error. Note that
4316 * errors are intentionally discarded here; it's the value
4317 * that's the problem -- it's not a bad value, merely one that
4318 * can't be used now.
4319 */
4320 if (strcmp(pd->pd_name, "stp_mcheck") == 0 &&
4321 vdp->vd_val != 0) {
4322 char bridge[MAXLINKNAMELEN];
4323 UID_STP_CFG_T cfg;
4324 dladm_bridge_prot_t brprot;
4325
4326 if (dladm_bridge_getlink(handle, linkid, bridge,
4327 sizeof (bridge)) != DLADM_STATUS_OK ||
4328 dladm_bridge_get_properties(bridge, &cfg,
4329 &brprot) != DLADM_STATUS_OK)
4330 return (DLADM_STATUS_FAILED);
4331 if (cfg.force_version <= 1)
4332 return (DLADM_STATUS_FAILED);
4333 }
4334 return (DLADM_STATUS_OK);
4335 }
4336 }
4337
4338 /* ARGSUSED */
4339 static dladm_status_t
4340 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd,
4341 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4342 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4343 {
4344 dladm_status_t retv;
4345 uint_t val;
4346
4347 if (flags != 0)
4348 return (DLADM_STATUS_NOTSUP);
4349 *perm_flags = MAC_PROP_PERM_RW;
4350 *val_cnt = 1;
4351 retv = dladm_bridge_get_forwarding(handle, linkid, &val);
4352 if (retv == DLADM_STATUS_NOTFOUND) {
4353 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4354 prop_val, val_cnt) != DLADM_STATUS_OK)
4355 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4356 DLADM_PROP_VAL_MAX);
4357 return (DLADM_STATUS_OK);
4358 }
4359 if (retv == DLADM_STATUS_OK)
4360 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val);
4361 else
4362 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4363 return (retv);
4364 }
4365
4366 /* ARGSUSED */
4367 static dladm_status_t
4368 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4369 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4370 {
4371 /* Tell the running daemon, if any */
4372 return (dladm_bridge_refresh(handle, linkid));
4373 }
4374
4375 /* ARGSUSED */
4376 static dladm_status_t
4377 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4378 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4379 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4380 {
4381 dladm_status_t status;
4382 dld_ioc_macprop_t *dip;
4383 uint16_t pvid;
4384
4385 if (flags != 0)
4386 return (DLADM_STATUS_NOTSUP);
4387 *perm_flags = MAC_PROP_PERM_RW;
4388 *val_cnt = 1;
4389 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4390 0, &status);
4391 if (dip == NULL)
4392 return (status);
4393 status = i_dladm_macprop(handle, dip, B_FALSE);
4394 if (status == DLADM_STATUS_OK) {
4395 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid));
4396 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid);
4397 } else {
4398 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4399 }
4400 free(dip);
4401 return (status);
4402 }
4403
4404 /* ARGSUSED */
4405 static dladm_status_t
4406 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4407 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4408 {
4409 dladm_status_t status;
4410 dld_ioc_macprop_t *dip;
4411 uint16_t pvid;
4412
4413 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4414 0, &status);
4415 if (dip == NULL)
4416 return (status);
4417 pvid = vdp->vd_val;
4418 (void) memcpy(dip->pr_val, &pvid, sizeof (pvid));
4419 status = i_dladm_macprop(handle, dip, B_TRUE);
4420 free(dip);
4421 if (status != DLADM_STATUS_OK)
4422 return (status);
4423
4424 /* Tell the running daemon, if any */
4425 return (dladm_bridge_refresh(handle, linkid));
4426 }
4427
4428 /* ARGSUSED */
4429 static dladm_status_t
4430 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4431 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4432 val_desc_t **vdpp, datalink_media_t media)
4433 {
4434 char *cp;
4435 uint_t val_cnt = *val_cntp;
4436 val_desc_t *vdp = *vdpp;
4437
4438 if (val_cnt != 1)
4439 return (DLADM_STATUS_BADVALCNT);
4440
4441 if (prop_val == NULL) {
4442 vdp->vd_val = 1;
4443 } else {
4444 errno = 0;
4445 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4446 if (errno != 0 || *cp != '\0')
4447 return (DLADM_STATUS_BADVAL);
4448 }
4449
4450 return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL :
4451 DLADM_STATUS_OK);
4452 }
4453
4454 dladm_status_t
4455 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
4456 mac_prop_id_t cmd, size_t len, boolean_t set)
4457 {
4458 uint32_t flags;
4459 dladm_status_t status;
4460 uint32_t media;
4461 dld_ioc_macprop_t *dip;
4462 void *dp;
4463
4464 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
4465 &media, NULL, 0)) != DLADM_STATUS_OK) {
4466 return (status);
4467 }
4468
4469 if (media != DL_WIFI)
4470 return (DLADM_STATUS_BADARG);
4471
4472 if (!(flags & DLADM_OPT_ACTIVE))
4473 return (DLADM_STATUS_TEMPONLY);
4474
4475 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
4476 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
4477
4478 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
4479 if (dip == NULL)
4480 return (DLADM_STATUS_NOMEM);
4481
4482 dp = (uchar_t *)dip->pr_val;
4483 if (set)
4484 (void) memcpy(dp, buf, len);
4485
4486 status = i_dladm_macprop(handle, dip, set);
4487 if (status == DLADM_STATUS_OK) {
4488 if (!set)
4489 (void) memcpy(buf, dp, len);
4490 }
4491
4492 free(dip);
4493 return (status);
4494 }
4495
4496 dladm_status_t
4497 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
4498 {
4499 return (dladm_parse_args(str, listp, novalues));
4500 }
4501
4502 /*
4503 * Retrieve the one link property from the database
4504 */
4505 /*ARGSUSED*/
4506 static int
4507 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
4508 const char *prop_name, void *arg)
4509 {
4510 dladm_arg_list_t *proplist = arg;
4511 dladm_arg_info_t *aip = NULL;
4512
4513 aip = &proplist->al_info[proplist->al_count];
4514 /*
4515 * it is fine to point to prop_name since prop_name points to the
4516 * prop_table[n].pd_name.
4517 */
4518 aip->ai_name = prop_name;
4519
4520 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
4521 prop_name, aip->ai_val, &aip->ai_count);
4522
4523 if (aip->ai_count != 0)
4524 proplist->al_count++;
4525
4526 return (DLADM_WALK_CONTINUE);
4527 }
4528
4529
4530 /*
4531 * Retrieve all link properties for a link from the database and
4532 * return a property list.
4533 */
4534 dladm_status_t
4535 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
4536 dladm_arg_list_t **listp)
4537 {
4538 dladm_arg_list_t *list;
4539 dladm_status_t status = DLADM_STATUS_OK;
4540
4541 list = calloc(1, sizeof (dladm_arg_list_t));
4542 if (list == NULL)
4543 return (dladm_errno2status(errno));
4544
4545 status = dladm_walk_linkprop(handle, linkid, list,
4546 i_dladm_get_one_prop);
4547
4548 *listp = list;
4549 return (status);
4550 }
4551
4552 /*
4553 * Retrieve the named property from a proplist, check the value and
4554 * convert to a kernel structure.
4555 */
4556 static dladm_status_t
4557 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
4558 dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg)
4559 {
4560 dladm_status_t status;
4561 dladm_arg_info_t *aip = NULL;
4562 int i, j;
4563
4564 /* Find named property in proplist */
4565 for (i = 0; i < proplist->al_count; i++) {
4566 aip = &proplist->al_info[i];
4567 if (strcasecmp(aip->ai_name, name) == 0)
4568 break;
4569 }
4570
4571 /* Property not in list */
4572 if (i == proplist->al_count)
4573 return (DLADM_STATUS_OK);
4574
4575 for (i = 0; i < DLADM_MAX_PROPS; i++) {
4576 prop_desc_t *pdp = &prop_table[i];
4577 val_desc_t *vdp;
4578
4579 vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
4580 if (vdp == NULL)
4581 return (DLADM_STATUS_NOMEM);
4582
4583 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
4584 continue;
4585
4586 if (aip->ai_val == NULL)
4587 return (DLADM_STATUS_BADARG);
4588
4589 /* Check property value */
4590 if (pdp->pd_check != NULL) {
4591 status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
4592 &(aip->ai_count), flags, &vdp, 0);
4593 } else {
4594 status = DLADM_STATUS_BADARG;
4595 }
4596
4597 if (status != DLADM_STATUS_OK)
4598 return (status);
4599
4600 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
4601 resource_prop_t *rpp = &rsrc_prop_table[j];
4602
4603 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
4604 continue;
4605
4606 /* Extract kernel structure */
4607 if (rpp->rp_extract != NULL) {
4608 status = rpp->rp_extract(vdp,
4609 aip->ai_count, arg);
4610 } else {
4611 status = DLADM_STATUS_BADARG;
4612 }
4613 break;
4614 }
4615
4616 if (status != DLADM_STATUS_OK)
4617 return (status);
4618
4619 break;
4620 }
4621 return (status);
4622 }
4623
4624 /*
4625 * Extract properties from a proplist and convert to mac_resource_props_t.
4626 */
4627 dladm_status_t
4628 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
4629 mac_resource_props_t *mrp, uint_t flags)
4630 {
4631 dladm_status_t status;
4632 int i;
4633
4634 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
4635 status = i_dladm_link_proplist_extract_one(handle,
4636 proplist, rsrc_prop_table[i].rp_name, flags, mrp);
4637 if (status != DLADM_STATUS_OK)
4638 return (status);
4639 }
4640 return (status);
4641 }
4642
4643 static const char *
4644 dladm_perm2str(uint_t perm, char *buf)
4645 {
4646 (void) snprintf(buf, DLADM_STRSIZE, "%c%c",
4647 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
4648 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
4649 return (buf);
4650 }
4651
4652 dladm_status_t
4653 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
4654 link_state_t *state)
4655 {
4656 uint_t perms;
4657
4658 return (i_dladm_get_public_prop(handle, linkid, "state", 0,
4659 &perms, state, sizeof (*state)));
4660 }
4661
4662 boolean_t
4663 dladm_attr_is_linkprop(const char *name)
4664 {
4665 /* non-property attribute names */
4666 const char *nonprop[] = {
4667 /* dlmgmtd core attributes */
4668 "name",
4669 "class",
4670 "media",
4671 FPHYMAJ,
4672 FPHYINST,
4673 FDEVNAME,
4674
4675 /* other attributes for vlan, aggr, etc */
4676 DLADM_ATTR_NAMES
4677 };
4678 boolean_t is_nonprop = B_FALSE;
4679 int i;
4680
4681 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
4682 if (strcmp(name, nonprop[i]) == 0) {
4683 is_nonprop = B_TRUE;
4684 break;
4685 }
4686 }
4687
4688 return (!is_nonprop);
4689 }
4690
4691 dladm_status_t
4692 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid,
4693 dladm_prop_type_t type, const char *prop_name, boolean_t *is_set)
4694 {
4695 char *buf, **propvals;
4696 uint_t valcnt = DLADM_MAX_PROP_VALCNT;
4697 int i;
4698 dladm_status_t status = DLADM_STATUS_OK;
4699 size_t bufsize;
4700
4701 *is_set = B_FALSE;
4702
4703 bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) *
4704 DLADM_MAX_PROP_VALCNT;
4705 if ((buf = calloc(1, bufsize)) == NULL)
4706 return (DLADM_STATUS_NOMEM);
4707
4708 propvals = (char **)(void *)buf;
4709 for (i = 0; i < valcnt; i++) {
4710 propvals[i] = buf +
4711 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4712 i * DLADM_PROP_VAL_MAX;
4713 }
4714
4715 if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals,
4716 &valcnt) != DLADM_STATUS_OK) {
4717 goto done;
4718 }
4719
4720 /*
4721 * valcnt is always set to 1 by get_pool(), hence we need to check
4722 * for a non-null string to see if it is set. For protection,
4723 * secondary-macs and allowed-ips, we can check either the *propval
4724 * or the valcnt.
4725 */
4726 if ((strcmp(prop_name, "pool") == 0 ||
4727 strcmp(prop_name, "protection") == 0 ||
4728 strcmp(prop_name, "secondary-macs") == 0 ||
4729 strcmp(prop_name, "allowed-ips") == 0) &&
4730 (strlen(*propvals) != 0)) {
4731 *is_set = B_TRUE;
4732 } else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) {
4733 *is_set = B_TRUE;
4734 } else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) &&
4735 (strcmp(propvals[0], "true") == 0)) {
4736 *is_set = B_TRUE;
4737 }
4738
4739 done:
4740 if (buf != NULL)
4741 free(buf);
4742 return (status);
4743 }
4744
4745 /* ARGSUSED */
4746 static dladm_status_t
4747 get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp,
4748 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4749 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4750 {
4751 char *s;
4752 uint32_t v;
4753 dladm_status_t status;
4754
4755 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4756 perm_flags, &v, sizeof (v));
4757 if (status != DLADM_STATUS_OK)
4758 return (status);
4759
4760 switch (v) {
4761 case DLADM_PART_CM_MODE:
4762 s = "cm";
4763 break;
4764 case DLADM_PART_UD_MODE:
4765 s = "ud";
4766 break;
4767 default:
4768 s = "";
4769 break;
4770 }
4771 (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s);
4772
4773 *val_cnt = 1;
4774 return (DLADM_STATUS_OK);
4775 }