2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include <libintl.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <fcntl.h>
2N/A#include <stddef.h>
2N/A#include <string.h>
2N/A#include <stropts.h>
2N/A#include <libdevinfo.h>
2N/A#include <net/if.h>
2N/A#include <net/if_dl.h>
2N/A#include <net/if_types.h>
2N/A#include <libdlpi.h>
2N/A#include <libdllink.h>
2N/A#include <libscf.h>
2N/A#include <libdlwlan.h>
2N/A#include <libdladm_impl.h>
2N/A#include <libdlwlan_impl.h>
2N/A#include <net/wpa.h>
2N/A
2N/Astatic dladm_status_t wpa_instance_create(dladm_handle_t, datalink_id_t,
2N/A void *);
2N/Astatic dladm_status_t wpa_instance_delete(dladm_handle_t, datalink_id_t);
2N/A
2N/Astatic dladm_status_t do_get_bsstype(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_essid(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_bssid(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_signal(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_encryption(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_authmode(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_linkstatus(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_esslist(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_rate(dladm_handle_t, datalink_id_t, void *, int);
2N/Astatic dladm_status_t do_get_mode(dladm_handle_t, datalink_id_t, void *, int);
2N/Astatic dladm_status_t do_get_capability(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic dladm_status_t do_get_wpamode(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/A
2N/Astatic dladm_status_t do_set_bsstype(dladm_handle_t, datalink_id_t,
2N/A dladm_wlan_bsstype_t *);
2N/Astatic dladm_status_t do_set_authmode(dladm_handle_t, datalink_id_t,
2N/A dladm_wlan_auth_t *);
2N/Astatic dladm_status_t do_set_encryption(dladm_handle_t, datalink_id_t,
2N/A dladm_wlan_secmode_t *);
2N/Astatic dladm_status_t do_set_essid(dladm_handle_t, datalink_id_t,
2N/A dladm_wlan_essid_t *);
2N/Astatic dladm_status_t do_set_createibss(dladm_handle_t, datalink_id_t,
2N/A boolean_t *);
2N/Astatic dladm_status_t do_set_key(dladm_handle_t, datalink_id_t,
2N/A dladm_wlan_key_t *, uint_t);
2N/Astatic dladm_status_t do_set_channel(dladm_handle_t, datalink_id_t,
2N/A dladm_wlan_channel_t *);
2N/A
2N/Astatic dladm_status_t do_scan(dladm_handle_t, datalink_id_t, void *, int);
2N/Astatic dladm_status_t do_connect(dladm_handle_t, datalink_id_t, void *, int,
2N/A dladm_wlan_attr_t *, boolean_t, void *, uint_t,
2N/A int);
2N/Astatic dladm_status_t do_disconnect(dladm_handle_t, datalink_id_t, void *,
2N/A int);
2N/Astatic boolean_t find_val_by_name(const char *, val_desc_t *,
2N/A uint_t, uint_t *);
2N/Astatic boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **);
2N/Astatic void generate_essid(dladm_wlan_essid_t *);
2N/A
2N/Astatic dladm_status_t dladm_wlan_wlresult2status(wldp_t *);
2N/Astatic dladm_status_t dladm_wlan_validate(dladm_handle_t, datalink_id_t);
2N/A
2N/Astatic val_desc_t linkstatus_vals[] = {
2N/A { "disconnected", DLADM_WLAN_LINK_DISCONNECTED },
2N/A { "connected", DLADM_WLAN_LINK_CONNECTED }
2N/A};
2N/A
2N/Astatic val_desc_t secmode_vals[] = {
2N/A { "none", DLADM_WLAN_SECMODE_NONE },
2N/A { "wep", DLADM_WLAN_SECMODE_WEP },
2N/A { "wpa", DLADM_WLAN_SECMODE_WPA }
2N/A};
2N/A
2N/Astatic val_desc_t strength_vals[] = {
2N/A { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK },
2N/A { "weak", DLADM_WLAN_STRENGTH_WEAK },
2N/A { "good", DLADM_WLAN_STRENGTH_GOOD },
2N/A { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD },
2N/A { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT }
2N/A};
2N/A
2N/Astatic val_desc_t mode_vals[] = {
2N/A { "a", DLADM_WLAN_MODE_80211A },
2N/A { "b", DLADM_WLAN_MODE_80211B },
2N/A { "g", DLADM_WLAN_MODE_80211G },
2N/A { "n", DLADM_WLAN_MODE_80211GN },
2N/A { "n", DLADM_WLAN_MODE_80211AN }
2N/A};
2N/A
2N/Astatic val_desc_t auth_vals[] = {
2N/A { "open", DLADM_WLAN_AUTH_OPEN },
2N/A { "shared", DLADM_WLAN_AUTH_SHARED }
2N/A};
2N/A
2N/Astatic val_desc_t bsstype_vals[] = {
2N/A { "bss", DLADM_WLAN_BSSTYPE_BSS },
2N/A { "ibss", DLADM_WLAN_BSSTYPE_IBSS },
2N/A { "any", DLADM_WLAN_BSSTYPE_ANY }
2N/A};
2N/A
2N/A#define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
2N/A
2N/Astatic dladm_status_t
2N/Adladm_wlan_wlresult2status(wldp_t *gbuf)
2N/A{
2N/A switch (gbuf->wldp_result) {
2N/A case WL_SUCCESS:
2N/A return (DLADM_STATUS_OK);
2N/A
2N/A case WL_NOTSUPPORTED:
2N/A case WL_LACK_FEATURE:
2N/A return (DLADM_STATUS_NOTSUP);
2N/A
2N/A case WL_READONLY:
2N/A return (DLADM_STATUS_PROPRDONLY);
2N/A
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A return (DLADM_STATUS_FAILED);
2N/A}
2N/A
2N/Astatic dladm_wlan_mode_t
2N/Ado_convert_mode(wl_phy_conf_t *phyp)
2N/A{
2N/A wl_erp_t *wlep = &phyp->wl_phy_erp_conf;
2N/A wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
2N/A
2N/A switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) {
2N/A case WL_ERP:
2N/A return (wlep->wl_erp_ht_enabled ?
2N/A DLADM_WLAN_MODE_80211GN : DLADM_WLAN_MODE_80211G);
2N/A case WL_OFDM:
2N/A return (wlop->wl_ofdm_ht_enabled ?
2N/A DLADM_WLAN_MODE_80211AN : DLADM_WLAN_MODE_80211A);
2N/A case WL_DSSS:
2N/A case WL_FHSS:
2N/A return (DLADM_WLAN_MODE_80211B);
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A return (DLADM_WLAN_MODE_NONE);
2N/A}
2N/A
2N/Aboolean_t
2N/Ai_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp)
2N/A{
2N/A wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf;
2N/A wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
2N/A
2N/A switch (wlfp->wl_fhss_subtype) {
2N/A case WL_FHSS:
2N/A case WL_DSSS:
2N/A case WL_IRBASE:
2N/A case WL_HRDS:
2N/A case WL_ERP:
2N/A *channelp = wlfp->wl_fhss_channel;
2N/A break;
2N/A case WL_OFDM:
2N/A *channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency);
2N/A break;
2N/A default:
2N/A return (B_FALSE);
2N/A }
2N/A return (B_TRUE);
2N/A}
2N/A
2N/A#define IEEE80211_RATE 0x7f
2N/Astatic void
2N/Afill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp)
2N/A{
2N/A int i;
2N/A
2N/A (void) memset(attrp, 0, sizeof (*attrp));
2N/A
2N/A (void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN,
2N/A "%s", wlp->wl_ess_conf_essid.wl_essid_essid);
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
2N/A
2N/A (void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid,
2N/A DLADM_WLAN_BSSID_LEN);
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
2N/A
2N/A attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled ==
2N/A WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE);
2N/A if (wlp->wl_ess_conf_reserved[0] > 0)
2N/A attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
2N/A
2N/A attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ?
2N/A DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS);
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
2N/A
2N/A attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ?
2N/A DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED);
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
2N/A
2N/A attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl);
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
2N/A
2N/A attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf);
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
2N/A
2N/A for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) {
2N/A wlp->wl_supported_rates[i] &= IEEE80211_RATE;
2N/A if (wlp->wl_supported_rates[i] > attrp->wa_speed)
2N/A attrp->wa_speed = wlp->wl_supported_rates[i];
2N/A }
2N/A if (attrp->wa_speed > 0)
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
2N/A
2N/A if (i_dladm_wlan_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf,
2N/A &attrp->wa_channel))
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL;
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_scan(dladm_handle_t handle, datalink_id_t linkid, void *arg,
2N/A boolean_t (*func)(void *, dladm_wlan_attr_t *))
2N/A{
2N/A int i;
2N/A uint32_t count;
2N/A wl_ess_conf_t *wlp;
2N/A wl_ess_list_t *wls = NULL;
2N/A char buf[WLDP_BUFSIZE];
2N/A wl_linkstatus_t wl_status;
2N/A dladm_wlan_attr_t wlattr;
2N/A dladm_status_t status;
2N/A
2N/A if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A status = do_get_linkstatus(handle, linkid, &wl_status,
2N/A sizeof (wl_status));
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if ((status = do_scan(handle, linkid, buf, sizeof (buf))) !=
2N/A DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if (func == NULL) {
2N/A status = DLADM_STATUS_OK;
2N/A goto done;
2N/A }
2N/A
2N/A wls = malloc(WLDP_BUFSIZE);
2N/A if (wls == NULL) {
2N/A status = DLADM_STATUS_NOMEM;
2N/A goto done;
2N/A }
2N/A
2N/A if ((status = do_get_esslist(handle, linkid, wls, WLDP_BUFSIZE))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A wlp = wls->wl_ess_list_ess;
2N/A count = wls->wl_ess_list_num;
2N/A
2N/A for (i = 0; i < count; i++, wlp++) {
2N/A fill_wlan_attr(wlp, &wlattr);
2N/A if (!func(arg, &wlattr))
2N/A break;
2N/A }
2N/A
2N/A if (wl_status != WL_CONNECTED) {
2N/A status = do_get_linkstatus(handle, linkid, &wl_status,
2N/A sizeof (&wl_status));
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A if (wl_status == WL_CONNECTED)
2N/A (void) do_disconnect(handle, linkid, buf, sizeof (buf));
2N/A }
2N/A
2N/A status = DLADM_STATUS_OK;
2N/Adone:
2N/A free(wls);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Structures used in building the list of eligible WLANs to connect to.
2N/A * Specifically, `connect_state' has the WLAN attributes that must be matched
2N/A * (in `cs_attr') and a growing list of WLANs that matched those attributes
2N/A * chained through `cs_list'. Each element in the list is of type `attr_node'
2N/A * and has the matching WLAN's attributes and a pointer to the next element.
2N/A * For convenience, `cs_count' tracks the number of elements in the list.
2N/A */
2N/Atypedef struct attr_node {
2N/A dladm_wlan_attr_t an_attr;
2N/A struct attr_node *an_next;
2N/A} attr_node_t;
2N/A
2N/Atypedef struct connect_state {
2N/A dladm_wlan_attr_t *cs_attr;
2N/A uint_t cs_count;
2N/A attr_node_t *cs_list;
2N/A} connect_state_t;
2N/A
2N/A/*
2N/A * Compare two sets of WLAN attributes. For now, we only consider strength
2N/A * and speed (in that order), which matches the documented default policy for
2N/A * dladm_wlan_connect().
2N/A */
2N/Astatic int
2N/Aattr_compare(const void *p1, const void *p2)
2N/A{
2N/A dladm_wlan_attr_t *attrp1, *attrp2;
2N/A
2N/A attrp1 = (*(dladm_wlan_attr_t **)p1);
2N/A attrp2 = (*(dladm_wlan_attr_t **)p2);
2N/A
2N/A if (attrp1->wa_strength < attrp2->wa_strength)
2N/A return (1);
2N/A
2N/A if (attrp1->wa_strength > attrp2->wa_strength)
2N/A return (-1);
2N/A
2N/A return (attrp2->wa_speed - attrp1->wa_speed);
2N/A}
2N/A
2N/A/*
2N/A * Callback function used by dladm_wlan_connect() to filter out unwanted
2N/A * WLANs when scanning for available WLANs. Always returns B_TRUE to
2N/A * continue the scan.
2N/A */
2N/Astatic boolean_t
2N/Aconnect_cb(void *arg, dladm_wlan_attr_t *attrp)
2N/A{
2N/A attr_node_t *nodep;
2N/A dladm_wlan_attr_t *fattrp;
2N/A connect_state_t *statep = (connect_state_t *)arg;
2N/A
2N/A fattrp = statep->cs_attr;
2N/A if (fattrp == NULL)
2N/A goto append;
2N/A
2N/A if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid)
2N/A return (B_TRUE);
2N/A
2N/A if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 &&
2N/A strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes,
2N/A DLADM_WLAN_MAX_ESSID_LEN) != 0)
2N/A return (B_TRUE);
2N/A
2N/A if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
2N/A fattrp->wa_secmode != attrp->wa_secmode)
2N/A return (B_TRUE);
2N/A
2N/A if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 &&
2N/A fattrp->wa_mode != attrp->wa_mode)
2N/A return (B_TRUE);
2N/A
2N/A if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 &&
2N/A fattrp->wa_strength != attrp->wa_strength)
2N/A return (B_TRUE);
2N/A
2N/A if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 &&
2N/A fattrp->wa_speed != attrp->wa_speed)
2N/A return (B_TRUE);
2N/A
2N/A if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) {
2N/A attrp->wa_auth = fattrp->wa_auth;
2N/A attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
2N/A }
2N/A
2N/A if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
2N/A fattrp->wa_bsstype != attrp->wa_bsstype)
2N/A return (B_TRUE);
2N/A
2N/A if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 &&
2N/A memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes,
2N/A DLADM_WLAN_BSSID_LEN) != 0)
2N/A return (B_TRUE);
2N/Aappend:
2N/A nodep = malloc(sizeof (attr_node_t));
2N/A if (nodep == NULL)
2N/A return (B_TRUE);
2N/A
2N/A (void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t));
2N/A nodep->an_next = statep->cs_list;
2N/A statep->cs_list = nodep;
2N/A statep->cs_count++;
2N/A
2N/A return (B_TRUE);
2N/A}
2N/A
2N/A#define IEEE80211_C_WPA 0x01800000
2N/A
2N/Astatic dladm_status_t
2N/Ado_connect(dladm_handle_t handle, datalink_id_t linkid, void *buf, int bufsize,
2N/A dladm_wlan_attr_t *attrp, boolean_t create_ibss, void *keys,
2N/A uint_t key_count, int timeout)
2N/A{
2N/A dladm_wlan_secmode_t secmode;
2N/A dladm_wlan_auth_t authmode;
2N/A dladm_wlan_bsstype_t bsstype;
2N/A dladm_wlan_essid_t essid;
2N/A boolean_t essid_valid = B_FALSE;
2N/A dladm_status_t status;
2N/A dladm_wlan_channel_t channel;
2N/A hrtime_t start;
2N/A wl_capability_t *caps;
2N/A wl_linkstatus_t wl_status;
2N/A
2N/A if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) {
2N/A channel = attrp->wa_channel;
2N/A status = do_set_channel(handle, linkid, &channel);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto fail;
2N/A }
2N/A
2N/A secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ?
2N/A attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE;
2N/A
2N/A if ((status = do_set_encryption(handle, linkid, &secmode)) !=
2N/A DLADM_STATUS_OK)
2N/A goto fail;
2N/A
2N/A authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ?
2N/A attrp->wa_auth : DLADM_WLAN_AUTH_OPEN;
2N/A
2N/A if ((status = do_set_authmode(handle, linkid, &authmode)) !=
2N/A DLADM_STATUS_OK)
2N/A goto fail;
2N/A
2N/A bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ?
2N/A attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS;
2N/A
2N/A if ((status = do_set_bsstype(handle, linkid, &bsstype)) !=
2N/A DLADM_STATUS_OK)
2N/A goto fail;
2N/A
2N/A if (secmode == DLADM_WLAN_SECMODE_WEP) {
2N/A if (keys == NULL || key_count == 0 ||
2N/A key_count > MAX_NWEPKEYS) {
2N/A status = DLADM_STATUS_BADARG;
2N/A goto fail;
2N/A }
2N/A status = do_set_key(handle, linkid, keys, key_count);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto fail;
2N/A } else if (secmode == DLADM_WLAN_SECMODE_WPA) {
2N/A if (keys == NULL || key_count == 0 ||
2N/A key_count > MAX_NWEPKEYS) {
2N/A status = DLADM_STATUS_BADARG;
2N/A goto fail;
2N/A }
2N/A status = do_get_capability(handle, linkid, buf, bufsize);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto fail;
2N/A caps = (wl_capability_t *)buf;
2N/A if ((caps->caps & IEEE80211_C_WPA) == 0)
2N/A return (DLADM_STATUS_NOTSUP);
2N/A }
2N/A
2N/A if (create_ibss) {
2N/A status = do_set_channel(handle, linkid, &channel);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto fail;
2N/A
2N/A status = do_set_createibss(handle, linkid, &create_ibss);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto fail;
2N/A
2N/A if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) {
2N/A generate_essid(&essid);
2N/A essid_valid = B_TRUE;
2N/A }
2N/A }
2N/A
2N/A if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) {
2N/A essid = attrp->wa_essid;
2N/A essid_valid = B_TRUE;
2N/A }
2N/A
2N/A if (!essid_valid) {
2N/A status = DLADM_STATUS_FAILED;
2N/A goto fail;
2N/A }
2N/A
2N/A if ((status = do_set_essid(handle, linkid, &essid)) != DLADM_STATUS_OK)
2N/A goto fail;
2N/A
2N/A /*
2N/A * Because wpa daemon needs getting essid from driver,
2N/A * we need call do_set_essid() first, then call wpa_instance_create().
2N/A */
2N/A if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL)
2N/A (void) wpa_instance_create(handle, linkid, keys);
2N/A
2N/A start = gethrtime();
2N/A for (;;) {
2N/A status = do_get_linkstatus(handle, linkid, &wl_status,
2N/A sizeof (wl_status));
2N/A if (status != DLADM_STATUS_OK)
2N/A goto fail;
2N/A
2N/A if (wl_status == WL_CONNECTED)
2N/A break;
2N/A
2N/A (void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE);
2N/A if ((timeout >= 0) && (gethrtime() - start) /
2N/A NANOSEC >= timeout) {
2N/A status = DLADM_STATUS_TIMEDOUT;
2N/A goto fail;
2N/A }
2N/A }
2N/A status = DLADM_STATUS_OK;
2N/Afail:
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_connect(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_attr_t *attrp, int timeout, void *keys, uint_t key_count,
2N/A uint_t flags)
2N/A{
2N/A int i;
2N/A char buf[WLDP_BUFSIZE];
2N/A connect_state_t state = {0, NULL, NULL};
2N/A attr_node_t *nodep = NULL;
2N/A boolean_t create_ibss, set_authmode;
2N/A dladm_wlan_attr_t **wl_list = NULL;
2N/A dladm_status_t status;
2N/A wl_linkstatus_t wl_status;
2N/A
2N/A if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A if ((status = do_get_linkstatus(handle, linkid, &wl_status,
2N/A sizeof (wl_status))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if (wl_status == WL_CONNECTED) {
2N/A status = DLADM_STATUS_ISCONN;
2N/A goto done;
2N/A }
2N/A
2N/A set_authmode = ((attrp != NULL) &&
2N/A (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0);
2N/A create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 &&
2N/A attrp != NULL &&
2N/A (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
2N/A attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS);
2N/A
2N/A if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 ||
2N/A (create_ibss && attrp != NULL &&
2N/A (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) {
2N/A status = do_connect(handle, linkid, buf, sizeof (buf), attrp,
2N/A create_ibss, keys, key_count, timeout);
2N/A goto done;
2N/A }
2N/A
2N/A state.cs_attr = attrp;
2N/A state.cs_list = NULL;
2N/A state.cs_count = 0;
2N/A
2N/A status = dladm_wlan_scan(handle, linkid, &state, connect_cb);
2N/A if (status != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if (state.cs_count == 0) {
2N/A if (!create_ibss) {
2N/A status = DLADM_STATUS_NOTFOUND;
2N/A goto done;
2N/A }
2N/A status = do_connect(handle, linkid, buf, sizeof (buf),
2N/A attrp, create_ibss, keys, key_count, timeout);
2N/A goto done;
2N/A }
2N/A
2N/A wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *));
2N/A if (wl_list == NULL) {
2N/A status = DLADM_STATUS_NOMEM;
2N/A goto done;
2N/A }
2N/A
2N/A nodep = state.cs_list;
2N/A for (i = 0; i < state.cs_count; i++) {
2N/A wl_list[i] = &nodep->an_attr;
2N/A nodep = nodep->an_next;
2N/A }
2N/A qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *),
2N/A attr_compare);
2N/A
2N/A for (i = 0; i < state.cs_count; i++) {
2N/A dladm_wlan_attr_t *ap = wl_list[i];
2N/A
2N/A status = do_connect(handle, linkid, buf, sizeof (buf),
2N/A ap, create_ibss, keys, key_count, timeout);
2N/A if (status == DLADM_STATUS_OK)
2N/A break;
2N/A
2N/A if (!set_authmode) {
2N/A ap->wa_auth = DLADM_WLAN_AUTH_SHARED;
2N/A ap->wa_valid |= DLADM_WLAN_ATTR_AUTH;
2N/A status = do_connect(handle, linkid, buf, sizeof (buf),
2N/A ap, create_ibss, keys, key_count, timeout);
2N/A if (status == DLADM_STATUS_OK)
2N/A break;
2N/A }
2N/A }
2N/Adone:
2N/A if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN))
2N/A (void) do_disconnect(handle, linkid, buf, sizeof (buf));
2N/A
2N/A while (state.cs_list != NULL) {
2N/A nodep = state.cs_list;
2N/A state.cs_list = nodep->an_next;
2N/A free(nodep);
2N/A }
2N/A free(wl_list);
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_disconnect(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A char buf[WLDP_BUFSIZE];
2N/A dladm_status_t status;
2N/A wl_linkstatus_t wl_status;
2N/A
2N/A if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A if ((status = do_get_linkstatus(handle, linkid, &wl_status,
2N/A sizeof (wl_status))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if (wl_status != WL_CONNECTED) {
2N/A status = DLADM_STATUS_NOTCONN;
2N/A goto done;
2N/A }
2N/A
2N/A if ((status = do_disconnect(handle, linkid, buf, sizeof (buf)))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if ((status = do_get_linkstatus(handle, linkid, &wl_status,
2N/A sizeof (wl_status))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if (wl_status == WL_CONNECTED) {
2N/A status = DLADM_STATUS_FAILED;
2N/A goto done;
2N/A }
2N/A
2N/A status = DLADM_STATUS_OK;
2N/Adone:
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_get_linkattr(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_linkattr_t *attrp)
2N/A{
2N/A wl_rssi_t signal;
2N/A wl_bss_type_t bsstype;
2N/A wl_authmode_t authmode;
2N/A wl_encryption_t encryption;
2N/A wl_rates_t *ratesp = NULL;
2N/A dladm_wlan_attr_t *wl_attrp;
2N/A dladm_status_t status;
2N/A char buf[WLDP_BUFSIZE];
2N/A wl_essid_t wls;
2N/A wl_phy_conf_t wl_phy_conf;
2N/A wl_linkstatus_t wl_status;
2N/A
2N/A if (attrp == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A (void) memset(attrp, 0, sizeof (*attrp));
2N/A wl_attrp = &attrp->la_wlan_attr;
2N/A
2N/A if ((status = do_get_linkstatus(handle, linkid, &wl_status,
2N/A sizeof (wl_status))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS;
2N/A if (wl_status != WL_CONNECTED)
2N/A attrp->la_status = DLADM_WLAN_LINK_DISCONNECTED;
2N/A else
2N/A attrp->la_status = DLADM_WLAN_LINK_CONNECTED;
2N/A
2N/A if ((status = do_get_essid(handle, linkid, &wls, sizeof (wls)))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A (void) strlcpy(wl_attrp->wa_essid.we_bytes, wls.wl_essid_essid,
2N/A DLADM_WLAN_MAX_ESSID_LEN);
2N/A
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
2N/A
2N/A if ((status = do_get_bssid(handle, linkid, buf, sizeof (buf)))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A (void) memcpy(wl_attrp->wa_bssid.wb_bytes, buf, DLADM_WLAN_BSSID_LEN);
2N/A
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
2N/A
2N/A if (attrp->la_status == DLADM_WLAN_LINK_DISCONNECTED) {
2N/A attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
2N/A status = DLADM_STATUS_OK;
2N/A goto done;
2N/A }
2N/A
2N/A if ((status = do_get_encryption(handle, linkid, &encryption,
2N/A sizeof (encryption))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
2N/A
2N/A switch (encryption) {
2N/A case WL_NOENCRYPTION:
2N/A wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE;
2N/A break;
2N/A case WL_ENC_WEP:
2N/A wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP;
2N/A break;
2N/A case WL_ENC_WPA:
2N/A wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
2N/A break;
2N/A default:
2N/A wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE;
2N/A break;
2N/A }
2N/A
2N/A if ((status = do_get_signal(handle, linkid, &signal, sizeof (signal)))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
2N/A wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal);
2N/A
2N/A ratesp = malloc(WLDP_BUFSIZE);
2N/A if (ratesp == NULL) {
2N/A status = DLADM_STATUS_NOMEM;
2N/A goto done;
2N/A }
2N/A
2N/A if ((status = do_get_rate(handle, linkid, ratesp, WLDP_BUFSIZE))
2N/A != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A if (ratesp->wl_rates_num > 0) {
2N/A uint_t i, r = 0;
2N/A
2N/A for (i = 0; i < ratesp->wl_rates_num; i++) {
2N/A if (ratesp->wl_rates_rates[i] > r)
2N/A r = ratesp->wl_rates_rates[i];
2N/A }
2N/A wl_attrp->wa_speed = r;
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
2N/A }
2N/A
2N/A if ((status = do_get_authmode(handle, linkid, &authmode,
2N/A sizeof (authmode))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
2N/A
2N/A switch (authmode) {
2N/A case WL_OPENSYSTEM:
2N/A wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN;
2N/A break;
2N/A case WL_SHAREDKEY:
2N/A wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED;
2N/A break;
2N/A default:
2N/A wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH;
2N/A break;
2N/A }
2N/A
2N/A if ((status = do_get_bsstype(handle, linkid, &bsstype,
2N/A sizeof (bsstype))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
2N/A
2N/A switch (bsstype) {
2N/A case WL_BSS_BSS:
2N/A wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS;
2N/A break;
2N/A case WL_BSS_IBSS:
2N/A wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS;
2N/A break;
2N/A case WL_BSS_ANY:
2N/A wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY;
2N/A break;
2N/A default:
2N/A wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE;
2N/A break;
2N/A }
2N/A
2N/A if ((status = do_get_mode(handle, linkid, &wl_phy_conf,
2N/A sizeof (wl_phy_conf))) != DLADM_STATUS_OK)
2N/A goto done;
2N/A
2N/A wl_attrp->wa_mode = do_convert_mode(&wl_phy_conf);
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
2N/A if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE)
2N/A wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
2N/A
2N/A attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
2N/A status = DLADM_STATUS_OK;
2N/A
2N/Adone:
2N/A free(ratesp);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Check to see if the link is wireless.
2N/A */
2N/Astatic dladm_status_t
2N/Adladm_wlan_validate(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A uint32_t media;
2N/A dladm_status_t status;
2N/A
2N/A status = dladm_datalink_id2info(handle, linkid, NULL, NULL, &media,
2N/A NULL, 0);
2N/A if (status == DLADM_STATUS_OK) {
2N/A if (media != DL_WIFI)
2N/A status = DLADM_STATUS_LINKINVAL;
2N/A }
2N/A return (status);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Afind_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < cnt; i++) {
2N/A if (strcasecmp(str, vdp[i].vd_name) == 0) {
2N/A *valp = vdp[i].vd_val;
2N/A return (B_TRUE);
2N/A }
2N/A }
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Afind_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < cnt; i++) {
2N/A if (val == vdp[i].vd_val) {
2N/A *strp = vdp[i].vd_name;
2N/A return (B_TRUE);
2N/A }
2N/A }
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf)
2N/A{
2N/A (void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes);
2N/A return (buf);
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf)
2N/A{
2N/A return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN,
2N/A IFT_OTHER));
2N/A}
2N/A
2N/Astatic const char *
2N/Adladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
2N/A{
2N/A char *s;
2N/A
2N/A if (!find_name_by_val(val, vdp, cnt, &s))
2N/A s = "";
2N/A
2N/A (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
2N/A return (buf);
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf)
2N/A{
2N/A return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals,
2N/A VALCNT(secmode_vals), buf));
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf)
2N/A{
2N/A return (dladm_wlan_val2str((uint_t)*strength, strength_vals,
2N/A VALCNT(strength_vals), buf));
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf)
2N/A{
2N/A return (dladm_wlan_val2str((uint_t)*mode, mode_vals,
2N/A VALCNT(mode_vals), buf));
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf)
2N/A{
2N/A (void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2,
2N/A (float)(*speed) / 2);
2N/A return (buf);
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf)
2N/A{
2N/A return (dladm_wlan_val2str((uint_t)*auth, auth_vals,
2N/A VALCNT(auth_vals), buf));
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf)
2N/A{
2N/A return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals,
2N/A VALCNT(bsstype_vals), buf));
2N/A}
2N/A
2N/Aconst char *
2N/Adladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf)
2N/A{
2N/A return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals,
2N/A VALCNT(linkstatus_vals), buf));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid)
2N/A{
2N/A if (str[0] == '\0' || strlen(str) > DLADM_WLAN_MAX_ESSID_LEN - 1)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A (void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid)
2N/A{
2N/A int len;
2N/A uchar_t *buf;
2N/A
2N/A buf = _link_aton(str, &len);
2N/A if (buf == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (len != DLADM_WLAN_BSSID_LEN) {
2N/A free(buf);
2N/A return (DLADM_STATUS_BADARG);
2N/A }
2N/A
2N/A (void) memcpy(bssid->wb_bytes, buf, len);
2N/A free(buf);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode)
2N/A{
2N/A uint_t val;
2N/A
2N/A if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val))
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A *secmode = (dladm_wlan_secmode_t)val;
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength)
2N/A{
2N/A uint_t val;
2N/A
2N/A if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A *strength = (dladm_wlan_strength_t)val;
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode)
2N/A{
2N/A uint_t val;
2N/A
2N/A if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val))
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A *mode = (dladm_wlan_mode_t)val;
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed)
2N/A{
2N/A *speed = (dladm_wlan_speed_t)(atof(str) * 2);
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth)
2N/A{
2N/A uint_t val;
2N/A
2N/A if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A *auth = (dladm_wlan_auth_t)val;
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype)
2N/A{
2N/A uint_t val;
2N/A
2N/A if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A *bsstype = (dladm_wlan_bsstype_t)val;
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus)
2N/A{
2N/A uint_t val;
2N/A
2N/A if (!find_val_by_name(str, linkstatus_vals,
2N/A VALCNT(linkstatus_vals), &val)) {
2N/A return (DLADM_STATUS_BADARG);
2N/A }
2N/A
2N/A *linkstatus = (dladm_wlan_linkstatus_t)val;
2N/A return (DLADM_STATUS_OK);
2N/A}
2N/A
2N/Adladm_status_t
2N/Ai_dladm_wlan_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid,
2N/A wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen)
2N/A{
2N/A char linkname[MAXPATHLEN];
2N/A int fd, rc;
2N/A struct strioctl stri;
2N/A uint32_t flags;
2N/A dladm_status_t status;
2N/A uint32_t media;
2N/A char link[MAXLINKNAMELEN];
2N/A
2N/A if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
2N/A &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2N/A return (status);
2N/A }
2N/A
2N/A if (media != DL_WIFI)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A if (!(flags & DLADM_OPT_ACTIVE))
2N/A return (DLADM_STATUS_TEMPONLY);
2N/A
2N/A /*
2N/A * dlpi_open() is not used here because libdlpi depends on libdladm,
2N/A * and we do not want to introduce recursive dependencies.
2N/A */
2N/A (void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link);
2N/A if ((fd = open(linkname, O_RDWR)) < 0)
2N/A return (dladm_errno2status(errno));
2N/A
2N/A gbuf->wldp_type = NET_802_11;
2N/A gbuf->wldp_id = id;
2N/A gbuf->wldp_length = len;
2N/A
2N/A stri.ic_timout = 0;
2N/A stri.ic_dp = (char *)gbuf;
2N/A stri.ic_cmd = cmd;
2N/A stri.ic_len = cmdlen;
2N/A
2N/A if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
2N/A if (rc > 0) {
2N/A /*
2N/A * Non-negative return value indicates the specific
2N/A * operation failed and the reason for the failure
2N/A * was stored in gbuf->wldp_result.
2N/A */
2N/A status = dladm_wlan_wlresult2status(gbuf);
2N/A } else {
2N/A /*
2N/A * Negative return value indicates the ioctl failed.
2N/A */
2N/A status = dladm_errno2status(errno);
2N/A }
2N/A }
2N/A (void) close(fd);
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_cmd_ioctl(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen, uint_t cmd)
2N/A{
2N/A wldp_t *gbuf;
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A
2N/A if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A
2N/A (void) memset(gbuf, 0, MAX_BUF_LEN);
2N/A status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, cmd,
2N/A WLDP_BUFSIZE, WLAN_COMMAND, sizeof (wldp_t));
2N/A (void) memcpy(buf, gbuf->wldp_buf, buflen);
2N/A free(gbuf);
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_scan(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
2N/A{
2N/A return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_SCAN));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_disconnect(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A if (do_get_wpamode(handle, linkid, buf, buflen) == 0 &&
2N/A ((wl_wpa_t *)(buf))->wpa_flag > 0)
2N/A (void) wpa_instance_delete(handle, linkid);
2N/A
2N/A return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_DISASSOCIATE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_esslist(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESS_LIST,
2N/A buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_bssid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSID,
2N/A buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_essid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESSID,
2N/A buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_bsstype(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSTYPE,
2N/A buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_linkstatus(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_LINKSTATUS,
2N/A buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_rate(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf,
2N/A MAC_PROP_WL_DESIRED_RATES, buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_authmode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf,
2N/A MAC_PROP_WL_AUTH_MODE, buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_encryption(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf,
2N/A MAC_PROP_WL_ENCRYPTION, buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_signal(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RSSI,
2N/A buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_mode(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
2N/A buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_set_bsstype(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_bsstype_t *bsstype)
2N/A{
2N/A wl_bss_type_t ibsstype;
2N/A
2N/A switch (*bsstype) {
2N/A case DLADM_WLAN_BSSTYPE_BSS:
2N/A ibsstype = WL_BSS_BSS;
2N/A break;
2N/A case DLADM_WLAN_BSSTYPE_IBSS:
2N/A ibsstype = WL_BSS_IBSS;
2N/A break;
2N/A default:
2N/A ibsstype = WL_BSS_ANY;
2N/A break;
2N/A }
2N/A return (i_dladm_wlan_param(handle, linkid, &ibsstype,
2N/A MAC_PROP_WL_BSSTYPE, sizeof (ibsstype), B_TRUE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_set_authmode(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_auth_t *auth)
2N/A{
2N/A wl_authmode_t auth_mode;
2N/A
2N/A switch (*auth) {
2N/A case DLADM_WLAN_AUTH_OPEN:
2N/A auth_mode = WL_OPENSYSTEM;
2N/A break;
2N/A case DLADM_WLAN_AUTH_SHARED:
2N/A auth_mode = WL_SHAREDKEY;
2N/A break;
2N/A default:
2N/A return (DLADM_STATUS_NOTSUP);
2N/A }
2N/A return (i_dladm_wlan_param(handle, linkid, &auth_mode,
2N/A MAC_PROP_WL_AUTH_MODE, sizeof (auth_mode), B_TRUE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_set_encryption(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_secmode_t *secmode)
2N/A{
2N/A wl_encryption_t encryption;
2N/A
2N/A switch (*secmode) {
2N/A case DLADM_WLAN_SECMODE_NONE:
2N/A encryption = WL_NOENCRYPTION;
2N/A break;
2N/A case DLADM_WLAN_SECMODE_WEP:
2N/A encryption = WL_ENC_WEP;
2N/A break;
2N/A case DLADM_WLAN_SECMODE_WPA:
2N/A return (0);
2N/A default:
2N/A return (DLADM_STATUS_NOTSUP);
2N/A }
2N/A return (i_dladm_wlan_param(handle, linkid, &encryption,
2N/A MAC_PROP_WL_ENCRYPTION, sizeof (encryption), B_TRUE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_set_key(dladm_handle_t handle, datalink_id_t linkid, dladm_wlan_key_t *keys,
2N/A uint_t key_count)
2N/A{
2N/A int i;
2N/A wl_wep_key_t *wkp;
2N/A wl_wep_key_tab_t wepkey_tab;
2N/A dladm_wlan_key_t *kp;
2N/A
2N/A if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A (void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
2N/A for (i = 0; i < MAX_NWEPKEYS; i++)
2N/A wepkey_tab[i].wl_wep_operation = WL_NUL;
2N/A
2N/A for (i = 0; i < key_count; i++) {
2N/A kp = &keys[i];
2N/A if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS)
2N/A return (DLADM_STATUS_BADARG);
2N/A if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN &&
2N/A kp->wk_len != DLADM_WLAN_WEPKEY128_LEN)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A wkp = &wepkey_tab[kp->wk_idx - 1];
2N/A wkp->wl_wep_operation = WL_ADD;
2N/A wkp->wl_wep_length = kp->wk_len;
2N/A (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len);
2N/A }
2N/A
2N/A return (i_dladm_wlan_param(handle, linkid, &wepkey_tab,
2N/A MAC_PROP_WL_KEY_TAB, sizeof (wepkey_tab), B_TRUE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_set_essid(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_essid_t *essid)
2N/A{
2N/A wl_essid_t iessid;
2N/A
2N/A (void) memset(&iessid, 0, sizeof (essid));
2N/A
2N/A if (essid != NULL && essid->we_bytes[0] != '\0') {
2N/A iessid.wl_essid_length = strlen(essid->we_bytes);
2N/A (void) strlcpy(iessid.wl_essid_essid, essid->we_bytes,
2N/A sizeof (iessid.wl_essid_essid));
2N/A } else {
2N/A return (DLADM_STATUS_BADARG);
2N/A }
2N/A return (i_dladm_wlan_param(handle, linkid, &iessid, MAC_PROP_WL_ESSID,
2N/A sizeof (iessid), B_TRUE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_set_channel(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_channel_t *channel)
2N/A{
2N/A wl_phy_conf_t phy_conf;
2N/A
2N/A if (*channel > MAX_CHANNEL_NUM)
2N/A return (DLADM_STATUS_BADVAL);
2N/A
2N/A (void) memset(&phy_conf, 0xff, sizeof (phy_conf));
2N/A phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
2N/A
2N/A return (i_dladm_wlan_param(handle, linkid, &phy_conf,
2N/A MAC_PROP_WL_PHY_CONFIG, sizeof (phy_conf), B_TRUE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_set_createibss(dladm_handle_t handle, datalink_id_t linkid,
2N/A boolean_t *create_ibss)
2N/A{
2N/A wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
2N/A
2N/A return (i_dladm_wlan_param(handle, linkid, &cr, MAC_PROP_WL_CREATE_IBSS,
2N/A sizeof (cr), B_TRUE));
2N/A}
2N/A
2N/Astatic void
2N/Agenerate_essid(dladm_wlan_essid_t *essid)
2N/A{
2N/A srandom(gethrtime());
2N/A (void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
2N/A random());
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_capability(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_CAPABILITY,
2N/A buflen, B_FALSE));
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_get_wpamode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2N/A int buflen)
2N/A{
2N/A return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_WPA, buflen,
2N/A B_FALSE));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_wpa_get_sr(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_ess_t *sr, uint_t escnt, uint_t *estot)
2N/A{
2N/A int i, n;
2N/A wl_wpa_ess_t *es;
2N/A dladm_status_t status;
2N/A
2N/A es = malloc(WLDP_BUFSIZE);
2N/A if (es == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A
2N/A status = i_dladm_wlan_param(handle, linkid, es, MAC_PROP_WL_SCANRESULTS,
2N/A WLDP_BUFSIZE, B_FALSE);
2N/A
2N/A if (status == DLADM_STATUS_OK) {
2N/A n = (es->count > escnt) ? escnt : es->count;
2N/A for (i = 0; i < n; i ++) {
2N/A (void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid,
2N/A DLADM_WLAN_BSSID_LEN);
2N/A sr[i].we_ssid_len = es->ess[i].ssid_len;
2N/A (void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid,
2N/A es->ess[i].ssid_len);
2N/A sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len;
2N/A (void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie,
2N/A es->ess[i].wpa_ie_len);
2N/A sr[i].we_freq = es->ess[i].freq;
2N/A }
2N/A *estot = n;
2N/A }
2N/A
2N/A free(es);
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_wpa_set_ie(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint8_t *wpa_ie, uint_t wpa_ie_len)
2N/A{
2N/A wl_wpa_ie_t *ie;
2N/A uint_t len;
2N/A dladm_status_t status;
2N/A
2N/A if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN)
2N/A return (DLADM_STATUS_BADARG);
2N/A len = sizeof (wl_wpa_ie_t) + wpa_ie_len;
2N/A ie = malloc(len);
2N/A if (ie == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A
2N/A (void) memset(ie, 0, len);
2N/A ie->wpa_ie_len = wpa_ie_len;
2N/A (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len);
2N/A
2N/A status = i_dladm_wlan_param(handle, linkid, ie, MAC_PROP_WL_SETOPTIE,
2N/A len, B_TRUE);
2N/A free(ie);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_wpa_set_wpa(dladm_handle_t handle, datalink_id_t linkid,
2N/A boolean_t flag)
2N/A{
2N/A wl_wpa_t wpa;
2N/A
2N/A wpa.wpa_flag = flag;
2N/A return (i_dladm_wlan_param(handle, linkid, &wpa, MAC_PROP_WL_WPA,
2N/A sizeof (wpa), B_TRUE));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_wpa_del_key(dladm_handle_t handle, datalink_id_t linkid,
2N/A uint_t key_idx, const dladm_wlan_bssid_t *addr)
2N/A{
2N/A wl_del_key_t wk;
2N/A
2N/A wk.idk_keyix = key_idx;
2N/A if (addr != NULL)
2N/A (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes,
2N/A DLADM_WLAN_BSSID_LEN);
2N/A
2N/A return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_DELKEY,
2N/A sizeof (wk), B_TRUE));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_wpa_set_key(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_cipher_t cipher, const dladm_wlan_bssid_t *addr,
2N/A boolean_t set_tx, uint64_t seq, uint_t key_idx, uint8_t *key,
2N/A uint_t key_len)
2N/A{
2N/A wl_key_t wk;
2N/A
2N/A (void) memset(&wk, 0, sizeof (wl_key_t));
2N/A switch (cipher) {
2N/A case DLADM_WLAN_CIPHER_WEP:
2N/A wk.ik_type = IEEE80211_CIPHER_WEP;
2N/A break;
2N/A case DLADM_WLAN_CIPHER_TKIP:
2N/A wk.ik_type = IEEE80211_CIPHER_TKIP;
2N/A break;
2N/A case DLADM_WLAN_CIPHER_AES_OCB:
2N/A wk.ik_type = IEEE80211_CIPHER_AES_OCB;
2N/A break;
2N/A case DLADM_WLAN_CIPHER_AES_CCM:
2N/A wk.ik_type = IEEE80211_CIPHER_AES_CCM;
2N/A break;
2N/A case DLADM_WLAN_CIPHER_CKIP:
2N/A wk.ik_type = IEEE80211_CIPHER_CKIP;
2N/A break;
2N/A case DLADM_WLAN_CIPHER_NONE:
2N/A wk.ik_type = IEEE80211_CIPHER_NONE;
2N/A break;
2N/A default:
2N/A return (DLADM_STATUS_BADARG);
2N/A }
2N/A wk.ik_flags = IEEE80211_KEY_RECV;
2N/A if (set_tx) {
2N/A wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
2N/A (void) memcpy(wk.ik_macaddr, addr->wb_bytes,
2N/A DLADM_WLAN_BSSID_LEN);
2N/A } else
2N/A (void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN);
2N/A wk.ik_keyix = key_idx;
2N/A wk.ik_keylen = key_len;
2N/A (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */
2N/A (void) memcpy(wk.ik_keydata, key, key_len);
2N/A
2N/A return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_KEY,
2N/A sizeof (wk), B_TRUE));
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_wlan_wpa_set_mlme(dladm_handle_t handle, datalink_id_t linkid,
2N/A dladm_wlan_mlme_op_t op, dladm_wlan_reason_t reason,
2N/A dladm_wlan_bssid_t *bssid)
2N/A{
2N/A wl_mlme_t mlme;
2N/A
2N/A (void) memset(&mlme, 0, sizeof (wl_mlme_t));
2N/A switch (op) {
2N/A case DLADM_WLAN_MLME_ASSOC:
2N/A mlme.im_op = IEEE80211_MLME_ASSOC;
2N/A break;
2N/A case DLADM_WLAN_MLME_DISASSOC:
2N/A mlme.im_op = IEEE80211_MLME_DISASSOC;
2N/A break;
2N/A default:
2N/A return (DLADM_STATUS_BADARG);
2N/A }
2N/A mlme.im_reason = reason;
2N/A if (bssid != NULL)
2N/A (void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
2N/A DLADM_WLAN_BSSID_LEN);
2N/A
2N/A return (i_dladm_wlan_param(handle, linkid, &mlme, MAC_PROP_WL_MLME,
2N/A sizeof (mlme), B_TRUE));
2N/A}
2N/A
2N/A/*
2N/A * routines of create instance
2N/A */
2N/Astatic scf_propertygroup_t *
2N/Aadd_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
2N/A const char *pg_name, const char *pg_type)
2N/A{
2N/A scf_propertygroup_t *pg;
2N/A
2N/A pg = scf_pg_create(handle);
2N/A if (pg == NULL)
2N/A return (NULL);
2N/A
2N/A if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
2N/A scf_pg_destroy(pg);
2N/A return (NULL);
2N/A }
2N/A
2N/A return (pg);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Aadd_new_property(scf_handle_t *handle, const char *prop_name,
2N/A scf_type_t type, const char *val, scf_transaction_t *tx)
2N/A{
2N/A scf_value_t *value = NULL;
2N/A scf_transaction_entry_t *entry = NULL;
2N/A
2N/A entry = scf_entry_create(handle);
2N/A if (entry == NULL)
2N/A goto out;
2N/A
2N/A value = scf_value_create(handle);
2N/A if (value == NULL)
2N/A goto out;
2N/A
2N/A if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
2N/A goto out;
2N/A
2N/A if (scf_value_set_from_string(value, type, val) != 0)
2N/A goto out;
2N/A
2N/A if (scf_entry_add_value(entry, value) != 0)
2N/A goto out;
2N/A
2N/A return (DLADM_STATUS_OK);
2N/A
2N/Aout:
2N/A if (value != NULL)
2N/A scf_value_destroy(value);
2N/A if (entry != NULL)
2N/A scf_entry_destroy(entry);
2N/A
2N/A return (DLADM_STATUS_FAILED);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Aadd_pg_method(scf_handle_t *handle, scf_instance_t *instance,
2N/A const char *pg_name, const char *flags)
2N/A{
2N/A int rv, size;
2N/A dladm_status_t status = DLADM_STATUS_FAILED;
2N/A char *command = NULL;
2N/A scf_transaction_t *tran = NULL;
2N/A scf_propertygroup_t *pg;
2N/A
2N/A pg = add_property_group_to_instance(handle, instance,
2N/A pg_name, SCF_GROUP_METHOD);
2N/A if (pg == NULL)
2N/A goto out;
2N/A
2N/A tran = scf_transaction_create(handle);
2N/A if (tran == NULL)
2N/A goto out;
2N/A
2N/A size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1;
2N/A command = malloc(size);
2N/A if (command == NULL) {
2N/A status = DLADM_STATUS_NOMEM;
2N/A goto out;
2N/A }
2N/A (void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
2N/A
2N/A do {
2N/A if (scf_transaction_start(tran, pg) != 0)
2N/A goto out;
2N/A
2N/A if (add_new_property(handle, SCF_PROPERTY_EXEC,
2N/A SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) {
2N/A goto out;
2N/A }
2N/A
2N/A rv = scf_transaction_commit(tran);
2N/A switch (rv) {
2N/A case 1:
2N/A status = DLADM_STATUS_OK;
2N/A goto out;
2N/A case 0:
2N/A scf_transaction_destroy_children(tran);
2N/A if (scf_pg_update(pg) == -1) {
2N/A goto out;
2N/A }
2N/A break;
2N/A case -1:
2N/A default:
2N/A goto out;
2N/A }
2N/A } while (rv == 0);
2N/A
2N/Aout:
2N/A if (tran != NULL) {
2N/A scf_transaction_destroy_children(tran);
2N/A scf_transaction_destroy(tran);
2N/A }
2N/A
2N/A if (pg != NULL)
2N/A scf_pg_destroy(pg);
2N/A
2N/A if (command != NULL)
2N/A free(command);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ado_create_instance(scf_handle_t *handle, scf_service_t *svc,
2N/A const char *instance_name, const char *command)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_FAILED;
2N/A char *buf;
2N/A ssize_t max_fmri_len;
2N/A scf_instance_t *instance;
2N/A
2N/A instance = scf_instance_create(handle);
2N/A if (instance == NULL)
2N/A goto out;
2N/A
2N/A if (scf_service_add_instance(svc, instance_name, instance) != 0) {
2N/A if (scf_error() == SCF_ERROR_EXISTS)
2N/A /* Let the caller deal with the duplicate instance */
2N/A status = DLADM_STATUS_EXIST;
2N/A goto out;
2N/A }
2N/A
2N/A if (add_pg_method(handle, instance, "start",
2N/A command) != DLADM_STATUS_OK) {
2N/A goto out;
2N/A }
2N/A
2N/A /* enabling the instance */
2N/A max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2N/A if ((buf = malloc(max_fmri_len + 1)) == NULL)
2N/A goto out;
2N/A
2N/A if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
2N/A if ((smf_disable_instance(buf, 0) != 0) ||
2N/A (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) {
2N/A goto out;
2N/A }
2N/A status = DLADM_STATUS_OK;
2N/A }
2N/A
2N/Aout:
2N/A if (instance != NULL)
2N/A scf_instance_destroy(instance);
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Acreate_instance(const char *instance_name, const char *command)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_FAILED;
2N/A scf_service_t *svc = NULL;
2N/A scf_handle_t *handle = NULL;
2N/A
2N/A handle = scf_handle_create(SCF_VERSION);
2N/A if (handle == NULL)
2N/A goto out;
2N/A
2N/A if (scf_handle_bind(handle) == -1)
2N/A goto out;
2N/A
2N/A if ((svc = scf_service_create(handle)) == NULL)
2N/A goto out;
2N/A
2N/A if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
2N/A NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
2N/A goto out;
2N/A
2N/A status = do_create_instance(handle, svc, instance_name, command);
2N/A
2N/Aout:
2N/A if (svc != NULL)
2N/A scf_service_destroy(svc);
2N/A
2N/A if (handle != NULL) {
2N/A (void) scf_handle_unbind(handle);
2N/A scf_handle_destroy(handle);
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * routines of delete instance
2N/A */
2N/A#define DEFAULT_TIMEOUT 60000000
2N/A#define INIT_WAIT_USECS 50000
2N/A
2N/Astatic void
2N/Await_until_disabled(scf_handle_t *handle, char *fmri)
2N/A{
2N/A char *state;
2N/A useconds_t max;
2N/A useconds_t usecs;
2N/A uint64_t *cp = NULL;
2N/A scf_simple_prop_t *sp = NULL;
2N/A
2N/A max = DEFAULT_TIMEOUT;
2N/A
2N/A if (((sp = scf_simple_prop_get(handle, fmri, "stop",
2N/A SCF_PROPERTY_TIMEOUT)) != NULL) &&
2N/A ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
2N/A max = (*cp) * 1000000; /* convert to usecs */
2N/A
2N/A if (sp != NULL)
2N/A scf_simple_prop_free(sp);
2N/A
2N/A for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
2N/A /* incremental wait */
2N/A usecs *= 2;
2N/A usecs = (usecs > max) ? max : usecs;
2N/A
2N/A (void) usleep(usecs);
2N/A
2N/A /* Check state after the wait */
2N/A if ((state = smf_get_state(fmri)) != NULL) {
2N/A if (strcmp(state, "disabled") == 0)
2N/A return;
2N/A }
2N/A }
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Adelete_instance(const char *instance_name)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_FAILED;
2N/A char *buf;
2N/A ssize_t max_fmri_len;
2N/A scf_scope_t *scope = NULL;
2N/A scf_service_t *svc = NULL;
2N/A scf_handle_t *handle = NULL;
2N/A scf_instance_t *instance;
2N/A
2N/A handle = scf_handle_create(SCF_VERSION);
2N/A if (handle == NULL)
2N/A goto out;
2N/A
2N/A if (scf_handle_bind(handle) == -1)
2N/A goto out;
2N/A
2N/A if ((scope = scf_scope_create(handle)) == NULL)
2N/A goto out;
2N/A
2N/A if ((svc = scf_service_create(handle)) == NULL)
2N/A goto out;
2N/A
2N/A if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
2N/A goto out;
2N/A
2N/A if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
2N/A goto out;
2N/A
2N/A instance = scf_instance_create(handle);
2N/A if (instance == NULL)
2N/A goto out;
2N/A
2N/A if (scf_service_get_instance(svc, instance_name, instance) != 0) {
2N/A scf_error_t scf_errnum = scf_error();
2N/A
2N/A if (scf_errnum == SCF_ERROR_NOT_FOUND)
2N/A status = DLADM_STATUS_OK;
2N/A
2N/A scf_instance_destroy(instance);
2N/A goto out;
2N/A }
2N/A
2N/A max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2N/A if ((buf = malloc(max_fmri_len + 1)) == NULL) {
2N/A scf_instance_destroy(instance);
2N/A goto out;
2N/A }
2N/A
2N/A if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
2N/A char *state;
2N/A
2N/A state = smf_get_state(buf);
2N/A if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
2N/A strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) {
2N/A if (smf_disable_instance(buf, 0) == 0) {
2N/A /*
2N/A * Wait for some time till timeout to avoid
2N/A * a race with scf_instance_delete() below.
2N/A */
2N/A wait_until_disabled(handle, buf);
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (scf_instance_delete(instance) != 0) {
2N/A scf_instance_destroy(instance);
2N/A goto out;
2N/A }
2N/A
2N/A scf_instance_destroy(instance);
2N/A
2N/A status = DLADM_STATUS_OK;
2N/A
2N/Aout:
2N/A if (svc != NULL)
2N/A scf_service_destroy(svc);
2N/A
2N/A if (scope != NULL)
2N/A scf_scope_destroy(scope);
2N/A
2N/A if (handle != NULL) {
2N/A (void) scf_handle_unbind(handle);
2N/A scf_handle_destroy(handle);
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Awpa_instance_create(dladm_handle_t handle, datalink_id_t linkid, void *key)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_FAILED;
2N/A char *command = NULL;
2N/A char *wk_name = ((dladm_wlan_key_t *)key)->wk_name;
2N/A int size;
2N/A char instance_name[MAXLINKNAMELEN];
2N/A
2N/A /*
2N/A * Use the link name as the instance name of the network/wpad service.
2N/A */
2N/A status = dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
2N/A instance_name, sizeof (instance_name));
2N/A if (status != DLADM_STATUS_OK)
2N/A goto out;
2N/A
2N/A size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1;
2N/A command = malloc(size);
2N/A if (command == NULL) {
2N/A status = DLADM_STATUS_NOMEM;
2N/A goto out;
2N/A }
2N/A (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
2N/A
2N/A status = create_instance(instance_name, command);
2N/A if (status == DLADM_STATUS_EXIST) {
2N/A /*
2N/A * Delete the existing instance and create a new instance
2N/A * with the supplied arguments.
2N/A */
2N/A if ((status = delete_instance(instance_name)) ==
2N/A DLADM_STATUS_OK) {
2N/A status = create_instance(instance_name, command);
2N/A }
2N/A }
2N/A
2N/Aout:
2N/A if (command != NULL)
2N/A free(command);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Awpa_instance_delete(dladm_handle_t handle, datalink_id_t linkid)
2N/A{
2N/A char instance_name[MAXLINKNAMELEN];
2N/A
2N/A /*
2N/A * Get the instance name of the network/wpad service (the same as
2N/A * the link name).
2N/A */
2N/A if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
2N/A instance_name, sizeof (instance_name)) != DLADM_STATUS_OK)
2N/A return (DLADM_STATUS_FAILED);
2N/A
2N/A return (delete_instance(instance_name));
2N/A}