13147Sxc151355 /* 23147Sxc151355 * CDDL HEADER START 33147Sxc151355 * 43147Sxc151355 * The contents of this file are subject to the terms of the 53147Sxc151355 * Common Development and Distribution License (the "License"). 63147Sxc151355 * You may not use this file except in compliance with the License. 73147Sxc151355 * 83147Sxc151355 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93147Sxc151355 * or http://www.opensolaris.org/os/licensing. 103147Sxc151355 * See the License for the specific language governing permissions 113147Sxc151355 * and limitations under the License. 123147Sxc151355 * 133147Sxc151355 * When distributing Covered Code, include this CDDL HEADER in each 143147Sxc151355 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153147Sxc151355 * If applicable, add the following below this CDDL HEADER, with the 163147Sxc151355 * fields enclosed by brackets "[]" replaced with your own identifying 173147Sxc151355 * information: Portions Copyright [yyyy] [name of copyright owner] 183147Sxc151355 * 193147Sxc151355 * CDDL HEADER END 203147Sxc151355 */ 213147Sxc151355 /* 22*5895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 233147Sxc151355 * Use is subject to license terms. 243147Sxc151355 */ 253147Sxc151355 263147Sxc151355 #pragma ident "%Z%%M% %I% %E% SMI" 273147Sxc151355 283147Sxc151355 #include <stdlib.h> 293147Sxc151355 #include <strings.h> 303147Sxc151355 #include <errno.h> 313147Sxc151355 #include <ctype.h> 32*5895Syz147064 #include <stddef.h> 333448Sdh155122 #include <sys/types.h> 343147Sxc151355 #include <sys/stat.h> 353448Sdh155122 #include <sys/dld.h> 363448Sdh155122 #include <sys/zone.h> 373448Sdh155122 #include <fcntl.h> 383448Sdh155122 #include <unistd.h> 393448Sdh155122 #include <libdevinfo.h> 403448Sdh155122 #include <zone.h> 413871Syz147064 #include <libdllink.h> 423147Sxc151355 #include <libdladm_impl.h> 43*5895Syz147064 #include <libdlwlan_impl.h> 443871Syz147064 #include <libdlwlan.h> 45*5895Syz147064 #include <libdlvlan.h> 463448Sdh155122 #include <dlfcn.h> 473448Sdh155122 #include <link.h> 48*5895Syz147064 #include <inet/wifi_ioctl.h> 493448Sdh155122 50*5895Syz147064 /* 51*5895Syz147064 * The linkprop get() callback. 52*5895Syz147064 * - propstrp: a property string array to keep the returned property. 53*5895Syz147064 * Caller allocated. 54*5895Syz147064 * - cntp: number of returned properties. 55*5895Syz147064 * Caller also uses it to indicate how many it expects. 56*5895Syz147064 */ 57*5895Syz147064 typedef dladm_status_t pd_getf_t(datalink_id_t, char **propstp, uint_t *cntp); 58*5895Syz147064 59*5895Syz147064 /* 60*5895Syz147064 * The linkprop set() callback. 61*5895Syz147064 * - propval: a val_desc_t array which keeps the property values to be set. 62*5895Syz147064 * - cnt: number of properties to be set. 63*5895Syz147064 */ 64*5895Syz147064 typedef dladm_status_t pd_setf_t(datalink_id_t, val_desc_t *propval, 65*5895Syz147064 uint_t cnt); 663448Sdh155122 67*5895Syz147064 #define PD_TEMPONLY 0x1 683448Sdh155122 69*5895Syz147064 /* 70*5895Syz147064 * The linkprop check() callback. 71*5895Syz147064 * - propstrp: property string array which keeps the property to be checked. 72*5895Syz147064 * - cnt: number of properties. 73*5895Syz147064 * - propval: return value; the property values of the given property strings. 74*5895Syz147064 * - dofree: indicates whether the caller needs to free propvalp->vd_val. 75*5895Syz147064 */ 76*5895Syz147064 typedef dladm_status_t pd_checkf_t(datalink_id_t, char **propstrp, 77*5895Syz147064 uint_t cnt, val_desc_t *propval, boolean_t *dofree); 783448Sdh155122 79*5895Syz147064 static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, 80*5895Syz147064 do_get_rate_prop, do_get_channel_prop, 81*5895Syz147064 do_get_powermode_prop, do_get_radio_prop; 82*5895Syz147064 static pd_setf_t do_set_zone, do_set_autopush, do_set_rate_prop, 83*5895Syz147064 do_set_powermode_prop, do_set_radio_prop; 84*5895Syz147064 static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate; 853448Sdh155122 863448Sdh155122 typedef struct prop_desc { 87*5895Syz147064 /* 88*5895Syz147064 * link property name 89*5895Syz147064 */ 90*5895Syz147064 char *pd_name; 91*5895Syz147064 92*5895Syz147064 /* 93*5895Syz147064 * default property value, can be set to { "", NULL } 94*5895Syz147064 */ 95*5895Syz147064 val_desc_t pd_defval; 96*5895Syz147064 97*5895Syz147064 /* 98*5895Syz147064 * list of optional property values, can be NULL. 99*5895Syz147064 * 100*5895Syz147064 * This is set to non-NULL if there is a list of possible property 101*5895Syz147064 * values. pd_optval would point to the array of possible values. 102*5895Syz147064 */ 103*5895Syz147064 val_desc_t *pd_optval; 104*5895Syz147064 105*5895Syz147064 /* 106*5895Syz147064 * count of the above optional property values. 0 if pd_optval is NULL. 107*5895Syz147064 */ 108*5895Syz147064 uint_t pd_noptval; 109*5895Syz147064 110*5895Syz147064 /* 111*5895Syz147064 * callback to set link property; 112*5895Syz147064 * set to NULL if this property is read-only 113*5895Syz147064 */ 114*5895Syz147064 pd_setf_t *pd_set; 115*5895Syz147064 116*5895Syz147064 /* 117*5895Syz147064 * callback to get modifiable link property 118*5895Syz147064 */ 119*5895Syz147064 pd_getf_t *pd_getmod; 120*5895Syz147064 121*5895Syz147064 /* 122*5895Syz147064 * callback to get current link property 123*5895Syz147064 */ 124*5895Syz147064 pd_getf_t *pd_get; 125*5895Syz147064 126*5895Syz147064 /* 127*5895Syz147064 * callback to validate link property value, set to NULL if pd_optval 128*5895Syz147064 * is not NULL. In that case, validate the value by comparing it with 129*5895Syz147064 * the pd_optval. Return a val_desc_t array pointer if the value is 130*5895Syz147064 * valid. 131*5895Syz147064 */ 132*5895Syz147064 pd_checkf_t *pd_check; 133*5895Syz147064 134*5895Syz147064 /* 135*5895Syz147064 * currently only PD_TEMPONLY is valid, which indicates the property 136*5895Syz147064 * is temporary only. 137*5895Syz147064 */ 138*5895Syz147064 uint_t pd_flags; 139*5895Syz147064 140*5895Syz147064 /* 141*5895Syz147064 * indicate link classes this property applies to. 142*5895Syz147064 */ 143*5895Syz147064 datalink_class_t pd_class; 144*5895Syz147064 145*5895Syz147064 /* 146*5895Syz147064 * indicate link media type this property applies to. 147*5895Syz147064 */ 148*5895Syz147064 datalink_media_t pd_dmedia; 1493448Sdh155122 } prop_desc_t; 1503448Sdh155122 151*5895Syz147064 static val_desc_t dladm_wlan_radio_vals[] = { 152*5895Syz147064 { "on", DLADM_WLAN_RADIO_ON }, 153*5895Syz147064 { "off", DLADM_WLAN_RADIO_OFF } 154*5895Syz147064 }; 155*5895Syz147064 156*5895Syz147064 static val_desc_t dladm_wlan_powermode_vals[] = { 157*5895Syz147064 { "off", DLADM_WLAN_PM_OFF }, 158*5895Syz147064 { "fast", DLADM_WLAN_PM_FAST }, 159*5895Syz147064 { "max", DLADM_WLAN_PM_MAX } 160*5895Syz147064 }; 161*5895Syz147064 1623448Sdh155122 static prop_desc_t prop_table[] = { 163*5895Syz147064 164*5895Syz147064 { "channel", { NULL, 0 }, NULL, 0, NULL, NULL, 165*5895Syz147064 do_get_channel_prop, NULL, 0, 166*5895Syz147064 DATALINK_CLASS_PHYS, DL_WIFI}, 167*5895Syz147064 168*5895Syz147064 { "powermode", { "off", DLADM_WLAN_PM_OFF }, 169*5895Syz147064 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), 170*5895Syz147064 do_set_powermode_prop, NULL, 171*5895Syz147064 do_get_powermode_prop, NULL, 0, 172*5895Syz147064 DATALINK_CLASS_PHYS, DL_WIFI}, 173*5895Syz147064 174*5895Syz147064 { "radio", { "on", DLADM_WLAN_RADIO_ON }, 175*5895Syz147064 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), 176*5895Syz147064 do_set_radio_prop, NULL, 177*5895Syz147064 do_get_radio_prop, NULL, 0, 178*5895Syz147064 DATALINK_CLASS_PHYS, DL_WIFI}, 179*5895Syz147064 180*5895Syz147064 { "speed", { "", 0 }, NULL, 0, 181*5895Syz147064 do_set_rate_prop, do_get_rate_mod, 182*5895Syz147064 do_get_rate_prop, do_check_rate, 0, 183*5895Syz147064 DATALINK_CLASS_PHYS, DL_WIFI}, 184*5895Syz147064 185*5895Syz147064 { "autopush", { "", NULL }, NULL, 0, 186*5895Syz147064 do_set_autopush, NULL, 187*5895Syz147064 do_get_autopush, do_check_autopush, 0, 188*5895Syz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE}, 189*5895Syz147064 190*5895Syz147064 { "zone", { "", NULL }, NULL, 0, 1913448Sdh155122 do_set_zone, NULL, 192*5895Syz147064 do_get_zone, do_check_zone, PD_TEMPONLY, 193*5895Syz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE} 1943448Sdh155122 }; 1953448Sdh155122 196*5895Syz147064 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 197*5895Syz147064 198*5895Syz147064 static dladm_status_t i_dladm_set_linkprop_db(datalink_id_t, const char *, 199*5895Syz147064 char **, uint_t); 200*5895Syz147064 static dladm_status_t i_dladm_get_linkprop_db(datalink_id_t, const char *, 201*5895Syz147064 char **, uint_t *); 202*5895Syz147064 static dladm_status_t i_dladm_set_single_prop(datalink_id_t, datalink_class_t, 203*5895Syz147064 uint32_t, prop_desc_t *, char **, uint_t, uint_t); 204*5895Syz147064 static dladm_status_t i_dladm_set_linkprop(datalink_id_t, const char *, 205*5895Syz147064 char **, uint_t, uint_t); 206*5895Syz147064 207*5895Syz147064 /* 208*5895Syz147064 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 209*5895Syz147064 * rates to be retrieved. However, we cannot increase it at this 210*5895Syz147064 * time because it will break binary compatibility with unbundled 211*5895Syz147064 * WiFi drivers and utilities. So for now we define an additional 212*5895Syz147064 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 213*5895Syz147064 */ 214*5895Syz147064 #define MAX_SUPPORT_RATES 64 215*5895Syz147064 216*5895Syz147064 #define AP_ANCHOR "[anchor]" 217*5895Syz147064 #define AP_DELIMITER '.' 218*5895Syz147064 219*5895Syz147064 static dladm_status_t 220*5895Syz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 221*5895Syz147064 val_desc_t *vdp) 222*5895Syz147064 { 223*5895Syz147064 int i, j; 224*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 2253147Sxc151355 226*5895Syz147064 for (j = 0; j < val_cnt; j++) { 227*5895Syz147064 for (i = 0; i < pdp->pd_noptval; i++) { 228*5895Syz147064 if (strcasecmp(*prop_val, 229*5895Syz147064 pdp->pd_optval[i].vd_name) == 0) { 230*5895Syz147064 break; 231*5895Syz147064 } 232*5895Syz147064 } 233*5895Syz147064 if (i == pdp->pd_noptval) { 234*5895Syz147064 status = DLADM_STATUS_BADVAL; 235*5895Syz147064 goto done; 236*5895Syz147064 } 237*5895Syz147064 (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t)); 238*5895Syz147064 } 239*5895Syz147064 240*5895Syz147064 done: 241*5895Syz147064 return (status); 242*5895Syz147064 } 243*5895Syz147064 244*5895Syz147064 static dladm_status_t 245*5895Syz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class, 246*5895Syz147064 uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 247*5895Syz147064 uint_t flags) 2483147Sxc151355 { 249*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 250*5895Syz147064 val_desc_t *vdp = NULL; 251*5895Syz147064 boolean_t needfree = B_FALSE; 252*5895Syz147064 uint_t cnt, i; 2533147Sxc151355 254*5895Syz147064 if (!(pdp->pd_class & class)) 255*5895Syz147064 return (DLADM_STATUS_BADARG); 256*5895Syz147064 257*5895Syz147064 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 2583147Sxc151355 return (DLADM_STATUS_BADARG); 2593147Sxc151355 260*5895Syz147064 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY)) 261*5895Syz147064 return (DLADM_STATUS_TEMPONLY); 262*5895Syz147064 263*5895Syz147064 if (!(flags & DLADM_OPT_ACTIVE)) 264*5895Syz147064 return (DLADM_STATUS_OK); 265*5895Syz147064 266*5895Syz147064 if (pdp->pd_set == NULL) 267*5895Syz147064 return (DLADM_STATUS_PROPRDONLY); 2683448Sdh155122 269*5895Syz147064 if (prop_val != NULL) { 270*5895Syz147064 vdp = malloc(sizeof (val_desc_t) * val_cnt); 271*5895Syz147064 if (vdp == NULL) 272*5895Syz147064 return (DLADM_STATUS_NOMEM); 273*5895Syz147064 274*5895Syz147064 if (pdp->pd_check != NULL) { 275*5895Syz147064 status = pdp->pd_check(linkid, prop_val, val_cnt, vdp, 276*5895Syz147064 &needfree); 277*5895Syz147064 } else if (pdp->pd_optval != NULL) { 278*5895Syz147064 status = do_check_prop(pdp, prop_val, val_cnt, vdp); 279*5895Syz147064 } else { 2803448Sdh155122 status = DLADM_STATUS_BADARG; 2813147Sxc151355 } 282*5895Syz147064 2833147Sxc151355 if (status != DLADM_STATUS_OK) 284*5895Syz147064 goto done; 285*5895Syz147064 286*5895Syz147064 cnt = val_cnt; 287*5895Syz147064 } else { 288*5895Syz147064 if (pdp->pd_defval.vd_name == NULL) 289*5895Syz147064 return (DLADM_STATUS_NOTSUP); 290*5895Syz147064 291*5895Syz147064 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 292*5895Syz147064 return (DLADM_STATUS_NOMEM); 293*5895Syz147064 294*5895Syz147064 (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t)); 295*5895Syz147064 cnt = 1; 296*5895Syz147064 } 297*5895Syz147064 status = pdp->pd_set(linkid, vdp, cnt); 298*5895Syz147064 if (needfree) { 299*5895Syz147064 for (i = 0; i < cnt; i++) 300*5895Syz147064 free((void *)(((val_desc_t *)vdp + i)->vd_val)); 3013147Sxc151355 } 302*5895Syz147064 done: 303*5895Syz147064 free(vdp); 304*5895Syz147064 return (status); 305*5895Syz147064 } 306*5895Syz147064 307*5895Syz147064 static dladm_status_t 308*5895Syz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, 309*5895Syz147064 char **prop_val, uint_t val_cnt, uint_t flags) 310*5895Syz147064 { 311*5895Syz147064 int i; 312*5895Syz147064 boolean_t found = B_FALSE; 313*5895Syz147064 datalink_class_t class; 314*5895Syz147064 uint32_t media; 315*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 316*5895Syz147064 317*5895Syz147064 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 318*5895Syz147064 if (status != DLADM_STATUS_OK) 319*5895Syz147064 return (status); 320*5895Syz147064 321*5895Syz147064 for (i = 0; i < DLADM_MAX_PROPS; i++) { 322*5895Syz147064 prop_desc_t *pdp = &prop_table[i]; 323*5895Syz147064 dladm_status_t s; 324*5895Syz147064 325*5895Syz147064 if (prop_name != NULL && 326*5895Syz147064 (strcasecmp(prop_name, pdp->pd_name) != 0)) 327*5895Syz147064 continue; 328*5895Syz147064 329*5895Syz147064 found = B_TRUE; 330*5895Syz147064 s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val, 331*5895Syz147064 val_cnt, flags); 3323448Sdh155122 333*5895Syz147064 if (prop_name != NULL) { 334*5895Syz147064 status = s; 335*5895Syz147064 break; 336*5895Syz147064 } else { 337*5895Syz147064 if (s != DLADM_STATUS_OK && 338*5895Syz147064 s != DLADM_STATUS_NOTSUP) 339*5895Syz147064 status = s; 340*5895Syz147064 } 341*5895Syz147064 } 342*5895Syz147064 if (!found) 343*5895Syz147064 status = DLADM_STATUS_NOTFOUND; 344*5895Syz147064 345*5895Syz147064 return (status); 346*5895Syz147064 } 347*5895Syz147064 348*5895Syz147064 /* 349*5895Syz147064 * Set/reset link property for specific link 350*5895Syz147064 */ 351*5895Syz147064 dladm_status_t 352*5895Syz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val, 353*5895Syz147064 uint_t val_cnt, uint_t flags) 354*5895Syz147064 { 355*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 356*5895Syz147064 357*5895Syz147064 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) || 358*5895Syz147064 (prop_val == NULL && val_cnt > 0) || 359*5895Syz147064 (prop_val != NULL && val_cnt == 0) || 360*5895Syz147064 (prop_name == NULL && prop_val != NULL)) { 361*5895Syz147064 return (DLADM_STATUS_BADARG); 362*5895Syz147064 } 363*5895Syz147064 364*5895Syz147064 status = i_dladm_set_linkprop(linkid, prop_name, prop_val, 365*5895Syz147064 val_cnt, flags); 366*5895Syz147064 if (status != DLADM_STATUS_OK) 367*5895Syz147064 return (status); 368*5895Syz147064 369*5895Syz147064 if (flags & DLADM_OPT_PERSIST) { 370*5895Syz147064 status = i_dladm_set_linkprop_db(linkid, prop_name, 3713147Sxc151355 prop_val, val_cnt); 3723147Sxc151355 } 3733147Sxc151355 return (status); 3743147Sxc151355 } 3753147Sxc151355 376*5895Syz147064 /* 377*5895Syz147064 * Walk link properties of the given specific link. 378*5895Syz147064 */ 3793147Sxc151355 dladm_status_t 380*5895Syz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg, 381*5895Syz147064 int (*func)(datalink_id_t, const char *, void *)) 3823147Sxc151355 { 383*5895Syz147064 dladm_status_t status; 384*5895Syz147064 datalink_class_t class; 385*5895Syz147064 uint_t media; 386*5895Syz147064 int i; 387*5895Syz147064 388*5895Syz147064 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 389*5895Syz147064 return (DLADM_STATUS_BADARG); 390*5895Syz147064 391*5895Syz147064 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 392*5895Syz147064 if (status != DLADM_STATUS_OK) 393*5895Syz147064 return (status); 394*5895Syz147064 395*5895Syz147064 for (i = 0; i < DLADM_MAX_PROPS; i++) { 396*5895Syz147064 if (!(prop_table[i].pd_class & class)) 397*5895Syz147064 continue; 398*5895Syz147064 399*5895Syz147064 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) 400*5895Syz147064 continue; 401*5895Syz147064 402*5895Syz147064 if (func(linkid, prop_table[i].pd_name, arg) == 403*5895Syz147064 DLADM_WALK_TERMINATE) { 404*5895Syz147064 break; 405*5895Syz147064 } 406*5895Syz147064 } 407*5895Syz147064 408*5895Syz147064 return (DLADM_STATUS_OK); 409*5895Syz147064 } 4103448Sdh155122 411*5895Syz147064 /* 412*5895Syz147064 * Get linkprop of the given specific link. 413*5895Syz147064 */ 414*5895Syz147064 dladm_status_t 415*5895Syz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, 416*5895Syz147064 const char *prop_name, char **prop_val, uint_t *val_cntp) 417*5895Syz147064 { 418*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 419*5895Syz147064 datalink_class_t class; 420*5895Syz147064 uint_t media; 421*5895Syz147064 prop_desc_t *pdp; 422*5895Syz147064 uint_t cnt; 423*5895Syz147064 int i; 424*5895Syz147064 425*5895Syz147064 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 426*5895Syz147064 prop_val == NULL || val_cntp == NULL || *val_cntp == 0) 427*5895Syz147064 return (DLADM_STATUS_BADARG); 428*5895Syz147064 429*5895Syz147064 for (i = 0; i < DLADM_MAX_PROPS; i++) 430*5895Syz147064 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 431*5895Syz147064 break; 432*5895Syz147064 433*5895Syz147064 if (i == DLADM_MAX_PROPS) 434*5895Syz147064 return (DLADM_STATUS_NOTFOUND); 435*5895Syz147064 436*5895Syz147064 pdp = &prop_table[i]; 437*5895Syz147064 438*5895Syz147064 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 439*5895Syz147064 if (status != DLADM_STATUS_OK) 440*5895Syz147064 return (status); 441*5895Syz147064 442*5895Syz147064 if (!(pdp->pd_class & class)) 443*5895Syz147064 return (DLADM_STATUS_BADARG); 444*5895Syz147064 445*5895Syz147064 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 4463147Sxc151355 return (DLADM_STATUS_BADARG); 4473147Sxc151355 448*5895Syz147064 switch (type) { 449*5895Syz147064 case DLADM_PROP_VAL_CURRENT: 450*5895Syz147064 status = pdp->pd_get(linkid, prop_val, val_cntp); 451*5895Syz147064 break; 452*5895Syz147064 453*5895Syz147064 case DLADM_PROP_VAL_DEFAULT: 454*5895Syz147064 if (pdp->pd_defval.vd_name == NULL) { 455*5895Syz147064 status = DLADM_STATUS_NOTSUP; 456*5895Syz147064 break; 457*5895Syz147064 } 458*5895Syz147064 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 459*5895Syz147064 *val_cntp = 1; 460*5895Syz147064 break; 4613448Sdh155122 462*5895Syz147064 case DLADM_PROP_VAL_MODIFIABLE: 463*5895Syz147064 if (pdp->pd_getmod != NULL) { 464*5895Syz147064 status = pdp->pd_getmod(linkid, prop_val, val_cntp); 465*5895Syz147064 break; 466*5895Syz147064 } 467*5895Syz147064 cnt = pdp->pd_noptval; 468*5895Syz147064 if (cnt == 0) { 469*5895Syz147064 status = DLADM_STATUS_NOTSUP; 470*5895Syz147064 } else if (cnt > *val_cntp) { 471*5895Syz147064 status = DLADM_STATUS_TOOSMALL; 472*5895Syz147064 } else { 473*5895Syz147064 for (i = 0; i < cnt; i++) { 474*5895Syz147064 (void) strcpy(prop_val[i], 475*5895Syz147064 pdp->pd_optval[i].vd_name); 476*5895Syz147064 } 477*5895Syz147064 *val_cntp = cnt; 478*5895Syz147064 } 479*5895Syz147064 break; 480*5895Syz147064 case DLADM_PROP_VAL_PERSISTENT: 481*5895Syz147064 if (pdp->pd_flags & PD_TEMPONLY) 482*5895Syz147064 return (DLADM_STATUS_TEMPONLY); 483*5895Syz147064 status = i_dladm_get_linkprop_db(linkid, prop_name, 484*5895Syz147064 prop_val, val_cntp); 485*5895Syz147064 break; 486*5895Syz147064 default: 487*5895Syz147064 status = DLADM_STATUS_BADARG; 488*5895Syz147064 break; 4893147Sxc151355 } 4903448Sdh155122 491*5895Syz147064 return (status); 492*5895Syz147064 } 493*5895Syz147064 494*5895Syz147064 /*ARGSUSED*/ 495*5895Syz147064 static int 496*5895Syz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg) 497*5895Syz147064 { 498*5895Syz147064 char *buf, **propvals; 499*5895Syz147064 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; 500*5895Syz147064 501*5895Syz147064 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 502*5895Syz147064 DLADM_MAX_PROP_VALCNT)) == NULL) { 503*5895Syz147064 return (DLADM_WALK_CONTINUE); 504*5895Syz147064 } 505*5895Syz147064 506*5895Syz147064 propvals = (char **)(void *)buf; 507*5895Syz147064 for (i = 0; i < valcnt; i++) { 508*5895Syz147064 propvals[i] = buf + 509*5895Syz147064 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 510*5895Syz147064 i * DLADM_PROP_VAL_MAX; 511*5895Syz147064 } 512*5895Syz147064 513*5895Syz147064 if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name, 514*5895Syz147064 propvals, &valcnt) != DLADM_STATUS_OK) { 515*5895Syz147064 goto done; 516*5895Syz147064 } 517*5895Syz147064 518*5895Syz147064 (void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt, 519*5895Syz147064 DLADM_OPT_ACTIVE); 520*5895Syz147064 521*5895Syz147064 done: 522*5895Syz147064 if (buf != NULL) 523*5895Syz147064 free(buf); 524*5895Syz147064 525*5895Syz147064 return (DLADM_WALK_CONTINUE); 526*5895Syz147064 } 527*5895Syz147064 528*5895Syz147064 /*ARGSUSED*/ 529*5895Syz147064 static int 530*5895Syz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 531*5895Syz147064 { 532*5895Syz147064 (void) dladm_init_linkprop(linkid); 533*5895Syz147064 return (DLADM_WALK_CONTINUE); 534*5895Syz147064 } 535*5895Syz147064 536*5895Syz147064 dladm_status_t 537*5895Syz147064 dladm_init_linkprop(datalink_id_t linkid) 538*5895Syz147064 { 539*5895Syz147064 if (linkid == DATALINK_ALL_LINKID) { 540*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 541*5895Syz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 542*5895Syz147064 DLADM_OPT_PERSIST); 543*5895Syz147064 } else { 544*5895Syz147064 (void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop); 5453448Sdh155122 } 5463448Sdh155122 return (DLADM_STATUS_OK); 5473147Sxc151355 } 5483147Sxc151355 549*5895Syz147064 static dladm_status_t 550*5895Syz147064 do_get_zone(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) 5513147Sxc151355 { 552*5895Syz147064 char zone_name[ZONENAME_MAX]; 553*5895Syz147064 zoneid_t zid; 554*5895Syz147064 dladm_status_t status; 5553147Sxc151355 556*5895Syz147064 status = dladm_getzid(linkid, &zid); 557*5895Syz147064 if (status != DLADM_STATUS_OK) 5583448Sdh155122 return (status); 5593448Sdh155122 560*5895Syz147064 *val_cnt = 1; 561*5895Syz147064 if (zid != GLOBAL_ZONEID) { 562*5895Syz147064 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 563*5895Syz147064 return (dladm_errno2status(errno)); 5643147Sxc151355 565*5895Syz147064 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 5663147Sxc151355 } else { 567*5895Syz147064 *prop_val[0] = '\0'; 5683147Sxc151355 } 5693147Sxc151355 5703448Sdh155122 return (DLADM_STATUS_OK); 5713448Sdh155122 } 5723448Sdh155122 5733448Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 5743448Sdh155122 5753448Sdh155122 static int 5763448Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 5773448Sdh155122 { 5783448Sdh155122 char root[MAXPATHLEN]; 5793448Sdh155122 zone_get_devroot_t real_zone_get_devroot; 5803448Sdh155122 void *dlhandle; 5813448Sdh155122 void *sym; 5823448Sdh155122 int ret; 5833448Sdh155122 5843448Sdh155122 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 5853448Sdh155122 return (-1); 5863448Sdh155122 5873448Sdh155122 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 5883448Sdh155122 (void) dlclose(dlhandle); 5893448Sdh155122 return (-1); 5903448Sdh155122 } 5913448Sdh155122 5923448Sdh155122 real_zone_get_devroot = (zone_get_devroot_t)sym; 5933448Sdh155122 5943448Sdh155122 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 5953448Sdh155122 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 5963448Sdh155122 (void) dlclose(dlhandle); 5973448Sdh155122 return (ret); 5983448Sdh155122 } 5993448Sdh155122 6003448Sdh155122 static dladm_status_t 601*5895Syz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add) 6023448Sdh155122 { 6033448Sdh155122 char path[MAXPATHLEN]; 604*5895Syz147064 char name[MAXLINKNAMELEN]; 6053448Sdh155122 di_prof_t prof = NULL; 6063448Sdh155122 char zone_name[ZONENAME_MAX]; 6073448Sdh155122 dladm_status_t status; 608*5895Syz147064 int ret; 6093448Sdh155122 6103448Sdh155122 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 6113448Sdh155122 return (dladm_errno2status(errno)); 6123448Sdh155122 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 6133448Sdh155122 return (dladm_errno2status(errno)); 6143448Sdh155122 if (di_prof_init(path, &prof) != 0) 6153448Sdh155122 return (dladm_errno2status(errno)); 6163448Sdh155122 617*5895Syz147064 status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN); 618*5895Syz147064 if (status != DLADM_STATUS_OK) 619*5895Syz147064 goto cleanup; 620*5895Syz147064 621*5895Syz147064 if (add) 622*5895Syz147064 ret = di_prof_add_dev(prof, name); 623*5895Syz147064 else 624*5895Syz147064 ret = di_prof_add_exclude(prof, name); 625*5895Syz147064 626*5895Syz147064 if (ret != 0) { 6273448Sdh155122 status = dladm_errno2status(errno); 6283448Sdh155122 goto cleanup; 6293448Sdh155122 } 6303448Sdh155122 6313448Sdh155122 if (di_prof_commit(prof) != 0) 6323448Sdh155122 status = dladm_errno2status(errno); 6333448Sdh155122 cleanup: 6343448Sdh155122 if (prof) 6353448Sdh155122 di_prof_fini(prof); 6363448Sdh155122 6373448Sdh155122 return (status); 6383448Sdh155122 } 6393448Sdh155122 6403448Sdh155122 static dladm_status_t 641*5895Syz147064 do_set_zone(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) 6423448Sdh155122 { 6433448Sdh155122 dladm_status_t status; 6443448Sdh155122 zoneid_t zid_old, zid_new; 645*5895Syz147064 char link[MAXLINKNAMELEN]; 6463448Sdh155122 6473448Sdh155122 if (val_cnt != 1) 6483448Sdh155122 return (DLADM_STATUS_BADVALCNT); 6493448Sdh155122 650*5895Syz147064 status = dladm_getzid(linkid, &zid_old); 6513448Sdh155122 if (status != DLADM_STATUS_OK) 6523448Sdh155122 return (status); 6533448Sdh155122 6543448Sdh155122 /* Do nothing if setting to current value */ 655*5895Syz147064 zid_new = vdp->vd_val; 6563448Sdh155122 if (zid_new == zid_old) 6573448Sdh155122 return (DLADM_STATUS_OK); 6583448Sdh155122 659*5895Syz147064 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, 660*5895Syz147064 link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 661*5895Syz147064 return (status); 662*5895Syz147064 } 663*5895Syz147064 664*5895Syz147064 if (zid_new != GLOBAL_ZONEID) { 665*5895Syz147064 /* 666*5895Syz147064 * If the new zoneid is the global zone, we could destroy 667*5895Syz147064 * the link (in the case of an implicitly-created VLAN) as a 668*5895Syz147064 * result of the dladm_setzid() operation. In that case, 669*5895Syz147064 * we defer the operation to the end of this function to avoid 670*5895Syz147064 * recreating the VLAN and getting a different linkid during 671*5895Syz147064 * the rollback if other operation fails. 672*5895Syz147064 * 673*5895Syz147064 * Otherwise, dladm_setzid() will hold a reference to the 674*5895Syz147064 * link and prevent a link renaming, so we need to do it 675*5895Syz147064 * before other operations. 676*5895Syz147064 */ 677*5895Syz147064 status = dladm_setzid(link, zid_new); 678*5895Syz147064 if (status != DLADM_STATUS_OK) 679*5895Syz147064 return (status); 680*5895Syz147064 } 681*5895Syz147064 6823448Sdh155122 if (zid_old != GLOBAL_ZONEID) { 683*5895Syz147064 if (zone_remove_datalink(zid_old, link) != 0 && 6843448Sdh155122 errno != ENXIO) { 6853448Sdh155122 status = dladm_errno2status(errno); 6863448Sdh155122 goto rollback1; 6873448Sdh155122 } 6883448Sdh155122 689*5895Syz147064 /* 690*5895Syz147064 * It is okay to fail to update the /dev entry (some 691*5895Syz147064 * vanity-named links do not have a /dev entry). 692*5895Syz147064 */ 693*5895Syz147064 (void) i_dladm_update_deventry(zid_old, linkid, B_FALSE); 694*5895Syz147064 } 695*5895Syz147064 696*5895Syz147064 if (zid_new != GLOBAL_ZONEID) { 697*5895Syz147064 if (zone_add_datalink(zid_new, link) != 0) { 698*5895Syz147064 status = dladm_errno2status(errno); 699*5895Syz147064 goto rollback2; 700*5895Syz147064 } 701*5895Syz147064 702*5895Syz147064 (void) i_dladm_update_deventry(zid_new, linkid, B_TRUE); 703*5895Syz147064 } else { 704*5895Syz147064 status = dladm_setzid(link, zid_new); 7053448Sdh155122 if (status != DLADM_STATUS_OK) 7063448Sdh155122 goto rollback2; 7073448Sdh155122 } 7083448Sdh155122 7093448Sdh155122 return (DLADM_STATUS_OK); 7103448Sdh155122 7113448Sdh155122 rollback2: 7123448Sdh155122 if (zid_old != GLOBAL_ZONEID) 713*5895Syz147064 (void) i_dladm_update_deventry(zid_old, linkid, B_TRUE); 714*5895Syz147064 if (zid_old != GLOBAL_ZONEID) 715*5895Syz147064 (void) zone_add_datalink(zid_old, link); 7163448Sdh155122 rollback1: 717*5895Syz147064 if (zid_new != GLOBAL_ZONEID) 718*5895Syz147064 (void) dladm_setzid(link, zid_old); 7193448Sdh155122 return (status); 7203448Sdh155122 } 7213448Sdh155122 7223448Sdh155122 /* ARGSUSED */ 7233448Sdh155122 static dladm_status_t 724*5895Syz147064 do_check_zone(datalink_id_t linkid, char **prop_val, uint_t val_cnt, 725*5895Syz147064 val_desc_t *vdp, boolean_t *needfreep) 7263448Sdh155122 { 727*5895Syz147064 zoneid_t zid; 7283448Sdh155122 7293448Sdh155122 if (val_cnt != 1) 7303448Sdh155122 return (DLADM_STATUS_BADVALCNT); 7313448Sdh155122 7323448Sdh155122 if ((zid = getzoneidbyname(*prop_val)) == -1) 7333448Sdh155122 return (DLADM_STATUS_BADVAL); 7343448Sdh155122 7353448Sdh155122 if (zid != GLOBAL_ZONEID) { 7363448Sdh155122 ushort_t flags; 7373448Sdh155122 7383448Sdh155122 if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags, 7393448Sdh155122 sizeof (flags)) < 0) { 7403448Sdh155122 return (dladm_errno2status(errno)); 7413448Sdh155122 } 7423448Sdh155122 7433448Sdh155122 if (!(flags & ZF_NET_EXCL)) { 7443448Sdh155122 return (DLADM_STATUS_BADVAL); 7453448Sdh155122 } 7463448Sdh155122 } 7473448Sdh155122 748*5895Syz147064 vdp->vd_val = zid; 749*5895Syz147064 *needfreep = B_FALSE; 750*5895Syz147064 return (DLADM_STATUS_OK); 751*5895Syz147064 } 752*5895Syz147064 753*5895Syz147064 static dladm_status_t 754*5895Syz147064 do_get_autopush(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) 755*5895Syz147064 { 756*5895Syz147064 dld_ioc_ap_t dia; 757*5895Syz147064 int fd, i, len; 758*5895Syz147064 759*5895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 760*5895Syz147064 return (dladm_errno2status(errno)); 761*5895Syz147064 762*5895Syz147064 *val_cnt = 1; 763*5895Syz147064 dia.dia_linkid = linkid; 764*5895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) { 765*5895Syz147064 (*prop_val)[0] = '\0'; 766*5895Syz147064 goto done; 767*5895Syz147064 } 768*5895Syz147064 769*5895Syz147064 for (i = 0, len = 0; i < dia.dia_npush; i++) { 770*5895Syz147064 if (i != 0) { 771*5895Syz147064 (void) snprintf(*prop_val + len, 772*5895Syz147064 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 773*5895Syz147064 len += 1; 774*5895Syz147064 } 775*5895Syz147064 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 776*5895Syz147064 "%s", dia.dia_aplist[i]); 777*5895Syz147064 len += strlen(dia.dia_aplist[i]); 778*5895Syz147064 if (dia.dia_anchor - 1 == i) { 779*5895Syz147064 (void) snprintf(*prop_val + len, 780*5895Syz147064 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 781*5895Syz147064 AP_ANCHOR); 782*5895Syz147064 len += (strlen(AP_ANCHOR) + 1); 783*5895Syz147064 } 784*5895Syz147064 } 785*5895Syz147064 786*5895Syz147064 done: 787*5895Syz147064 (void) close(fd); 788*5895Syz147064 return (DLADM_STATUS_OK); 789*5895Syz147064 } 790*5895Syz147064 791*5895Syz147064 static dladm_status_t 792*5895Syz147064 do_set_autopush(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) 793*5895Syz147064 { 794*5895Syz147064 dld_ioc_ap_t dia; 795*5895Syz147064 struct dlautopush *dlap = (struct dlautopush *)vdp->vd_val; 796*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 797*5895Syz147064 int fd, i; 798*5895Syz147064 int ic_cmd; 799*5895Syz147064 800*5895Syz147064 if (val_cnt != 1) 801*5895Syz147064 return (DLADM_STATUS_BADVALCNT); 802*5895Syz147064 803*5895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 804*5895Syz147064 return (dladm_errno2status(errno)); 805*5895Syz147064 806*5895Syz147064 dia.dia_linkid = linkid; 807*5895Syz147064 if (dlap != NULL) { 808*5895Syz147064 dia.dia_anchor = dlap->dap_anchor; 809*5895Syz147064 dia.dia_npush = dlap->dap_npush; 810*5895Syz147064 for (i = 0; i < dia.dia_npush; i++) { 811*5895Syz147064 (void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i], 812*5895Syz147064 FMNAMESZ+1); 813*5895Syz147064 } 814*5895Syz147064 ic_cmd = DLDIOC_SETAUTOPUSH; 815*5895Syz147064 } else { 816*5895Syz147064 ic_cmd = DLDIOC_CLRAUTOPUSH; 817*5895Syz147064 } 818*5895Syz147064 819*5895Syz147064 if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0) 820*5895Syz147064 status = dladm_errno2status(errno); 821*5895Syz147064 822*5895Syz147064 (void) close(fd); 823*5895Syz147064 return (status); 824*5895Syz147064 } 825*5895Syz147064 826*5895Syz147064 /* 827*5895Syz147064 * Add the specified module to the dlautopush structure; returns a 828*5895Syz147064 * DLADM_STATUS_* code. 829*5895Syz147064 */ 830*5895Syz147064 dladm_status_t 831*5895Syz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 832*5895Syz147064 { 833*5895Syz147064 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 834*5895Syz147064 return (DLADM_STATUS_BADVAL); 835*5895Syz147064 836*5895Syz147064 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 837*5895Syz147064 /* 838*5895Syz147064 * We don't allow multiple anchors, and the anchor must 839*5895Syz147064 * be after at least one module. 840*5895Syz147064 */ 841*5895Syz147064 if (dlap->dap_anchor != 0) 842*5895Syz147064 return (DLADM_STATUS_BADVAL); 843*5895Syz147064 if (dlap->dap_npush == 0) 844*5895Syz147064 return (DLADM_STATUS_BADVAL); 845*5895Syz147064 846*5895Syz147064 dlap->dap_anchor = dlap->dap_npush; 847*5895Syz147064 return (DLADM_STATUS_OK); 848*5895Syz147064 } 849*5895Syz147064 if (dlap->dap_npush > MAXAPUSH) 850*5895Syz147064 return (DLADM_STATUS_BADVALCNT); 851*5895Syz147064 852*5895Syz147064 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 853*5895Syz147064 FMNAMESZ + 1); 854*5895Syz147064 855*5895Syz147064 return (DLADM_STATUS_OK); 856*5895Syz147064 } 857*5895Syz147064 858*5895Syz147064 /* 859*5895Syz147064 * Currently, both '.' and ' '(space) can be used as the delimiters between 860*5895Syz147064 * autopush modules. The former is used in dladm set-linkprop, and the 861*5895Syz147064 * latter is used in the autopush(1M) file. 862*5895Syz147064 */ 863*5895Syz147064 /* ARGSUSED */ 864*5895Syz147064 static dladm_status_t 865*5895Syz147064 do_check_autopush(datalink_id_t linkid, char **prop_val, uint_t val_cnt, 866*5895Syz147064 val_desc_t *vdp, boolean_t *needfreep) 867*5895Syz147064 { 868*5895Syz147064 char *module; 869*5895Syz147064 struct dlautopush *dlap; 870*5895Syz147064 dladm_status_t status; 871*5895Syz147064 char val[DLADM_PROP_VAL_MAX]; 872*5895Syz147064 char delimiters[4]; 873*5895Syz147064 874*5895Syz147064 if (val_cnt != 1) 875*5895Syz147064 return (DLADM_STATUS_BADVALCNT); 876*5895Syz147064 877*5895Syz147064 dlap = malloc(sizeof (struct dlautopush)); 878*5895Syz147064 if (dlap == NULL) 8793448Sdh155122 return (DLADM_STATUS_NOMEM); 8803448Sdh155122 881*5895Syz147064 (void) memset(dlap, 0, sizeof (struct dlautopush)); 882*5895Syz147064 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 883*5895Syz147064 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 884*5895Syz147064 module = strtok(val, delimiters); 885*5895Syz147064 while (module != NULL) { 886*5895Syz147064 status = i_dladm_add_ap_module(module, dlap); 887*5895Syz147064 if (status != DLADM_STATUS_OK) 888*5895Syz147064 return (status); 889*5895Syz147064 module = strtok(NULL, delimiters); 890*5895Syz147064 } 891*5895Syz147064 892*5895Syz147064 vdp->vd_val = (uintptr_t)dlap; 893*5895Syz147064 *needfreep = B_TRUE; 8943448Sdh155122 return (DLADM_STATUS_OK); 8953448Sdh155122 } 8963448Sdh155122 8973448Sdh155122 static dladm_status_t 898*5895Syz147064 do_get_rate_common(datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 899*5895Syz147064 uint_t id) 9003448Sdh155122 { 901*5895Syz147064 wl_rates_t *wrp; 902*5895Syz147064 uint_t i; 903*5895Syz147064 wldp_t *gbuf = NULL; 904*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 905*5895Syz147064 906*5895Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 907*5895Syz147064 status = DLADM_STATUS_NOMEM; 908*5895Syz147064 goto done; 909*5895Syz147064 } 910*5895Syz147064 911*5895Syz147064 status = i_dladm_wlan_get_ioctl(linkid, gbuf, id); 912*5895Syz147064 if (status != DLADM_STATUS_OK) 913*5895Syz147064 goto done; 914*5895Syz147064 915*5895Syz147064 wrp = (wl_rates_t *)gbuf->wldp_buf; 916*5895Syz147064 if (wrp->wl_rates_num > *val_cnt) { 917*5895Syz147064 status = DLADM_STATUS_TOOSMALL; 918*5895Syz147064 goto done; 919*5895Syz147064 } 920*5895Syz147064 921*5895Syz147064 if (wrp->wl_rates_rates[0] == 0) { 922*5895Syz147064 prop_val[0][0] = '\0'; 923*5895Syz147064 *val_cnt = 1; 924*5895Syz147064 goto done; 925*5895Syz147064 } 926*5895Syz147064 927*5895Syz147064 for (i = 0; i < wrp->wl_rates_num; i++) { 928*5895Syz147064 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 929*5895Syz147064 wrp->wl_rates_rates[i] % 2, 930*5895Syz147064 (float)wrp->wl_rates_rates[i] / 2); 931*5895Syz147064 } 932*5895Syz147064 *val_cnt = wrp->wl_rates_num; 9333448Sdh155122 934*5895Syz147064 done: 935*5895Syz147064 free(gbuf); 936*5895Syz147064 return (status); 937*5895Syz147064 } 938*5895Syz147064 939*5895Syz147064 static dladm_status_t 940*5895Syz147064 do_get_rate_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) 941*5895Syz147064 { 942*5895Syz147064 return (do_get_rate_common(linkid, prop_val, val_cnt, 943*5895Syz147064 WL_DESIRED_RATES)); 944*5895Syz147064 } 945*5895Syz147064 946*5895Syz147064 static dladm_status_t 947*5895Syz147064 do_get_rate_mod(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) 948*5895Syz147064 { 949*5895Syz147064 return (do_get_rate_common(linkid, prop_val, val_cnt, 950*5895Syz147064 WL_SUPPORTED_RATES)); 951*5895Syz147064 } 952*5895Syz147064 953*5895Syz147064 static dladm_status_t 954*5895Syz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates) 955*5895Syz147064 { 956*5895Syz147064 int i; 957*5895Syz147064 uint_t len; 958*5895Syz147064 wldp_t *gbuf; 959*5895Syz147064 wl_rates_t *wrp; 960*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 961*5895Syz147064 962*5895Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 963*5895Syz147064 return (DLADM_STATUS_NOMEM); 964*5895Syz147064 965*5895Syz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 9663448Sdh155122 967*5895Syz147064 wrp = (wl_rates_t *)gbuf->wldp_buf; 968*5895Syz147064 for (i = 0; i < rates->wr_cnt; i++) 969*5895Syz147064 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 970*5895Syz147064 wrp->wl_rates_num = rates->wr_cnt; 971*5895Syz147064 972*5895Syz147064 len = offsetof(wl_rates_t, wl_rates_rates) + 973*5895Syz147064 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 974*5895Syz147064 status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len, 975*5895Syz147064 WLAN_SET_PARAM, len); 976*5895Syz147064 977*5895Syz147064 free(gbuf); 978*5895Syz147064 return (status); 979*5895Syz147064 } 9803448Sdh155122 981*5895Syz147064 static dladm_status_t 982*5895Syz147064 do_set_rate_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) 983*5895Syz147064 { 984*5895Syz147064 dladm_wlan_rates_t rates; 985*5895Syz147064 dladm_status_t status; 986*5895Syz147064 987*5895Syz147064 if (val_cnt != 1) 988*5895Syz147064 return (DLADM_STATUS_BADVALCNT); 989*5895Syz147064 990*5895Syz147064 rates.wr_cnt = 1; 991*5895Syz147064 rates.wr_rates[0] = vdp[0].vd_val; 992*5895Syz147064 993*5895Syz147064 status = do_set_rate(linkid, &rates); 994*5895Syz147064 995*5895Syz147064 done: 996*5895Syz147064 return (status); 997*5895Syz147064 } 9983448Sdh155122 999*5895Syz147064 /* ARGSUSED */ 1000*5895Syz147064 static dladm_status_t 1001*5895Syz147064 do_check_rate(datalink_id_t linkid, char **prop_val, uint_t val_cnt, 1002*5895Syz147064 val_desc_t *vdp, boolean_t *needfreep) 1003*5895Syz147064 { 1004*5895Syz147064 int i; 1005*5895Syz147064 uint_t modval_cnt = MAX_SUPPORT_RATES; 1006*5895Syz147064 char *buf, **modval; 1007*5895Syz147064 dladm_status_t status; 1008*5895Syz147064 1009*5895Syz147064 if (val_cnt != 1) 1010*5895Syz147064 return (DLADM_STATUS_BADVALCNT); 1011*5895Syz147064 1012*5895Syz147064 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 1013*5895Syz147064 MAX_SUPPORT_RATES); 1014*5895Syz147064 if (buf == NULL) { 1015*5895Syz147064 status = DLADM_STATUS_NOMEM; 1016*5895Syz147064 goto done; 1017*5895Syz147064 } 10183448Sdh155122 1019*5895Syz147064 modval = (char **)(void *)buf; 1020*5895Syz147064 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 1021*5895Syz147064 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 1022*5895Syz147064 i * DLADM_STRSIZE; 1023*5895Syz147064 } 1024*5895Syz147064 1025*5895Syz147064 status = do_get_rate_mod(linkid, modval, &modval_cnt); 1026*5895Syz147064 if (status != DLADM_STATUS_OK) 1027*5895Syz147064 goto done; 1028*5895Syz147064 1029*5895Syz147064 for (i = 0; i < modval_cnt; i++) { 1030*5895Syz147064 if (strcasecmp(*prop_val, modval[i]) == 0) { 1031*5895Syz147064 vdp->vd_val = (uint_t)(atof(*prop_val) * 2); 1032*5895Syz147064 status = DLADM_STATUS_OK; 1033*5895Syz147064 1034*5895Syz147064 /* 1035*5895Syz147064 * Does not need the caller to free the vdp->vd_val 1036*5895Syz147064 */ 1037*5895Syz147064 *needfreep = B_FALSE; 10383448Sdh155122 break; 10393448Sdh155122 } 1040*5895Syz147064 } 1041*5895Syz147064 if (i == modval_cnt) 1042*5895Syz147064 status = DLADM_STATUS_BADVAL; 1043*5895Syz147064 done: 1044*5895Syz147064 free(buf); 1045*5895Syz147064 return (status); 1046*5895Syz147064 } 1047*5895Syz147064 1048*5895Syz147064 static dladm_status_t 1049*5895Syz147064 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf) 1050*5895Syz147064 { 1051*5895Syz147064 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG)); 1052*5895Syz147064 } 1053*5895Syz147064 1054*5895Syz147064 static dladm_status_t 1055*5895Syz147064 do_get_channel_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) 1056*5895Syz147064 { 1057*5895Syz147064 uint32_t channel; 1058*5895Syz147064 wldp_t *gbuf; 1059*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 1060*5895Syz147064 1061*5895Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1062*5895Syz147064 return (DLADM_STATUS_NOMEM); 1063*5895Syz147064 1064*5895Syz147064 if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK) 1065*5895Syz147064 goto done; 1066*5895Syz147064 1067*5895Syz147064 if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, 1068*5895Syz147064 &channel)) { 1069*5895Syz147064 status = DLADM_STATUS_NOTFOUND; 1070*5895Syz147064 goto done; 1071*5895Syz147064 } 1072*5895Syz147064 1073*5895Syz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 1074*5895Syz147064 *val_cnt = 1; 10753448Sdh155122 1076*5895Syz147064 done: 1077*5895Syz147064 free(gbuf); 1078*5895Syz147064 return (status); 1079*5895Syz147064 } 1080*5895Syz147064 1081*5895Syz147064 static dladm_status_t 1082*5895Syz147064 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf) 1083*5895Syz147064 { 1084*5895Syz147064 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE)); 1085*5895Syz147064 } 1086*5895Syz147064 1087*5895Syz147064 static dladm_status_t 1088*5895Syz147064 do_get_powermode_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) 1089*5895Syz147064 { 1090*5895Syz147064 wl_ps_mode_t *mode; 1091*5895Syz147064 const char *s; 1092*5895Syz147064 wldp_t *gbuf; 1093*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 1094*5895Syz147064 1095*5895Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1096*5895Syz147064 return (DLADM_STATUS_NOMEM); 1097*5895Syz147064 1098*5895Syz147064 if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK) 1099*5895Syz147064 goto done; 1100*5895Syz147064 1101*5895Syz147064 mode = (wl_ps_mode_t *)(gbuf->wldp_buf); 1102*5895Syz147064 switch (mode->wl_ps_mode) { 1103*5895Syz147064 case WL_PM_AM: 1104*5895Syz147064 s = "off"; 1105*5895Syz147064 break; 1106*5895Syz147064 case WL_PM_MPS: 1107*5895Syz147064 s = "max"; 1108*5895Syz147064 break; 1109*5895Syz147064 case WL_PM_FAST: 1110*5895Syz147064 s = "fast"; 11113448Sdh155122 break; 11123448Sdh155122 default: 1113*5895Syz147064 status = DLADM_STATUS_NOTFOUND; 1114*5895Syz147064 goto done; 1115*5895Syz147064 } 1116*5895Syz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1117*5895Syz147064 *val_cnt = 1; 1118*5895Syz147064 1119*5895Syz147064 done: 1120*5895Syz147064 free(gbuf); 1121*5895Syz147064 return (status); 1122*5895Syz147064 } 1123*5895Syz147064 1124*5895Syz147064 static dladm_status_t 1125*5895Syz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm) 1126*5895Syz147064 { 1127*5895Syz147064 wl_ps_mode_t ps_mode; 1128*5895Syz147064 1129*5895Syz147064 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 1130*5895Syz147064 1131*5895Syz147064 switch (*pm) { 1132*5895Syz147064 case DLADM_WLAN_PM_OFF: 1133*5895Syz147064 ps_mode.wl_ps_mode = WL_PM_AM; 11343448Sdh155122 break; 1135*5895Syz147064 case DLADM_WLAN_PM_MAX: 1136*5895Syz147064 ps_mode.wl_ps_mode = WL_PM_MPS; 1137*5895Syz147064 break; 1138*5895Syz147064 case DLADM_WLAN_PM_FAST: 1139*5895Syz147064 ps_mode.wl_ps_mode = WL_PM_FAST; 1140*5895Syz147064 break; 1141*5895Syz147064 default: 1142*5895Syz147064 return (DLADM_STATUS_NOTSUP); 11433448Sdh155122 } 1144*5895Syz147064 return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode, 1145*5895Syz147064 sizeof (ps_mode))); 1146*5895Syz147064 } 1147*5895Syz147064 1148*5895Syz147064 /* ARGSUSED */ 1149*5895Syz147064 static dladm_status_t 1150*5895Syz147064 do_set_powermode_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) 1151*5895Syz147064 { 1152*5895Syz147064 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 1153*5895Syz147064 dladm_status_t status; 1154*5895Syz147064 1155*5895Syz147064 if (val_cnt != 1) 1156*5895Syz147064 return (DLADM_STATUS_BADVALCNT); 1157*5895Syz147064 1158*5895Syz147064 status = do_set_powermode(linkid, &powermode); 11593448Sdh155122 11603448Sdh155122 return (status); 11613448Sdh155122 } 11623448Sdh155122 11633448Sdh155122 static dladm_status_t 1164*5895Syz147064 do_get_radio(datalink_id_t linkid, wldp_t *gbuf) 11653448Sdh155122 { 1166*5895Syz147064 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO)); 1167*5895Syz147064 } 11683448Sdh155122 1169*5895Syz147064 static dladm_status_t 1170*5895Syz147064 do_get_radio_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) 1171*5895Syz147064 { 1172*5895Syz147064 wl_radio_t radio; 1173*5895Syz147064 const char *s; 1174*5895Syz147064 wldp_t *gbuf; 1175*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 11763448Sdh155122 1177*5895Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1178*5895Syz147064 return (DLADM_STATUS_NOMEM); 11793448Sdh155122 1180*5895Syz147064 if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK) 1181*5895Syz147064 goto done; 11823448Sdh155122 1183*5895Syz147064 radio = *(wl_radio_t *)(gbuf->wldp_buf); 1184*5895Syz147064 switch (radio) { 1185*5895Syz147064 case B_TRUE: 1186*5895Syz147064 s = "on"; 1187*5895Syz147064 break; 1188*5895Syz147064 case B_FALSE: 1189*5895Syz147064 s = "off"; 1190*5895Syz147064 break; 1191*5895Syz147064 default: 1192*5895Syz147064 status = DLADM_STATUS_NOTFOUND; 1193*5895Syz147064 goto done; 1194*5895Syz147064 } 1195*5895Syz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1196*5895Syz147064 *val_cnt = 1; 11973448Sdh155122 1198*5895Syz147064 done: 1199*5895Syz147064 free(gbuf); 12003448Sdh155122 return (status); 12013448Sdh155122 } 12023448Sdh155122 12033448Sdh155122 static dladm_status_t 1204*5895Syz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio) 12053448Sdh155122 { 1206*5895Syz147064 wl_radio_t r; 12073448Sdh155122 1208*5895Syz147064 switch (*radio) { 1209*5895Syz147064 case DLADM_WLAN_RADIO_ON: 1210*5895Syz147064 r = B_TRUE; 1211*5895Syz147064 break; 1212*5895Syz147064 case DLADM_WLAN_RADIO_OFF: 1213*5895Syz147064 r = B_FALSE; 1214*5895Syz147064 break; 1215*5895Syz147064 default: 1216*5895Syz147064 return (DLADM_STATUS_NOTSUP); 1217*5895Syz147064 } 1218*5895Syz147064 return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r))); 1219*5895Syz147064 } 12203448Sdh155122 1221*5895Syz147064 /* ARGSUSED */ 1222*5895Syz147064 static dladm_status_t 1223*5895Syz147064 do_set_radio_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) 1224*5895Syz147064 { 1225*5895Syz147064 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 1226*5895Syz147064 dladm_status_t status; 12273448Sdh155122 1228*5895Syz147064 if (val_cnt != 1) 1229*5895Syz147064 return (DLADM_STATUS_BADVALCNT); 1230*5895Syz147064 1231*5895Syz147064 status = do_set_radio(linkid, &radio); 12323448Sdh155122 12333448Sdh155122 return (status); 12343448Sdh155122 } 12353448Sdh155122 1236*5895Syz147064 static dladm_status_t 1237*5895Syz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name, 1238*5895Syz147064 char **prop_val, uint_t val_cnt) 12393448Sdh155122 { 1240*5895Syz147064 char buf[MAXLINELEN]; 1241*5895Syz147064 int i; 1242*5895Syz147064 dladm_conf_t conf; 1243*5895Syz147064 dladm_status_t status; 12443448Sdh155122 1245*5895Syz147064 status = dladm_read_conf(linkid, &conf); 1246*5895Syz147064 if (status != DLADM_STATUS_OK) 1247*5895Syz147064 return (status); 12483448Sdh155122 1249*5895Syz147064 /* 1250*5895Syz147064 * reset case. 1251*5895Syz147064 */ 1252*5895Syz147064 if (val_cnt == 0) { 1253*5895Syz147064 status = dladm_unset_conf_field(conf, prop_name); 1254*5895Syz147064 if (status == DLADM_STATUS_OK) 1255*5895Syz147064 status = dladm_write_conf(conf); 1256*5895Syz147064 goto done; 1257*5895Syz147064 } 12583448Sdh155122 1259*5895Syz147064 buf[0] = '\0'; 1260*5895Syz147064 for (i = 0; i < val_cnt; i++) { 1261*5895Syz147064 (void) strlcat(buf, prop_val[i], MAXLINELEN); 1262*5895Syz147064 if (i != val_cnt - 1) 1263*5895Syz147064 (void) strlcat(buf, ",", MAXLINELEN); 12643448Sdh155122 } 12653448Sdh155122 1266*5895Syz147064 status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf); 1267*5895Syz147064 if (status == DLADM_STATUS_OK) 1268*5895Syz147064 status = dladm_write_conf(conf); 1269*5895Syz147064 1270*5895Syz147064 done: 1271*5895Syz147064 dladm_destroy_conf(conf); 1272*5895Syz147064 return (status); 12733448Sdh155122 } 1274*5895Syz147064 1275*5895Syz147064 static dladm_status_t 1276*5895Syz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name, 1277*5895Syz147064 char **prop_val, uint_t *val_cntp) 1278*5895Syz147064 { 1279*5895Syz147064 char buf[MAXLINELEN], *str; 1280*5895Syz147064 uint_t cnt = 0; 1281*5895Syz147064 dladm_conf_t conf; 1282*5895Syz147064 dladm_status_t status; 1283*5895Syz147064 1284*5895Syz147064 status = dladm_read_conf(linkid, &conf); 1285*5895Syz147064 if (status != DLADM_STATUS_OK) 1286*5895Syz147064 return (status); 1287*5895Syz147064 1288*5895Syz147064 status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN); 1289*5895Syz147064 if (status != DLADM_STATUS_OK) 1290*5895Syz147064 goto done; 1291*5895Syz147064 1292*5895Syz147064 str = strtok(buf, ","); 1293*5895Syz147064 while (str != NULL) { 1294*5895Syz147064 if (cnt == *val_cntp) { 1295*5895Syz147064 status = DLADM_STATUS_TOOSMALL; 1296*5895Syz147064 goto done; 1297*5895Syz147064 } 1298*5895Syz147064 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 1299*5895Syz147064 str = strtok(NULL, ","); 1300*5895Syz147064 } 1301*5895Syz147064 1302*5895Syz147064 *val_cntp = cnt; 1303*5895Syz147064 1304*5895Syz147064 done: 1305*5895Syz147064 dladm_destroy_conf(conf); 1306*5895Syz147064 return (status); 1307*5895Syz147064 } 1308