summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdladm/common/linkprop.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdladm/common/linkprop.c')
-rw-r--r--usr/src/lib/libdladm/common/linkprop.c1773
1 files changed, 973 insertions, 800 deletions
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c
index e624cec0ec..a05f6ce877 100644
--- a/usr/src/lib/libdladm/common/linkprop.c
+++ b/usr/src/lib/libdladm/common/linkprop.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,6 +29,7 @@
#include <strings.h>
#include <errno.h>
#include <ctype.h>
+#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dld.h>
@@ -39,721 +40,533 @@
#include <zone.h>
#include <libdllink.h>
#include <libdladm_impl.h>
+#include <libdlwlan_impl.h>
#include <libdlwlan.h>
+#include <libdlvlan.h>
#include <dlfcn.h>
#include <link.h>
+#include <inet/wifi_ioctl.h>
-static dladm_status_t i_dladm_set_prop_db(const char *, const char *,
- char **, uint_t);
-static dladm_status_t i_dladm_get_prop_db(const char *, const char *,
- char **, uint_t *);
-static dladm_status_t i_dladm_get_prop_temp(const char *, dladm_prop_type_t,
- const char *, char **, uint_t *);
-static dladm_status_t i_dladm_set_prop_temp(const char *, const char *,
- char **, uint_t, uint_t, char **);
-static boolean_t i_dladm_is_prop_temponly(const char *prop_name,
- char **);
+/*
+ * The linkprop get() callback.
+ * - propstrp: a property string array to keep the returned property.
+ * Caller allocated.
+ * - cntp: number of returned properties.
+ * Caller also uses it to indicate how many it expects.
+ */
+typedef dladm_status_t pd_getf_t(datalink_id_t, char **propstp, uint_t *cntp);
-typedef struct val_desc {
- char *vd_name;
- void *vd_val;
-} val_desc_t;
+/*
+ * The linkprop set() callback.
+ * - propval: a val_desc_t array which keeps the property values to be set.
+ * - cnt: number of properties to be set.
+ */
+typedef dladm_status_t pd_setf_t(datalink_id_t, val_desc_t *propval,
+ uint_t cnt);
-struct prop_desc;
+#define PD_TEMPONLY 0x1
-typedef dladm_status_t pd_getf_t(const char *, char **, uint_t *);
-typedef dladm_status_t pd_setf_t(const char *, val_desc_t *, uint_t);
-typedef dladm_status_t pd_checkf_t(struct prop_desc *, char **,
- uint_t, val_desc_t **);
+/*
+ * The linkprop check() callback.
+ * - propstrp: property string array which keeps the property to be checked.
+ * - cnt: number of properties.
+ * - propval: return value; the property values of the given property strings.
+ * - dofree: indicates whether the caller needs to free propvalp->vd_val.
+ */
+typedef dladm_status_t pd_checkf_t(datalink_id_t, char **propstrp,
+ uint_t cnt, val_desc_t *propval, boolean_t *dofree);
-static pd_getf_t do_get_zone;
-static pd_setf_t do_set_zone;
-static pd_checkf_t do_check_zone;
+static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod,
+ do_get_rate_prop, do_get_channel_prop,
+ do_get_powermode_prop, do_get_radio_prop;
+static pd_setf_t do_set_zone, do_set_autopush, do_set_rate_prop,
+ do_set_powermode_prop, do_set_radio_prop;
+static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate;
typedef struct prop_desc {
- char *pd_name;
- val_desc_t pd_defval;
- val_desc_t *pd_modval;
- uint_t pd_nmodval;
- boolean_t pd_temponly;
- pd_setf_t *pd_set;
- pd_getf_t *pd_getmod;
- pd_getf_t *pd_get;
- pd_checkf_t *pd_check;
+ /*
+ * link property name
+ */
+ char *pd_name;
+
+ /*
+ * default property value, can be set to { "", NULL }
+ */
+ val_desc_t pd_defval;
+
+ /*
+ * list of optional property values, can be NULL.
+ *
+ * This is set to non-NULL if there is a list of possible property
+ * values. pd_optval would point to the array of possible values.
+ */
+ val_desc_t *pd_optval;
+
+ /*
+ * count of the above optional property values. 0 if pd_optval is NULL.
+ */
+ uint_t pd_noptval;
+
+ /*
+ * callback to set link property;
+ * set to NULL if this property is read-only
+ */
+ pd_setf_t *pd_set;
+
+ /*
+ * callback to get modifiable link property
+ */
+ pd_getf_t *pd_getmod;
+
+ /*
+ * callback to get current link property
+ */
+ pd_getf_t *pd_get;
+
+ /*
+ * callback to validate link property value, set to NULL if pd_optval
+ * is not NULL. In that case, validate the value by comparing it with
+ * the pd_optval. Return a val_desc_t array pointer if the value is
+ * valid.
+ */
+ pd_checkf_t *pd_check;
+
+ /*
+ * currently only PD_TEMPONLY is valid, which indicates the property
+ * is temporary only.
+ */
+ uint_t pd_flags;
+
+ /*
+ * indicate link classes this property applies to.
+ */
+ datalink_class_t pd_class;
+
+ /*
+ * indicate link media type this property applies to.
+ */
+ datalink_media_t pd_dmedia;
} prop_desc_t;
+static val_desc_t dladm_wlan_radio_vals[] = {
+ { "on", DLADM_WLAN_RADIO_ON },
+ { "off", DLADM_WLAN_RADIO_OFF }
+};
+
+static val_desc_t dladm_wlan_powermode_vals[] = {
+ { "off", DLADM_WLAN_PM_OFF },
+ { "fast", DLADM_WLAN_PM_FAST },
+ { "max", DLADM_WLAN_PM_MAX }
+};
+
static prop_desc_t prop_table[] = {
- { "zone", { "", NULL }, NULL, 0, B_TRUE,
+
+ { "channel", { NULL, 0 }, NULL, 0, NULL, NULL,
+ do_get_channel_prop, NULL, 0,
+ DATALINK_CLASS_PHYS, DL_WIFI},
+
+ { "powermode", { "off", DLADM_WLAN_PM_OFF },
+ dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
+ do_set_powermode_prop, NULL,
+ do_get_powermode_prop, NULL, 0,
+ DATALINK_CLASS_PHYS, DL_WIFI},
+
+ { "radio", { "on", DLADM_WLAN_RADIO_ON },
+ dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
+ do_set_radio_prop, NULL,
+ do_get_radio_prop, NULL, 0,
+ DATALINK_CLASS_PHYS, DL_WIFI},
+
+ { "speed", { "", 0 }, NULL, 0,
+ do_set_rate_prop, do_get_rate_mod,
+ do_get_rate_prop, do_check_rate, 0,
+ DATALINK_CLASS_PHYS, DL_WIFI},
+
+ { "autopush", { "", NULL }, NULL, 0,
+ do_set_autopush, NULL,
+ do_get_autopush, do_check_autopush, 0,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE},
+
+ { "zone", { "", NULL }, NULL, 0,
do_set_zone, NULL,
- do_get_zone, do_check_zone}
+ do_get_zone, do_check_zone, PD_TEMPONLY,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE}
};
-#define MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t))
+#define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t))
-dladm_status_t
-dladm_set_prop(const char *link, const char *prop_name, char **prop_val,
- uint_t val_cnt, uint_t flags, char **errprop)
-{
- dladm_status_t status = DLADM_STATUS_BADARG;
+static dladm_status_t i_dladm_set_linkprop_db(datalink_id_t, const char *,
+ char **, uint_t);
+static dladm_status_t i_dladm_get_linkprop_db(datalink_id_t, const char *,
+ char **, uint_t *);
+static dladm_status_t i_dladm_set_single_prop(datalink_id_t, datalink_class_t,
+ uint32_t, prop_desc_t *, char **, uint_t, uint_t);
+static dladm_status_t i_dladm_set_linkprop(datalink_id_t, const char *,
+ char **, uint_t, uint_t);
- if (link == NULL || (prop_val == NULL && val_cnt > 0) ||
- (prop_val != NULL && val_cnt == 0) || flags == 0)
- return (DLADM_STATUS_BADARG);
+/*
+ * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
+ * rates to be retrieved. However, we cannot increase it at this
+ * time because it will break binary compatibility with unbundled
+ * WiFi drivers and utilities. So for now we define an additional
+ * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
+ */
+#define MAX_SUPPORT_RATES 64
- if ((flags & DLADM_OPT_TEMP) != 0) {
- status = i_dladm_set_prop_temp(link, prop_name, prop_val,
- val_cnt, flags, errprop);
- if (status == DLADM_STATUS_TEMPONLY &&
- (flags & DLADM_OPT_PERSIST) != 0)
- return (DLADM_STATUS_TEMPONLY);
+#define AP_ANCHOR "[anchor]"
+#define AP_DELIMITER '.'
- if (status == DLADM_STATUS_NOTFOUND) {
- status = DLADM_STATUS_BADARG;
- if (dladm_wlan_is_valid(link)) {
- status = dladm_wlan_set_prop(link, prop_name,
- prop_val, val_cnt, errprop);
+static dladm_status_t
+do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
+ val_desc_t *vdp)
+{
+ int i, j;
+ dladm_status_t status = DLADM_STATUS_OK;
+
+ for (j = 0; j < val_cnt; j++) {
+ for (i = 0; i < pdp->pd_noptval; i++) {
+ if (strcasecmp(*prop_val,
+ pdp->pd_optval[i].vd_name) == 0) {
+ break;
}
}
- if (status != DLADM_STATUS_OK)
- return (status);
+ if (i == pdp->pd_noptval) {
+ status = DLADM_STATUS_BADVAL;
+ goto done;
+ }
+ (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
}
- if ((flags & DLADM_OPT_PERSIST) != 0) {
- if (i_dladm_is_prop_temponly(prop_name, errprop))
- return (DLADM_STATUS_TEMPONLY);
- status = i_dladm_set_prop_db(link, prop_name,
- prop_val, val_cnt);
- }
+done:
return (status);
}
-dladm_status_t
-dladm_walk_prop(const char *link, void *arg,
- boolean_t (*func)(void *, const char *))
+static dladm_status_t
+i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
+ uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
+ uint_t flags)
{
- int i;
+ dladm_status_t status = DLADM_STATUS_OK;
+ val_desc_t *vdp = NULL;
+ boolean_t needfree = B_FALSE;
+ uint_t cnt, i;
- if (link == NULL || func == NULL)
+ if (!(pdp->pd_class & class))
return (DLADM_STATUS_BADARG);
- /* For wifi links, show wifi properties first */
- if (dladm_wlan_is_valid(link)) {
- dladm_status_t status;
-
- status = dladm_wlan_walk_prop(link, arg, func);
- if (status != DLADM_STATUS_OK)
- return (status);
- }
-
- /* Then show data-link properties if there are any */
- for (i = 0; i < MAX_PROPS; i++) {
- if (!func(arg, prop_table[i].pd_name))
- break;
- }
- return (DLADM_STATUS_OK);
-}
-
-dladm_status_t
-dladm_get_prop(const char *link, dladm_prop_type_t type,
- const char *prop_name, char **prop_val, uint_t *val_cntp)
-{
- dladm_status_t status;
-
- if (link == NULL || prop_name == NULL || prop_val == NULL ||
- val_cntp == NULL || *val_cntp == 0)
+ if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
return (DLADM_STATUS_BADARG);
- if (type == DLADM_PROP_VAL_PERSISTENT) {
- if (i_dladm_is_prop_temponly(prop_name, NULL))
- return (DLADM_STATUS_TEMPONLY);
- return (i_dladm_get_prop_db(link, prop_name,
- prop_val, val_cntp));
- }
+ if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
+ return (DLADM_STATUS_TEMPONLY);
- status = i_dladm_get_prop_temp(link, type, prop_name,
- prop_val, val_cntp);
- if (status != DLADM_STATUS_NOTFOUND)
- return (status);
+ if (!(flags & DLADM_OPT_ACTIVE))
+ return (DLADM_STATUS_OK);
- if (dladm_wlan_is_valid(link)) {
- return (dladm_wlan_get_prop(link, type, prop_name,
- prop_val, val_cntp));
- }
- return (DLADM_STATUS_BADARG);
-}
+ if (pdp->pd_set == NULL)
+ return (DLADM_STATUS_PROPRDONLY);
-/*
- * Data structures used for implementing persistent link properties
- */
-typedef struct linkprop_val {
- const char *lv_name;
- struct linkprop_val *lv_nextval;
-} linkprop_val_t;
-
-typedef struct linkprop_info {
- const char *li_name;
- struct linkprop_info *li_nextprop;
- struct linkprop_val *li_val;
-} linkprop_info_t;
-
-typedef struct linkprop_db_state linkprop_db_state_t;
-
-typedef boolean_t (*linkprop_db_op_t)(linkprop_db_state_t *,
- char *, linkprop_info_t *, dladm_status_t *);
-
-struct linkprop_db_state {
- linkprop_db_op_t ls_op;
- const char *ls_link;
- const char *ls_propname;
- char **ls_propval;
- uint_t *ls_valcntp;
-};
+ if (prop_val != NULL) {
+ vdp = malloc(sizeof (val_desc_t) * val_cnt);
+ if (vdp == NULL)
+ return (DLADM_STATUS_NOMEM);
-static void
-free_linkprops(linkprop_info_t *lip)
-{
- linkprop_info_t *lip_next;
- linkprop_val_t *lvp, *lvp_next;
-
- for (; lip != NULL; lip = lip_next) {
- lip_next = lip->li_nextprop;
- for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
- lvp_next = lvp->lv_nextval;
- free(lvp);
+ if (pdp->pd_check != NULL) {
+ status = pdp->pd_check(linkid, prop_val, val_cnt, vdp,
+ &needfree);
+ } else if (pdp->pd_optval != NULL) {
+ status = do_check_prop(pdp, prop_val, val_cnt, vdp);
+ } else {
+ status = DLADM_STATUS_BADARG;
}
- free(lip);
- }
-}
-/*
- * Generate an entry in the link property database.
- * Each entry has this format:
- * <linkname> <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
- */
-static void
-generate_linkprop_line(linkprop_db_state_t *lsp, char *buf,
- linkprop_info_t *listp, dladm_status_t *statusp)
-{
- char tmpbuf[MAXLINELEN];
- char *ptr, *lim = tmpbuf + MAXLINELEN;
- linkprop_info_t *lip = listp;
- linkprop_val_t *lvp = NULL;
+ if (status != DLADM_STATUS_OK)
+ goto done;
- /*
- * Delete line if there are no properties left.
- */
- if (lip == NULL ||
- (lip->li_val == NULL && lip->li_nextprop == NULL)) {
- buf[0] = '\0';
- return;
- }
- ptr = tmpbuf;
- ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", lsp->ls_link);
- for (; lip != NULL; lip = lip->li_nextprop) {
- /*
- * Skip properties without values.
- */
- if (lip->li_val == NULL)
- continue;
+ cnt = val_cnt;
+ } else {
+ if (pdp->pd_defval.vd_name == NULL)
+ return (DLADM_STATUS_NOTSUP);
- ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name);
- for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
- ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c",
- lvp->lv_name,
- ((lvp->lv_nextval == NULL) ? ';' : ','));
- }
+ if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
+ return (DLADM_STATUS_NOMEM);
+
+ (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
+ cnt = 1;
}
- if (ptr > lim) {
- *statusp = DLADM_STATUS_TOOSMALL;
- return;
+ status = pdp->pd_set(linkid, vdp, cnt);
+ if (needfree) {
+ for (i = 0; i < cnt; i++)
+ free((void *)(((val_desc_t *)vdp + i)->vd_val));
}
- (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
+done:
+ free(vdp);
+ return (status);
}
-/*
- * This function is used to update or create an entry in the persistent db.
- * process_linkprop_db() will first scan the db for an entry matching the
- * specified link. If a match is found, this function is invoked with the
- * entry's contents (buf) and its linked-list representation (listp). lsp
- * holds the name and values of the property to be added or updated; this
- * information will be merged with listp. Subsequently, an updated entry
- * will be written to buf, which will in turn be written to disk by
- * process_linkprop_db(). If no entry matches the specified link, listp
- * will be NULL; a new entry will be generated in this case and it will
- * contain only the property information in lsp.
- */
-static boolean_t
-process_linkprop_set(linkprop_db_state_t *lsp, char *buf,
- linkprop_info_t *listp, dladm_status_t *statusp)
+static dladm_status_t
+i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
+ char **prop_val, uint_t val_cnt, uint_t flags)
{
- dladm_status_t status;
- linkprop_info_t *lastp = NULL, *lip = listp, *nlip = NULL;
- linkprop_val_t **lvpp;
- int i;
-
- if (lsp->ls_propname == NULL) {
- buf[0] = '\0';
- return (B_FALSE);
- }
+ int i;
+ boolean_t found = B_FALSE;
+ datalink_class_t class;
+ uint32_t media;
+ dladm_status_t status = DLADM_STATUS_OK;
- /*
- * Find the linkprop we want to change.
- */
- for (; lip != NULL; lip = lip->li_nextprop) {
- if (strcmp(lip->li_name, lsp->ls_propname) == 0)
- break;
+ status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
+ if (status != DLADM_STATUS_OK)
+ return (status);
- lastp = lip;
- }
+ for (i = 0; i < DLADM_MAX_PROPS; i++) {
+ prop_desc_t *pdp = &prop_table[i];
+ dladm_status_t s;
- if (lip == NULL) {
- /*
- * If the linkprop is not found, append it to the list.
- */
- if ((nlip = malloc(sizeof (linkprop_info_t))) == NULL) {
- status = DLADM_STATUS_NOMEM;
- goto fail;
- }
- /*
- * nlip will need to be freed later if there is no list to
- * append to.
- */
- if (lastp != NULL)
- lastp->li_nextprop = nlip;
- nlip->li_name = lsp->ls_propname;
- nlip->li_nextprop = NULL;
- nlip->li_val = NULL;
- lvpp = &nlip->li_val;
- } else {
- linkprop_val_t *lvp, *lvp_next;
+ if (prop_name != NULL &&
+ (strcasecmp(prop_name, pdp->pd_name) != 0))
+ continue;
- /*
- * If the linkprop is found, delete the existing values from it.
- */
- for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
- lvp_next = lvp->lv_nextval;
- free(lvp);
- }
- lip->li_val = NULL;
- lvpp = &lip->li_val;
- }
+ found = B_TRUE;
+ s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
+ val_cnt, flags);
- /*
- * Fill our linkprop with the specified values.
- */
- for (i = 0; i < *lsp->ls_valcntp; i++) {
- if ((*lvpp = malloc(sizeof (linkprop_val_t))) == NULL) {
- status = DLADM_STATUS_NOMEM;
- goto fail;
+ if (prop_name != NULL) {
+ status = s;
+ break;
+ } else {
+ if (s != DLADM_STATUS_OK &&
+ s != DLADM_STATUS_NOTSUP)
+ status = s;
}
- (*lvpp)->lv_name = lsp->ls_propval[i];
- (*lvpp)->lv_nextval = NULL;
- lvpp = &(*lvpp)->lv_nextval;
}
+ if (!found)
+ status = DLADM_STATUS_NOTFOUND;
- if (listp != NULL) {
- generate_linkprop_line(lsp, buf, listp, statusp);
- } else {
- generate_linkprop_line(lsp, buf, nlip, statusp);
- free_linkprops(nlip);
- }
- return (B_FALSE);
-
-fail:
- *statusp = status;
- if (listp == NULL)
- free_linkprops(nlip);
-
- return (B_FALSE);
+ return (status);
}
/*
- * This function is used for retrieving the values for a specific property.
- * It gets called if an entry matching the specified link exists in the db.
- * The entry is converted into a linked-list listp. This list is then scanned
- * for the specified property name; if a matching property exists, its
- * associated values are copied to the array lsp->ls_propval.
+ * Set/reset link property for specific link
*/
-/* ARGSUSED */
-static boolean_t
-process_linkprop_get(linkprop_db_state_t *lsp, char *buf,
- linkprop_info_t *listp, dladm_status_t *statusp)
+dladm_status_t
+dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
+ uint_t val_cnt, uint_t flags)
{
- linkprop_info_t *lip = listp;
- linkprop_val_t *lvp;
- uint_t valcnt = 0;
+ dladm_status_t status = DLADM_STATUS_OK;
- /*
- * Find the linkprop we want to get.
- */
- for (; lip != NULL; lip = lip->li_nextprop) {
- if (strcmp(lip->li_name, lsp->ls_propname) == 0)
- break;
- }
- if (lip == NULL) {
- *statusp = DLADM_STATUS_NOTFOUND;
- return (B_FALSE);
+ if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
+ (prop_val == NULL && val_cnt > 0) ||
+ (prop_val != NULL && val_cnt == 0) ||
+ (prop_name == NULL && prop_val != NULL)) {
+ return (DLADM_STATUS_BADARG);
}
- for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
- (void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name,
- DLADM_PROP_VAL_MAX);
+ status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
+ val_cnt, flags);
+ if (status != DLADM_STATUS_OK)
+ return (status);
- if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) {
- *statusp = DLADM_STATUS_TOOSMALL;
- return (B_FALSE);
- }
+ if (flags & DLADM_OPT_PERSIST) {
+ status = i_dladm_set_linkprop_db(linkid, prop_name,
+ prop_val, val_cnt);
}
- /*
- * This function is meant to be called at most once for each call
- * to process_linkprop_db(). For this reason, it's ok to overwrite
- * the caller's valcnt array size with the actual number of values
- * returned.
- */
- *lsp->ls_valcntp = valcnt;
- return (B_FALSE);
+ return (status);
}
/*
- * This is used for initializing link properties.
- * Unlike the other routines, this gets called for every entry in the
- * database. lsp->ls_link is not user-specified but instead is set to
- * the current link being processed.
+ * Walk link properties of the given specific link.
*/
-/* ARGSUSED */
-static boolean_t
-process_linkprop_init(linkprop_db_state_t *lsp, char *buf,
- linkprop_info_t *listp, dladm_status_t *statusp)
+dladm_status_t
+dladm_walk_linkprop(datalink_id_t linkid, void *arg,
+ int (*func)(datalink_id_t, const char *, void *))
{
- dladm_status_t status = DLADM_STATUS_OK;
- linkprop_info_t *lip = listp;
- linkprop_val_t *lvp;
- uint_t valcnt, i;
- char **propval;
-
- for (; lip != NULL; lip = lip->li_nextprop) {
- /*
- * Construct the propval array and fill it with
- * values from listp.
- */
- for (lvp = lip->li_val, valcnt = 0;
- lvp != NULL; lvp = lvp->lv_nextval, valcnt++)
- ;
+ dladm_status_t status;
+ datalink_class_t class;
+ uint_t media;
+ int i;
- propval = malloc(sizeof (char *) * valcnt);
- if (propval == NULL) {
- *statusp = DLADM_STATUS_NOMEM;
- break;
- }
- lvp = lip->li_val;
- for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval)
- propval[i] = (char *)lvp->lv_name;
-
- status = dladm_set_prop(lsp->ls_link, lip->li_name,
- propval, valcnt, DLADM_OPT_TEMP, NULL);
-
- /*
- * We continue with initializing other properties even
- * after encountering an error. This error will be
- * propagated to the caller via 'statusp'.
- */
- if (status != DLADM_STATUS_OK)
- *statusp = status;
-
- free(propval);
- }
- return (B_TRUE);
-}
+ if (linkid == DATALINK_INVALID_LINKID || func == NULL)
+ return (DLADM_STATUS_BADARG);
-static int
-parse_linkprops(char *buf, linkprop_info_t **lipp)
-{
- int i, len;
- char *curr;
- linkprop_info_t *lip = NULL;
- linkprop_info_t **tailp = lipp;
- linkprop_val_t *lvp = NULL;
- linkprop_val_t **vtailp = NULL;
-
- curr = buf;
- len = strlen(buf);
- for (i = 0; i < len; i++) {
- char c = buf[i];
- boolean_t match = (c == '=' || c == ',' || c == ';');
+ status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
+ if (status != DLADM_STATUS_OK)
+ return (status);
- /*
- * Move to the next character if there is no match and
- * if we have not reached the last character.
- */
- if (!match && i != len - 1)
+ for (i = 0; i < DLADM_MAX_PROPS; i++) {
+ if (!(prop_table[i].pd_class & class))
continue;
- if (match) {
- /*
- * Nul-terminate the string pointed to by 'curr'.
- */
- buf[i] = '\0';
- if (*curr == '\0')
- goto fail;
- }
+ if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
+ continue;
- if (lip != NULL) {
- /*
- * We get here after we have processed the "<prop>="
- * pattern. The pattern we are now interested in is
- * "<val0>,<val1>,...,<valn>;". For each value we
- * find, a linkprop_val_t will be allocated and
- * added to the current 'lip'.
- */
- if (c == '=')
- goto fail;
-
- lvp = malloc(sizeof (*lvp));
- if (lvp == NULL)
- goto fail;
-
- lvp->lv_name = curr;
- lvp->lv_nextval = NULL;
- *vtailp = lvp;
- vtailp = &lvp->lv_nextval;
-
- if (c == ';') {
- tailp = &lip->li_nextprop;
- vtailp = NULL;
- lip = NULL;
- }
- } else {
- /*
- * lip == NULL indicates that 'curr' must be refering
- * to a property name. We allocate a new linkprop_info_t
- * append it to the list given by the caller.
- */
- if (c != '=')
- goto fail;
-
- lip = malloc(sizeof (*lip));
- if (lip == NULL)
- goto fail;
-
- lip->li_name = curr;
- lip->li_val = NULL;
- lip->li_nextprop = NULL;
- *tailp = lip;
- vtailp = &lip->li_val;
+ if (func(linkid, prop_table[i].pd_name, arg) ==
+ DLADM_WALK_TERMINATE) {
+ break;
}
- curr = buf + i + 1;
}
- /*
- * The list must be non-empty and the last character must be ';'.
- */
- if (*lipp == NULL || lip != NULL)
- goto fail;
-
- return (0);
-fail:
- free_linkprops(*lipp);
- *lipp = NULL;
- return (-1);
+ return (DLADM_STATUS_OK);
}
-static boolean_t
-process_linkprop_line(linkprop_db_state_t *lsp, char *buf,
- dladm_status_t *statusp)
+/*
+ * Get linkprop of the given specific link.
+ */
+dladm_status_t
+dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
+ const char *prop_name, char **prop_val, uint_t *val_cntp)
{
- linkprop_info_t *lip = NULL;
- int i, len, llen;
- char *str, *lasts;
- boolean_t cont, nolink = B_FALSE;
+ dladm_status_t status = DLADM_STATUS_OK;
+ datalink_class_t class;
+ uint_t media;
+ prop_desc_t *pdp;
+ uint_t cnt;
+ int i;
+
+ if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
+ prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
+ return (DLADM_STATUS_BADARG);
- /*
- * Skip leading spaces, blank lines, and comments.
- */
- len = strlen(buf);
- for (i = 0; i < len; i++) {
- if (!isspace(buf[i]))
+ for (i = 0; i < DLADM_MAX_PROPS; i++)
+ if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
break;
- }
- if (i == len || buf[i] == '#')
- return (B_TRUE);
- str = buf + i;
- if (lsp->ls_link != NULL) {
- /*
- * Skip links we're not interested in.
- * Note that strncmp() and isspace() are used here
- * instead of strtok() and strcmp() because we don't
- * want to modify buf in case it does not contain the
- * specified link.
- */
- llen = strlen(lsp->ls_link);
- if (strncmp(str, lsp->ls_link, llen) != 0 ||
- !isspace(str[llen]))
- return (B_TRUE);
- } else {
- /*
- * If a link is not specified, find the link name
- * and assign it to lsp->ls_link.
- */
- if (strtok_r(str, " \n\t", &lasts) == NULL)
- goto fail;
-
- llen = strlen(str);
- lsp->ls_link = str;
- nolink = B_TRUE;
- }
- str += llen + 1;
- if (str >= buf + len)
- goto fail;
-
- /*
- * Now find the list of link properties.
- */
- if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
- goto fail;
+ if (i == DLADM_MAX_PROPS)
+ return (DLADM_STATUS_NOTFOUND);
- if (parse_linkprops(str, &lip) < 0)
- goto fail;
+ pdp = &prop_table[i];
- cont = (*lsp->ls_op)(lsp, buf, lip, statusp);
- free_linkprops(lip);
- if (nolink)
- lsp->ls_link = NULL;
- return (cont);
+ status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
+ if (status != DLADM_STATUS_OK)
+ return (status);
-fail:
- free_linkprops(lip);
- if (nolink)
- lsp->ls_link = NULL;
+ if (!(pdp->pd_class & class))
+ return (DLADM_STATUS_BADARG);
- /*
- * Delete corrupted line.
- */
- buf[0] = '\0';
- return (B_TRUE);
-}
+ if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
+ return (DLADM_STATUS_BADARG);
-static dladm_status_t
-process_linkprop_db(void *arg, FILE *fp, FILE *nfp)
-{
- linkprop_db_state_t *lsp = arg;
- dladm_status_t status = DLADM_STATUS_OK;
- char buf[MAXLINELEN];
- boolean_t cont = B_TRUE;
+ switch (type) {
+ case DLADM_PROP_VAL_CURRENT:
+ status = pdp->pd_get(linkid, prop_val, val_cntp);
+ break;
- /*
- * This loop processes each line of the configuration file.
- * buf can potentially be modified by process_linkprop_line().
- * If this is a write operation and buf is not truncated, buf will
- * be written to disk. process_linkprop_line() will no longer be
- * called after it returns B_FALSE; at which point the remainder
- * of the file will continue to be read and, if necessary, written
- * to disk as well.
- */
- while (fgets(buf, MAXLINELEN, fp) != NULL) {
- if (cont)
- cont = process_linkprop_line(lsp, buf, &status);
+ case DLADM_PROP_VAL_DEFAULT:
+ if (pdp->pd_defval.vd_name == NULL) {
+ status = DLADM_STATUS_NOTSUP;
+ break;
+ }
+ (void) strcpy(*prop_val, pdp->pd_defval.vd_name);
+ *val_cntp = 1;
+ break;
- if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
- status = dladm_errno2status(errno);
+ case DLADM_PROP_VAL_MODIFIABLE:
+ if (pdp->pd_getmod != NULL) {
+ status = pdp->pd_getmod(linkid, prop_val, val_cntp);
break;
}
+ cnt = pdp->pd_noptval;
+ if (cnt == 0) {
+ status = DLADM_STATUS_NOTSUP;
+ } else if (cnt > *val_cntp) {
+ status = DLADM_STATUS_TOOSMALL;
+ } else {
+ for (i = 0; i < cnt; i++) {
+ (void) strcpy(prop_val[i],
+ pdp->pd_optval[i].vd_name);
+ }
+ *val_cntp = cnt;
+ }
+ break;
+ case DLADM_PROP_VAL_PERSISTENT:
+ if (pdp->pd_flags & PD_TEMPONLY)
+ return (DLADM_STATUS_TEMPONLY);
+ status = i_dladm_get_linkprop_db(linkid, prop_name,
+ prop_val, val_cntp);
+ break;
+ default:
+ status = DLADM_STATUS_BADARG;
+ break;
}
- if (status != DLADM_STATUS_OK || !cont)
- return (status);
+ return (status);
+}
- if (lsp->ls_op == process_linkprop_set) {
- /*
- * If the specified link is not found above, we add the
- * link and its properties to the configuration file.
- */
- (void) (*lsp->ls_op)(lsp, buf, NULL, &status);
- if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF)
- status = dladm_errno2status(errno);
- }
+/*ARGSUSED*/
+static int
+i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
+{
+ char *buf, **propvals;
+ uint_t i, valcnt = DLADM_MAX_PROP_VALCNT;
- if (lsp->ls_op == process_linkprop_get)
- status = DLADM_STATUS_NOTFOUND;
+ if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
+ DLADM_MAX_PROP_VALCNT)) == NULL) {
+ return (DLADM_WALK_CONTINUE);
+ }
- return (status);
-}
+ propvals = (char **)(void *)buf;
+ for (i = 0; i < valcnt; i++) {
+ propvals[i] = buf +
+ sizeof (char *) * DLADM_MAX_PROP_VALCNT +
+ i * DLADM_PROP_VAL_MAX;
+ }
-#define LINKPROP_RW_DB(statep, writeop) \
- (i_dladm_rw_db("/etc/dladm/linkprop.conf", \
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_linkprop_db, \
- (statep), (writeop)))
+ if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
+ propvals, &valcnt) != DLADM_STATUS_OK) {
+ goto done;
+ }
-static dladm_status_t
-i_dladm_set_prop_db(const char *link, const char *prop_name,
- char **prop_val, uint_t val_cnt)
-{
- linkprop_db_state_t state;
+ (void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
+ DLADM_OPT_ACTIVE);
- state.ls_op = process_linkprop_set;
- state.ls_link = link;
- state.ls_propname = prop_name;
- state.ls_propval = prop_val;
- state.ls_valcntp = &val_cnt;
+done:
+ if (buf != NULL)
+ free(buf);
- return (LINKPROP_RW_DB(&state, B_TRUE));
+ return (DLADM_WALK_CONTINUE);
}
-static dladm_status_t
-i_dladm_get_prop_db(const char *link, const char *prop_name,
- char **prop_val, uint_t *val_cntp)
+/*ARGSUSED*/
+static int
+i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
{
- linkprop_db_state_t state;
-
- state.ls_op = process_linkprop_get;
- state.ls_link = link;
- state.ls_propname = prop_name;
- state.ls_propval = prop_val;
- state.ls_valcntp = val_cntp;
-
- return (LINKPROP_RW_DB(&state, B_FALSE));
+ (void) dladm_init_linkprop(linkid);
+ return (DLADM_WALK_CONTINUE);
}
dladm_status_t
-dladm_init_linkprop(void)
+dladm_init_linkprop(datalink_id_t linkid)
{
- linkprop_db_state_t state;
-
- state.ls_op = process_linkprop_init;
- state.ls_link = NULL;
- state.ls_propname = NULL;
- state.ls_propval = NULL;
- state.ls_valcntp = NULL;
-
- return (LINKPROP_RW_DB(&state, B_FALSE));
+ if (linkid == DATALINK_ALL_LINKID) {
+ (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
+ DLADM_OPT_PERSIST);
+ } else {
+ (void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
+ }
+ return (DLADM_STATUS_OK);
}
static dladm_status_t
-i_dladm_get_zoneid(const char *link, zoneid_t *zidp)
+do_get_zone(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
{
- int fd;
- dld_hold_vlan_t dhv;
+ char zone_name[ZONENAME_MAX];
+ zoneid_t zid;
+ dladm_status_t status;
- if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
- return (dladm_errno2status(errno));
+ status = dladm_getzid(linkid, &zid);
+ if (status != DLADM_STATUS_OK)
+ return (status);
- bzero(&dhv, sizeof (dld_hold_vlan_t));
- (void) strlcpy(dhv.dhv_name, link, IFNAMSIZ);
- dhv.dhv_zid = -1;
+ *val_cnt = 1;
+ if (zid != GLOBAL_ZONEID) {
+ if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
+ return (dladm_errno2status(errno));
- if (i_dladm_ioctl(fd, DLDIOCZIDGET, &dhv, sizeof (dhv)) < 0) {
- if (errno == ENOENT) {
- *zidp = GLOBAL_ZONEID;
- } else {
- dladm_status_t status = dladm_errno2status(errno);
- (void) close(fd);
- return (status);
- }
+ (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
} else {
- *zidp = dhv.dhv_zid;
+ *prop_val[0] = '\0';
}
- (void) close(fd);
return (DLADM_STATUS_OK);
}
@@ -785,12 +598,14 @@ i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
}
static dladm_status_t
-i_dladm_add_deventry(zoneid_t zid, const char *link)
+i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
{
char path[MAXPATHLEN];
+ char name[MAXLINKNAMELEN];
di_prof_t prof = NULL;
char zone_name[ZONENAME_MAX];
dladm_status_t status;
+ int ret;
if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
return (dladm_errno2status(errno));
@@ -799,40 +614,20 @@ i_dladm_add_deventry(zoneid_t zid, const char *link)
if (di_prof_init(path, &prof) != 0)
return (dladm_errno2status(errno));
- status = DLADM_STATUS_OK;
- if (di_prof_add_dev(prof, link) != 0) {
- status = dladm_errno2status(errno);
+ status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
+ if (status != DLADM_STATUS_OK)
goto cleanup;
- }
- if (di_prof_commit(prof) != 0)
- status = dladm_errno2status(errno);
-cleanup:
- if (prof)
- di_prof_fini(prof);
-
- return (status);
-}
-
-static dladm_status_t
-i_dladm_remove_deventry(zoneid_t zid, const char *link)
-{
- char path[MAXPATHLEN];
- di_prof_t prof = NULL;
- char zone_name[ZONENAME_MAX];
- dladm_status_t status;
- if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
- return (dladm_errno2status(errno));
- if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
- return (dladm_errno2status(errno));
- if (di_prof_init(path, &prof) != 0)
- return (dladm_errno2status(errno));
+ if (add)
+ ret = di_prof_add_dev(prof, name);
+ else
+ ret = di_prof_add_exclude(prof, name);
- status = DLADM_STATUS_OK;
- if (di_prof_add_exclude(prof, link) != 0) {
+ if (ret != 0) {
status = dladm_errno2status(errno);
goto cleanup;
}
+
if (di_prof_commit(prof) != 0)
status = dladm_errno2status(errno);
cleanup:
@@ -843,102 +638,93 @@ cleanup:
}
static dladm_status_t
-do_get_zone(const char *link, char **prop_val, uint_t *val_cnt)
-{
- char zone_name[ZONENAME_MAX];
- zoneid_t zid;
- dladm_status_t status;
-
- status = i_dladm_get_zoneid(link, &zid);
- if (status != DLADM_STATUS_OK)
- return (status);
-
- *val_cnt = 1;
- if (zid != GLOBAL_ZONEID) {
- if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
- return (dladm_errno2status(errno));
-
- (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
- } else {
- *prop_val[0] = '\0';
- }
-
- return (DLADM_STATUS_OK);
-}
-
-static dladm_status_t
-do_set_zone(const char *link, val_desc_t *vdp, uint_t val_cnt)
+do_set_zone(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
{
dladm_status_t status;
zoneid_t zid_old, zid_new;
+ char link[MAXLINKNAMELEN];
if (val_cnt != 1)
return (DLADM_STATUS_BADVALCNT);
- status = i_dladm_get_zoneid(link, &zid_old);
+ status = dladm_getzid(linkid, &zid_old);
if (status != DLADM_STATUS_OK)
return (status);
/* Do nothing if setting to current value */
- zid_new = (intptr_t)(void *)vdp->vd_val;
+ zid_new = vdp->vd_val;
if (zid_new == zid_old)
return (DLADM_STATUS_OK);
- if (zid_old != GLOBAL_ZONEID) {
- if (dladm_rele_link(link, GLOBAL_ZONEID, B_TRUE) < 0)
- return (dladm_errno2status(errno));
+ if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
+ link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
+ return (status);
+ }
- if (zone_remove_datalink(zid_old, (char *)link) != 0 &&
+ if (zid_new != GLOBAL_ZONEID) {
+ /*
+ * If the new zoneid is the global zone, we could destroy
+ * the link (in the case of an implicitly-created VLAN) as a
+ * result of the dladm_setzid() operation. In that case,
+ * we defer the operation to the end of this function to avoid
+ * recreating the VLAN and getting a different linkid during
+ * the rollback if other operation fails.
+ *
+ * Otherwise, dladm_setzid() will hold a reference to the
+ * link and prevent a link renaming, so we need to do it
+ * before other operations.
+ */
+ status = dladm_setzid(link, zid_new);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+ }
+
+ if (zid_old != GLOBAL_ZONEID) {
+ if (zone_remove_datalink(zid_old, link) != 0 &&
errno != ENXIO) {
status = dladm_errno2status(errno);
goto rollback1;
}
- status = i_dladm_remove_deventry(zid_old, link);
- if (status != DLADM_STATUS_OK)
- goto rollback2;
+ /*
+ * It is okay to fail to update the /dev entry (some
+ * vanity-named links do not have a /dev entry).
+ */
+ (void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
}
if (zid_new != GLOBAL_ZONEID) {
- if (zone_add_datalink(zid_new, (char *)link) != 0) {
- status = dladm_errno2status(errno);
- goto rollback3;
- }
-
- if (dladm_hold_link(link, zid_new, B_TRUE) < 0) {
- (void) zone_remove_datalink(zid_new, (char *)link);
+ if (zone_add_datalink(zid_new, link) != 0) {
status = dladm_errno2status(errno);
- goto rollback3;
+ goto rollback2;
}
- status = i_dladm_add_deventry(zid_new, link);
- if (status != DLADM_STATUS_OK) {
- (void) dladm_rele_link(link, GLOBAL_ZONEID, B_FALSE);
- (void) zone_remove_datalink(zid_new, (char *)link);
- goto rollback3;
- }
+ (void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
+ } else {
+ status = dladm_setzid(link, zid_new);
+ if (status != DLADM_STATUS_OK)
+ goto rollback2;
}
+
return (DLADM_STATUS_OK);
-rollback3:
- if (zid_old != GLOBAL_ZONEID)
- (void) i_dladm_add_deventry(zid_old, link);
rollback2:
if (zid_old != GLOBAL_ZONEID)
- (void) zone_add_datalink(zid_old, (char *)link);
+ (void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
+ if (zid_old != GLOBAL_ZONEID)
+ (void) zone_add_datalink(zid_old, link);
rollback1:
- (void) dladm_hold_link(link, zid_old, B_FALSE);
-cleanexit:
+ if (zid_new != GLOBAL_ZONEID)
+ (void) dladm_setzid(link, zid_old);
return (status);
}
/* ARGSUSED */
static dladm_status_t
-do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
- val_desc_t **vdpp)
+do_check_zone(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
+ val_desc_t *vdp, boolean_t *needfreep)
{
- zoneid_t zid;
- val_desc_t *vdp = NULL;
+ zoneid_t zid;
if (val_cnt != 1)
return (DLADM_STATUS_BADVALCNT);
@@ -959,176 +745,563 @@ do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
}
}
- vdp = malloc(sizeof (val_desc_t));
- if (vdp == NULL)
- return (DLADM_STATUS_NOMEM);
-
- vdp->vd_val = (void *)(uintptr_t)zid;
- *vdpp = vdp;
+ vdp->vd_val = zid;
+ *needfreep = B_FALSE;
return (DLADM_STATUS_OK);
}
static dladm_status_t
-i_dladm_get_prop_temp(const char *link, dladm_prop_type_t type,
- const char *prop_name, char **prop_val, uint_t *val_cntp)
+do_get_autopush(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
{
- int i;
- dladm_status_t status;
- uint_t cnt;
- prop_desc_t *pdp;
+ dld_ioc_ap_t dia;
+ int fd, i, len;
- if (link == NULL || prop_name == NULL || prop_val == NULL ||
- val_cntp == NULL || *val_cntp == 0)
- return (DLADM_STATUS_BADARG);
+ if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+ return (dladm_errno2status(errno));
- for (i = 0; i < MAX_PROPS; i++)
- if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
- break;
+ *val_cnt = 1;
+ dia.dia_linkid = linkid;
+ if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) {
+ (*prop_val)[0] = '\0';
+ goto done;
+ }
- if (i == MAX_PROPS)
- return (DLADM_STATUS_NOTFOUND);
+ for (i = 0, len = 0; i < dia.dia_npush; i++) {
+ if (i != 0) {
+ (void) snprintf(*prop_val + len,
+ DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
+ len += 1;
+ }
+ (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
+ "%s", dia.dia_aplist[i]);
+ len += strlen(dia.dia_aplist[i]);
+ if (dia.dia_anchor - 1 == i) {
+ (void) snprintf(*prop_val + len,
+ DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
+ AP_ANCHOR);
+ len += (strlen(AP_ANCHOR) + 1);
+ }
+ }
- pdp = &prop_table[i];
- status = DLADM_STATUS_OK;
+done:
+ (void) close(fd);
+ return (DLADM_STATUS_OK);
+}
- switch (type) {
- case DLADM_PROP_VAL_CURRENT:
- status = pdp->pd_get(link, prop_val, val_cntp);
- break;
- case DLADM_PROP_VAL_DEFAULT:
- if (pdp->pd_defval.vd_name == NULL) {
- status = DLADM_STATUS_NOTSUP;
- break;
- }
- (void) strcpy(*prop_val, pdp->pd_defval.vd_name);
- *val_cntp = 1;
- break;
+static dladm_status_t
+do_set_autopush(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
+{
+ dld_ioc_ap_t dia;
+ struct dlautopush *dlap = (struct dlautopush *)vdp->vd_val;
+ dladm_status_t status = DLADM_STATUS_OK;
+ int fd, i;
+ int ic_cmd;
- case DLADM_PROP_VAL_MODIFIABLE:
- if (pdp->pd_getmod != NULL) {
- status = pdp->pd_getmod(link, prop_val, val_cntp);
- break;
- }
- cnt = pdp->pd_nmodval;
- if (cnt == 0) {
- status = DLADM_STATUS_NOTSUP;
- } else if (cnt > *val_cntp) {
- status = DLADM_STATUS_TOOSMALL;
- } else {
- for (i = 0; i < cnt; i++) {
- (void) strcpy(prop_val[i],
- pdp->pd_modval[i].vd_name);
- }
- *val_cntp = cnt;
+ if (val_cnt != 1)
+ return (DLADM_STATUS_BADVALCNT);
+
+ if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+ return (dladm_errno2status(errno));
+
+ dia.dia_linkid = linkid;
+ if (dlap != NULL) {
+ dia.dia_anchor = dlap->dap_anchor;
+ dia.dia_npush = dlap->dap_npush;
+ for (i = 0; i < dia.dia_npush; i++) {
+ (void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i],
+ FMNAMESZ+1);
}
- break;
- default:
- status = DLADM_STATUS_BADARG;
- break;
+ ic_cmd = DLDIOC_SETAUTOPUSH;
+ } else {
+ ic_cmd = DLDIOC_CLRAUTOPUSH;
}
+ if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0)
+ status = dladm_errno2status(errno);
+
+ (void) close(fd);
return (status);
}
-static dladm_status_t
-i_dladm_set_one_prop_temp(const char *link, prop_desc_t *pdp, char **prop_val,
- uint_t val_cnt, uint_t flags)
+/*
+ * Add the specified module to the dlautopush structure; returns a
+ * DLADM_STATUS_* code.
+ */
+dladm_status_t
+i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
{
- dladm_status_t status;
- val_desc_t *vdp = NULL;
- uint_t cnt;
+ if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
+ return (DLADM_STATUS_BADVAL);
- if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0)
- return (DLADM_STATUS_TEMPONLY);
+ if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
+ /*
+ * We don't allow multiple anchors, and the anchor must
+ * be after at least one module.
+ */
+ if (dlap->dap_anchor != 0)
+ return (DLADM_STATUS_BADVAL);
+ if (dlap->dap_npush == 0)
+ return (DLADM_STATUS_BADVAL);
- if (pdp->pd_set == NULL)
- return (DLADM_STATUS_PROPRDONLY);
+ dlap->dap_anchor = dlap->dap_npush;
+ return (DLADM_STATUS_OK);
+ }
+ if (dlap->dap_npush > MAXAPUSH)
+ return (DLADM_STATUS_BADVALCNT);
- if (prop_val != NULL) {
- if (pdp->pd_check != NULL)
- status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp);
- else
- status = DLADM_STATUS_BADARG;
+ (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
+ FMNAMESZ + 1);
+
+ return (DLADM_STATUS_OK);
+}
+
+/*
+ * Currently, both '.' and ' '(space) can be used as the delimiters between
+ * autopush modules. The former is used in dladm set-linkprop, and the
+ * latter is used in the autopush(1M) file.
+ */
+/* ARGSUSED */
+static dladm_status_t
+do_check_autopush(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
+ val_desc_t *vdp, boolean_t *needfreep)
+{
+ char *module;
+ struct dlautopush *dlap;
+ dladm_status_t status;
+ char val[DLADM_PROP_VAL_MAX];
+ char delimiters[4];
+
+ if (val_cnt != 1)
+ return (DLADM_STATUS_BADVALCNT);
+
+ dlap = malloc(sizeof (struct dlautopush));
+ if (dlap == NULL)
+ return (DLADM_STATUS_NOMEM);
+ (void) memset(dlap, 0, sizeof (struct dlautopush));
+ (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
+ bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
+ module = strtok(val, delimiters);
+ while (module != NULL) {
+ status = i_dladm_add_ap_module(module, dlap);
if (status != DLADM_STATUS_OK)
return (status);
+ module = strtok(NULL, delimiters);
+ }
- cnt = val_cnt;
- } else {
- if (pdp->pd_defval.vd_name == NULL)
- return (DLADM_STATUS_NOTSUP);
+ vdp->vd_val = (uintptr_t)dlap;
+ *needfreep = B_TRUE;
+ return (DLADM_STATUS_OK);
+}
- if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
- return (DLADM_STATUS_NOMEM);
+static dladm_status_t
+do_get_rate_common(datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
+ uint_t id)
+{
+ wl_rates_t *wrp;
+ uint_t i;
+ wldp_t *gbuf = NULL;
+ dladm_status_t status = DLADM_STATUS_OK;
- (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
- cnt = 1;
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
+ status = DLADM_STATUS_NOMEM;
+ goto done;
}
- status = pdp->pd_set(link, vdp, cnt);
+ status = i_dladm_wlan_get_ioctl(linkid, gbuf, id);
+ if (status != DLADM_STATUS_OK)
+ goto done;
- free(vdp);
+ wrp = (wl_rates_t *)gbuf->wldp_buf;
+ if (wrp->wl_rates_num > *val_cnt) {
+ status = DLADM_STATUS_TOOSMALL;
+ goto done;
+ }
+
+ if (wrp->wl_rates_rates[0] == 0) {
+ prop_val[0][0] = '\0';
+ *val_cnt = 1;
+ goto done;
+ }
+
+ for (i = 0; i < wrp->wl_rates_num; i++) {
+ (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
+ wrp->wl_rates_rates[i] % 2,
+ (float)wrp->wl_rates_rates[i] / 2);
+ }
+ *val_cnt = wrp->wl_rates_num;
+
+done:
+ free(gbuf);
return (status);
}
static dladm_status_t
-i_dladm_set_prop_temp(const char *link, const char *prop_name, char **prop_val,
- uint_t val_cnt, uint_t flags, char **errprop)
+do_get_rate_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
+{
+ return (do_get_rate_common(linkid, prop_val, val_cnt,
+ WL_DESIRED_RATES));
+}
+
+static dladm_status_t
+do_get_rate_mod(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
+{
+ return (do_get_rate_common(linkid, prop_val, val_cnt,
+ WL_SUPPORTED_RATES));
+}
+
+static dladm_status_t
+do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
{
- int i;
+ int i;
+ uint_t len;
+ wldp_t *gbuf;
+ wl_rates_t *wrp;
dladm_status_t status = DLADM_STATUS_OK;
- boolean_t found = B_FALSE;
- for (i = 0; i < MAX_PROPS; i++) {
- prop_desc_t *pdp = &prop_table[i];
- dladm_status_t s;
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
+ return (DLADM_STATUS_NOMEM);
- if (prop_name != NULL &&
- (strcasecmp(prop_name, pdp->pd_name) != 0))
- continue;
+ (void) memset(gbuf, 0, MAX_BUF_LEN);
- found = B_TRUE;
- s = i_dladm_set_one_prop_temp(link, pdp, prop_val, val_cnt,
- flags);
+ wrp = (wl_rates_t *)gbuf->wldp_buf;
+ for (i = 0; i < rates->wr_cnt; i++)
+ wrp->wl_rates_rates[i] = rates->wr_rates[i];
+ wrp->wl_rates_num = rates->wr_cnt;
- if (prop_name != NULL) {
- status = s;
+ len = offsetof(wl_rates_t, wl_rates_rates) +
+ (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
+ status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len,
+ WLAN_SET_PARAM, len);
+
+ free(gbuf);
+ return (status);
+}
+
+static dladm_status_t
+do_set_rate_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
+{
+ dladm_wlan_rates_t rates;
+ dladm_status_t status;
+
+ if (val_cnt != 1)
+ return (DLADM_STATUS_BADVALCNT);
+
+ rates.wr_cnt = 1;
+ rates.wr_rates[0] = vdp[0].vd_val;
+
+ status = do_set_rate(linkid, &rates);
+
+done:
+ return (status);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+do_check_rate(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
+ val_desc_t *vdp, boolean_t *needfreep)
+{
+ int i;
+ uint_t modval_cnt = MAX_SUPPORT_RATES;
+ char *buf, **modval;
+ dladm_status_t status;
+
+ if (val_cnt != 1)
+ return (DLADM_STATUS_BADVALCNT);
+
+ buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
+ MAX_SUPPORT_RATES);
+ if (buf == NULL) {
+ status = DLADM_STATUS_NOMEM;
+ goto done;
+ }
+
+ modval = (char **)(void *)buf;
+ for (i = 0; i < MAX_SUPPORT_RATES; i++) {
+ modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
+ i * DLADM_STRSIZE;
+ }
+
+ status = do_get_rate_mod(linkid, modval, &modval_cnt);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ for (i = 0; i < modval_cnt; i++) {
+ if (strcasecmp(*prop_val, modval[i]) == 0) {
+ vdp->vd_val = (uint_t)(atof(*prop_val) * 2);
+ status = DLADM_STATUS_OK;
+
+ /*
+ * Does not need the caller to free the vdp->vd_val
+ */
+ *needfreep = B_FALSE;
break;
- } else {
- if (s != DLADM_STATUS_OK &&
- s != DLADM_STATUS_NOTSUP) {
- if (errprop != NULL)
- *errprop = pdp->pd_name;
- status = s;
- break;
- }
}
}
+ if (i == modval_cnt)
+ status = DLADM_STATUS_BADVAL;
+done:
+ free(buf);
+ return (status);
+}
- if (!found)
+static dladm_status_t
+do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf)
+{
+ return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG));
+}
+
+static dladm_status_t
+do_get_channel_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
+{
+ uint32_t channel;
+ wldp_t *gbuf;
+ dladm_status_t status = DLADM_STATUS_OK;
+
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
+ return (DLADM_STATUS_NOMEM);
+
+ if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK)
+ goto done;
+
+ if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf,
+ &channel)) {
status = DLADM_STATUS_NOTFOUND;
+ goto done;
+ }
+ (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
+ *val_cnt = 1;
+
+done:
+ free(gbuf);
return (status);
}
-static boolean_t
-i_dladm_is_prop_temponly(const char *prop_name, char **errprop)
+static dladm_status_t
+do_get_powermode(datalink_id_t linkid, wldp_t *gbuf)
{
- int i;
+ return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE));
+}
- for (i = 0; i < MAX_PROPS; i++) {
- prop_desc_t *pdp = &prop_table[i];
+static dladm_status_t
+do_get_powermode_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
+{
+ wl_ps_mode_t *mode;
+ const char *s;
+ wldp_t *gbuf;
+ dladm_status_t status = DLADM_STATUS_OK;
- if (prop_name != NULL &&
- (strcasecmp(prop_name, pdp->pd_name) != 0))
- continue;
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
+ return (DLADM_STATUS_NOMEM);
+
+ if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK)
+ goto done;
+
+ mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
+ switch (mode->wl_ps_mode) {
+ case WL_PM_AM:
+ s = "off";
+ break;
+ case WL_PM_MPS:
+ s = "max";
+ break;
+ case WL_PM_FAST:
+ s = "fast";
+ break;
+ default:
+ status = DLADM_STATUS_NOTFOUND;
+ goto done;
+ }
+ (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
+ *val_cnt = 1;
+
+done:
+ free(gbuf);
+ return (status);
+}
+
+static dladm_status_t
+do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
+{
+ wl_ps_mode_t ps_mode;
- if (errprop != NULL)
- *errprop = pdp->pd_name;
+ (void) memset(&ps_mode, 0xff, sizeof (ps_mode));
- if (pdp->pd_temponly)
- return (B_TRUE);
+ switch (*pm) {
+ case DLADM_WLAN_PM_OFF:
+ ps_mode.wl_ps_mode = WL_PM_AM;
+ break;
+ case DLADM_WLAN_PM_MAX:
+ ps_mode.wl_ps_mode = WL_PM_MPS;
+ break;
+ case DLADM_WLAN_PM_FAST:
+ ps_mode.wl_ps_mode = WL_PM_FAST;
+ break;
+ default:
+ return (DLADM_STATUS_NOTSUP);
}
+ return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode,
+ sizeof (ps_mode)));
+}
- return (B_FALSE);
+/* ARGSUSED */
+static dladm_status_t
+do_set_powermode_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
+{
+ dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
+ dladm_status_t status;
+
+ if (val_cnt != 1)
+ return (DLADM_STATUS_BADVALCNT);
+
+ status = do_set_powermode(linkid, &powermode);
+
+ return (status);
+}
+
+static dladm_status_t
+do_get_radio(datalink_id_t linkid, wldp_t *gbuf)
+{
+ return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO));
+}
+
+static dladm_status_t
+do_get_radio_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
+{
+ wl_radio_t radio;
+ const char *s;
+ wldp_t *gbuf;
+ dladm_status_t status = DLADM_STATUS_OK;
+
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
+ return (DLADM_STATUS_NOMEM);
+
+ if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK)
+ goto done;
+
+ radio = *(wl_radio_t *)(gbuf->wldp_buf);
+ switch (radio) {
+ case B_TRUE:
+ s = "on";
+ break;
+ case B_FALSE:
+ s = "off";
+ break;
+ default:
+ status = DLADM_STATUS_NOTFOUND;
+ goto done;
+ }
+ (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
+ *val_cnt = 1;
+
+done:
+ free(gbuf);
+ return (status);
+}
+
+static dladm_status_t
+do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
+{
+ wl_radio_t r;
+
+ switch (*radio) {
+ case DLADM_WLAN_RADIO_ON:
+ r = B_TRUE;
+ break;
+ case DLADM_WLAN_RADIO_OFF:
+ r = B_FALSE;
+ break;
+ default:
+ return (DLADM_STATUS_NOTSUP);
+ }
+ return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r)));
+}
+
+/* ARGSUSED */
+static dladm_status_t
+do_set_radio_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
+{
+ dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
+ dladm_status_t status;
+
+ if (val_cnt != 1)
+ return (DLADM_STATUS_BADVALCNT);
+
+ status = do_set_radio(linkid, &radio);
+
+ return (status);
+}
+
+static dladm_status_t
+i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
+ char **prop_val, uint_t val_cnt)
+{
+ char buf[MAXLINELEN];
+ int i;
+ dladm_conf_t conf;
+ dladm_status_t status;
+
+ status = dladm_read_conf(linkid, &conf);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ /*
+ * reset case.
+ */
+ if (val_cnt == 0) {
+ status = dladm_unset_conf_field(conf, prop_name);
+ if (status == DLADM_STATUS_OK)
+ status = dladm_write_conf(conf);
+ goto done;
+ }
+
+ buf[0] = '\0';
+ for (i = 0; i < val_cnt; i++) {
+ (void) strlcat(buf, prop_val[i], MAXLINELEN);
+ if (i != val_cnt - 1)
+ (void) strlcat(buf, ",", MAXLINELEN);
+ }
+
+ status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
+ if (status == DLADM_STATUS_OK)
+ status = dladm_write_conf(conf);
+
+done:
+ dladm_destroy_conf(conf);
+ return (status);
+}
+
+static dladm_status_t
+i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
+ char **prop_val, uint_t *val_cntp)
+{
+ char buf[MAXLINELEN], *str;
+ uint_t cnt = 0;
+ dladm_conf_t conf;
+ dladm_status_t status;
+
+ status = dladm_read_conf(linkid, &conf);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ str = strtok(buf, ",");
+ while (str != NULL) {
+ if (cnt == *val_cntp) {
+ status = DLADM_STATUS_TOOSMALL;
+ goto done;
+ }
+ (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
+ str = strtok(NULL, ",");
+ }
+
+ *val_cntp = cnt;
+
+done:
+ dladm_destroy_conf(conf);
+ return (status);
}