16ba597c5SAnurag S. Maskey /*
26ba597c5SAnurag S. Maskey * CDDL HEADER START
36ba597c5SAnurag S. Maskey *
46ba597c5SAnurag S. Maskey * The contents of this file are subject to the terms of the
56ba597c5SAnurag S. Maskey * Common Development and Distribution License (the "License").
66ba597c5SAnurag S. Maskey * You may not use this file except in compliance with the License.
76ba597c5SAnurag S. Maskey *
86ba597c5SAnurag S. Maskey * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ba597c5SAnurag S. Maskey * or http://www.opensolaris.org/os/licensing.
106ba597c5SAnurag S. Maskey * See the License for the specific language governing permissions
116ba597c5SAnurag S. Maskey * and limitations under the License.
126ba597c5SAnurag S. Maskey *
136ba597c5SAnurag S. Maskey * When distributing Covered Code, include this CDDL HEADER in each
146ba597c5SAnurag S. Maskey * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ba597c5SAnurag S. Maskey * If applicable, add the following below this CDDL HEADER, with the
166ba597c5SAnurag S. Maskey * fields enclosed by brackets "[]" replaced with your own identifying
176ba597c5SAnurag S. Maskey * information: Portions Copyright [yyyy] [name of copyright owner]
186ba597c5SAnurag S. Maskey *
196ba597c5SAnurag S. Maskey * CDDL HEADER END
206ba597c5SAnurag S. Maskey */
216ba597c5SAnurag S. Maskey
226ba597c5SAnurag S. Maskey /*
2383ca9a11SAnurag S. Maskey * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
246ba597c5SAnurag S. Maskey */
256ba597c5SAnurag S. Maskey
266ba597c5SAnurag S. Maskey #include <assert.h>
276ba597c5SAnurag S. Maskey #include <ctype.h>
286ba597c5SAnurag S. Maskey #include <err.h>
296ba597c5SAnurag S. Maskey #include <errno.h>
306ba597c5SAnurag S. Maskey #include <execinfo.h>
316ba597c5SAnurag S. Maskey #include <kstat.h>
326ba597c5SAnurag S. Maskey #include <libdladm.h>
336ba597c5SAnurag S. Maskey #include <libdllink.h>
346ba597c5SAnurag S. Maskey #include <libdlstat.h>
356ba597c5SAnurag S. Maskey #include <libdlwlan.h>
366ba597c5SAnurag S. Maskey #include <libnwam.h>
376ba597c5SAnurag S. Maskey #include <limits.h>
386ba597c5SAnurag S. Maskey #include <pthread.h>
396ba597c5SAnurag S. Maskey #include <stdio.h>
406ba597c5SAnurag S. Maskey #include <stdlib.h>
416ba597c5SAnurag S. Maskey #include <string.h>
426ba597c5SAnurag S. Maskey #include <strings.h>
436ba597c5SAnurag S. Maskey #include <sys/stat.h>
446ba597c5SAnurag S. Maskey #include <sys/time.h>
456ba597c5SAnurag S. Maskey #include <sys/types.h>
466ba597c5SAnurag S. Maskey #include <unistd.h>
476ba597c5SAnurag S. Maskey #include <libdlpi.h>
486ba597c5SAnurag S. Maskey #include <ucontext.h>
496ba597c5SAnurag S. Maskey
506ba597c5SAnurag S. Maskey #include "events.h"
516ba597c5SAnurag S. Maskey #include "llp.h"
526ba597c5SAnurag S. Maskey #include "objects.h"
536ba597c5SAnurag S. Maskey #include "ncp.h"
546ba597c5SAnurag S. Maskey #include "ncu.h"
556ba597c5SAnurag S. Maskey #include "known_wlans.h"
566ba597c5SAnurag S. Maskey #include "util.h"
576ba597c5SAnurag S. Maskey
586ba597c5SAnurag S. Maskey /*
596ba597c5SAnurag S. Maskey * ncu_phys.c - contains routines that are physical-link specific.
606ba597c5SAnurag S. Maskey * Mostly WiFi code.
616ba597c5SAnurag S. Maskey */
626ba597c5SAnurag S. Maskey
636ba597c5SAnurag S. Maskey /*
646ba597c5SAnurag S. Maskey * Get link state from kstats. Used to determine initial link state for
656ba597c5SAnurag S. Maskey * cases where drivers do not support DL_NOTE_LINK_UP/DOWN. If link
666ba597c5SAnurag S. Maskey * state is LINK_STATE_UNKNOWN, we assume the link is up and the IP NCU
676ba597c5SAnurag S. Maskey * timeout will cause us to move on to other links.
686ba597c5SAnurag S. Maskey */
696ba597c5SAnurag S. Maskey link_state_t
nwamd_get_link_state(const char * name)706ba597c5SAnurag S. Maskey nwamd_get_link_state(const char *name)
716ba597c5SAnurag S. Maskey {
726ba597c5SAnurag S. Maskey kstat_ctl_t *kcp;
736ba597c5SAnurag S. Maskey kstat_t *ksp;
746ba597c5SAnurag S. Maskey char module[DLPI_LINKNAME_MAX];
756ba597c5SAnurag S. Maskey uint_t instance;
766ba597c5SAnurag S. Maskey link_state_t link_state = LINK_STATE_UNKNOWN;
776ba597c5SAnurag S. Maskey
786ba597c5SAnurag S. Maskey if ((kcp = kstat_open()) == NULL)
796ba597c5SAnurag S. Maskey return (link_state);
806ba597c5SAnurag S. Maskey
816ba597c5SAnurag S. Maskey if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
826ba597c5SAnurag S. Maskey goto out;
836ba597c5SAnurag S. Maskey
846ba597c5SAnurag S. Maskey if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL) {
856ba597c5SAnurag S. Maskey /*
866ba597c5SAnurag S. Maskey * The kstat query could fail if the underlying MAC
876ba597c5SAnurag S. Maskey * driver was already detached.
886ba597c5SAnurag S. Maskey */
896ba597c5SAnurag S. Maskey goto out;
906ba597c5SAnurag S. Maskey }
916ba597c5SAnurag S. Maskey
926ba597c5SAnurag S. Maskey if (kstat_read(kcp, ksp, NULL) == -1)
936ba597c5SAnurag S. Maskey goto out;
946ba597c5SAnurag S. Maskey
956ba597c5SAnurag S. Maskey (void) dladm_kstat_value(ksp, "link_state", KSTAT_DATA_UINT32,
966ba597c5SAnurag S. Maskey &link_state);
976ba597c5SAnurag S. Maskey
986ba597c5SAnurag S. Maskey out:
996ba597c5SAnurag S. Maskey (void) kstat_close(kcp);
1006ba597c5SAnurag S. Maskey
1016ba597c5SAnurag S. Maskey return (link_state);
1026ba597c5SAnurag S. Maskey }
1036ba597c5SAnurag S. Maskey
1046ba597c5SAnurag S. Maskey /*
1056ba597c5SAnurag S. Maskey * Set/unset link propeties. At present, these are MAC address, link MTU and
1066ba597c5SAnurag S. Maskey * autopush modules. We set MAC address last as setting it may cause a chip
1076ba597c5SAnurag S. Maskey * reset which can prevent other device property setting succeeding.
1086ba597c5SAnurag S. Maskey */
1096ba597c5SAnurag S. Maskey void
nwamd_set_unset_link_properties(nwamd_ncu_t * ncu,boolean_t set)1106ba597c5SAnurag S. Maskey nwamd_set_unset_link_properties(nwamd_ncu_t *ncu, boolean_t set)
1116ba597c5SAnurag S. Maskey {
112f6da83d4SAnurag S. Maskey dlpi_handle_t dh = ncu->ncu_link.nwamd_link_dhp;
113f6da83d4SAnurag S. Maskey char *addr = set ? ncu->ncu_link.nwamd_link_mac_addr : NULL;
114f6da83d4SAnurag S. Maskey uint64_t mtu = set ? ncu->ncu_link.nwamd_link_mtu : 0;
115f6da83d4SAnurag S. Maskey char **autopush = set ? ncu->ncu_link.nwamd_link_autopush : NULL;
116f6da83d4SAnurag S. Maskey uint_t num_autopush = set ? ncu->ncu_link.nwamd_link_num_autopush : 0;
1176ba597c5SAnurag S. Maskey uchar_t *hwaddr = NULL, curraddr[DLPI_PHYSADDR_MAX];
1186ba597c5SAnurag S. Maskey size_t hwaddrlen = DLPI_PHYSADDR_MAX;
1196ba597c5SAnurag S. Maskey int retval;
1206ba597c5SAnurag S. Maskey dladm_status_t status;
1216ba597c5SAnurag S. Maskey char mtustr[DLADM_PROP_VAL_MAX];
1226ba597c5SAnurag S. Maskey char *cp;
1236ba597c5SAnurag S. Maskey char errmsg[DLADM_STRSIZE];
1246ba597c5SAnurag S. Maskey uint_t cnt = 1;
1256ba597c5SAnurag S. Maskey
1266ba597c5SAnurag S. Maskey /*
1276ba597c5SAnurag S. Maskey * Set MTU here - either default value (if mtu == 0 indicating it has
1286ba597c5SAnurag S. Maskey * not been set) or specified value.
1296ba597c5SAnurag S. Maskey */
1306ba597c5SAnurag S. Maskey if (mtu == 0) {
1316ba597c5SAnurag S. Maskey cp = mtustr;
1326ba597c5SAnurag S. Maskey status = dladm_get_linkprop(dld_handle,
133f6da83d4SAnurag S. Maskey ncu->ncu_link.nwamd_link_id, DLADM_PROP_VAL_DEFAULT, "mtu",
134f6da83d4SAnurag S. Maskey &cp, &cnt);
1356ba597c5SAnurag S. Maskey if (status != DLADM_STATUS_OK) {
1366ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
1376ba597c5SAnurag S. Maskey "dladm_get_linkprop failed: %s",
1386ba597c5SAnurag S. Maskey dladm_status2str(status, errmsg));
1396ba597c5SAnurag S. Maskey return;
1406ba597c5SAnurag S. Maskey }
1416ba597c5SAnurag S. Maskey } else {
1426ba597c5SAnurag S. Maskey (void) snprintf(mtustr, DLADM_PROP_VAL_MAX, "%lld", mtu);
1436ba597c5SAnurag S. Maskey }
1446ba597c5SAnurag S. Maskey
1456ba597c5SAnurag S. Maskey cp = mtustr;
1466ba597c5SAnurag S. Maskey
1476ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_set_unset_link_properties: setting MTU of %s "
1486ba597c5SAnurag S. Maskey "for link %s", mtustr, ncu->ncu_name);
149f6da83d4SAnurag S. Maskey status = dladm_set_linkprop(dld_handle, ncu->ncu_link.nwamd_link_id,
150f6da83d4SAnurag S. Maskey "mtu", &cp, 1, DLADM_OPT_ACTIVE);
1516ba597c5SAnurag S. Maskey if (status != DLADM_STATUS_OK) {
1526ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
1536ba597c5SAnurag S. Maskey "dladm_set_linkprop failed: %s",
1546ba597c5SAnurag S. Maskey dladm_status2str(status, errmsg));
1556ba597c5SAnurag S. Maskey }
1566ba597c5SAnurag S. Maskey
1576ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_set_unset_link_properties: setting %d "
1586ba597c5SAnurag S. Maskey "autopush module for link %s", num_autopush, ncu->ncu_name);
159f6da83d4SAnurag S. Maskey status = dladm_set_linkprop(dld_handle, ncu->ncu_link.nwamd_link_id,
160f6da83d4SAnurag S. Maskey "autopush", autopush, num_autopush, DLADM_OPT_ACTIVE);
1616ba597c5SAnurag S. Maskey if (status != DLADM_STATUS_OK) {
1626ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
1636ba597c5SAnurag S. Maskey "dladm_set_linkprop failed for autopush property: %s",
1646ba597c5SAnurag S. Maskey dladm_status2str(status, errmsg));
1656ba597c5SAnurag S. Maskey }
1666ba597c5SAnurag S. Maskey
1676ba597c5SAnurag S. Maskey /*
1686ba597c5SAnurag S. Maskey * Set physical address - either factory (if link_mac_addr is NULL
1696ba597c5SAnurag S. Maskey * or we are unsetting properties) or specified MAC address string.
1706ba597c5SAnurag S. Maskey */
1716ba597c5SAnurag S. Maskey if (addr == NULL) {
1726ba597c5SAnurag S. Maskey if ((hwaddr = calloc(1, DLPI_PHYSADDR_MAX)) == NULL) {
1736ba597c5SAnurag S. Maskey nlog(LOG_ERR,
1746ba597c5SAnurag S. Maskey "nwamd_set_unset_link_properties: malloc() failed");
1756ba597c5SAnurag S. Maskey return;
1766ba597c5SAnurag S. Maskey }
1776ba597c5SAnurag S. Maskey if ((retval = dlpi_get_physaddr(dh, DL_FACT_PHYS_ADDR,
1786ba597c5SAnurag S. Maskey hwaddr, &hwaddrlen)) != DLPI_SUCCESS) {
1796ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
1806ba597c5SAnurag S. Maskey "could not get physical address for %s: %s",
1816ba597c5SAnurag S. Maskey ncu->ncu_name, dlpi_strerror(retval));
1826ba597c5SAnurag S. Maskey free(hwaddr);
1836ba597c5SAnurag S. Maskey return;
1846ba597c5SAnurag S. Maskey }
1856ba597c5SAnurag S. Maskey } else {
1866ba597c5SAnurag S. Maskey int addrlen = hwaddrlen;
1876ba597c5SAnurag S. Maskey if ((hwaddr = _link_aton(addr, &addrlen)) == NULL) {
1886ba597c5SAnurag S. Maskey if (addrlen == -1) {
1896ba597c5SAnurag S. Maskey nlog(LOG_ERR,
1906ba597c5SAnurag S. Maskey "nwamd_set_unset_link_properties: "
1916ba597c5SAnurag S. Maskey "%s: bad address for %s",
1926ba597c5SAnurag S. Maskey addr, ncu->ncu_name);
1936ba597c5SAnurag S. Maskey return;
1946ba597c5SAnurag S. Maskey } else {
1956ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_set_unset_link_properties:"
1966ba597c5SAnurag S. Maskey " malloc() failed");
1976ba597c5SAnurag S. Maskey return;
1986ba597c5SAnurag S. Maskey }
1996ba597c5SAnurag S. Maskey }
2006ba597c5SAnurag S. Maskey hwaddrlen = addrlen;
2016ba597c5SAnurag S. Maskey }
2026ba597c5SAnurag S. Maskey
2036ba597c5SAnurag S. Maskey /*
2046ba597c5SAnurag S. Maskey * Only set physical address if desired address differs from current -
2056ba597c5SAnurag S. Maskey * this avoids unnecessary chip resets for some drivers.
2066ba597c5SAnurag S. Maskey */
2076ba597c5SAnurag S. Maskey retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, curraddr,
2086ba597c5SAnurag S. Maskey &hwaddrlen);
2096ba597c5SAnurag S. Maskey if (retval != DLPI_SUCCESS || bcmp(curraddr, hwaddr, hwaddrlen) != 0) {
2106ba597c5SAnurag S. Maskey retval = dlpi_set_physaddr(dh, DL_CURR_PHYS_ADDR, hwaddr,
2116ba597c5SAnurag S. Maskey hwaddrlen);
2126ba597c5SAnurag S. Maskey if (retval != DLPI_SUCCESS) {
2136ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_set_unset_link_properties:"
2146ba597c5SAnurag S. Maskey "failed setting mac address on %s: %s",
2156ba597c5SAnurag S. Maskey ncu->ncu_name, dlpi_strerror(retval));
2166ba597c5SAnurag S. Maskey }
2176ba597c5SAnurag S. Maskey }
2186ba597c5SAnurag S. Maskey free(hwaddr);
2196ba597c5SAnurag S. Maskey }
2206ba597c5SAnurag S. Maskey
2216ba597c5SAnurag S. Maskey #define WLAN_ENC(sec) \
2226ba597c5SAnurag S. Maskey ((sec == DLADM_WLAN_SECMODE_WPA ? "WPA" : \
2236ba597c5SAnurag S. Maskey (sec == DLADM_WLAN_SECMODE_WEP ? "WEP" : "none")))
2246ba597c5SAnurag S. Maskey
2256ba597c5SAnurag S. Maskey #define NEED_ENC(sec) \
2266ba597c5SAnurag S. Maskey (sec == DLADM_WLAN_SECMODE_WPA || sec == DLADM_WLAN_SECMODE_WEP)
2276ba597c5SAnurag S. Maskey
2286ba597c5SAnurag S. Maskey #define WIRELESS_LAN_INIT_COUNT 8
2296ba597c5SAnurag S. Maskey
2306ba597c5SAnurag S. Maskey /*
2316ba597c5SAnurag S. Maskey * The variable wireless_scan_level specifies the signal level
2326ba597c5SAnurag S. Maskey * that we will initiate connections to previously-visited APs
2336ba597c5SAnurag S. Maskey * at when we are in the connected state.
2346ba597c5SAnurag S. Maskey */
2356ba597c5SAnurag S. Maskey dladm_wlan_strength_t wireless_scan_level = DLADM_WLAN_STRENGTH_WEAK;
2366ba597c5SAnurag S. Maskey
2376ba597c5SAnurag S. Maskey /*
2386ba597c5SAnurag S. Maskey * The variable wireless_scan_interval specifies how often the periodic
2396ba597c5SAnurag S. Maskey * scan occurs.
2406ba597c5SAnurag S. Maskey */
2416ba597c5SAnurag S. Maskey uint64_t wireless_scan_interval = WIRELESS_SCAN_INTERVAL_DEFAULT;
2426ba597c5SAnurag S. Maskey
2436ba597c5SAnurag S. Maskey /*
2446ba597c5SAnurag S. Maskey * The variable wireless_autoconf specifies if we use dladm_wlan_autoconf()
2456ba597c5SAnurag S. Maskey * to connect.
2466ba597c5SAnurag S. Maskey */
2476ba597c5SAnurag S. Maskey boolean_t wireless_autoconf = B_FALSE;
2486ba597c5SAnurag S. Maskey
2496ba597c5SAnurag S. Maskey /*
2506ba597c5SAnurag S. Maskey * The variable wireless_strict_bssid specifies if we only connect
2516ba597c5SAnurag S. Maskey * to WLANs with BSSIDs that we previously connected to.
2526ba597c5SAnurag S. Maskey */
2536ba597c5SAnurag S. Maskey boolean_t wireless_strict_bssid = B_FALSE;
2546ba597c5SAnurag S. Maskey
2556ba597c5SAnurag S. Maskey /*
2566ba597c5SAnurag S. Maskey * We need to ensure scan or connect threads do not run concurrently
2576ba597c5SAnurag S. Maskey * on any links - otherwise we get radio interference. Acquire this
2586ba597c5SAnurag S. Maskey * lock on entering scan/connect threads to prevent this.
2596ba597c5SAnurag S. Maskey */
2606ba597c5SAnurag S. Maskey pthread_mutex_t wireless_mutex = PTHREAD_MUTEX_INITIALIZER;
2616ba597c5SAnurag S. Maskey
2626ba597c5SAnurag S. Maskey static void
scanconnect_entry(void)2636ba597c5SAnurag S. Maskey scanconnect_entry(void)
2646ba597c5SAnurag S. Maskey {
2656ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&wireless_mutex);
2666ba597c5SAnurag S. Maskey }
2676ba597c5SAnurag S. Maskey
2686ba597c5SAnurag S. Maskey static void
scanconnect_exit(void)2696ba597c5SAnurag S. Maskey scanconnect_exit(void)
2706ba597c5SAnurag S. Maskey {
2716ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&wireless_mutex);
2726ba597c5SAnurag S. Maskey }
2736ba597c5SAnurag S. Maskey
2746ba597c5SAnurag S. Maskey /*
2756ba597c5SAnurag S. Maskey * Below are functions used to handle storage/retrieval of keys
2766ba597c5SAnurag S. Maskey * for a given WLAN. The keys are stored/retrieved using dladm_set_secobj()
2776ba597c5SAnurag S. Maskey * and dladm_get_secobj().
2786ba597c5SAnurag S. Maskey */
2796ba597c5SAnurag S. Maskey
2806ba597c5SAnurag S. Maskey /*
2816ba597c5SAnurag S. Maskey * Convert key hexascii string to raw secobj value. This
2826ba597c5SAnurag S. Maskey * code is very similar to convert_secobj() in dladm.c, it would
2836ba597c5SAnurag S. Maskey * be good to have a libdladm function to convert values.
2846ba597c5SAnurag S. Maskey */
2856ba597c5SAnurag S. Maskey static int
key_string_to_secobj_value(char * buf,uint8_t * obj_val,uint_t * obj_lenp,dladm_secobj_class_t class)2866ba597c5SAnurag S. Maskey key_string_to_secobj_value(char *buf, uint8_t *obj_val, uint_t *obj_lenp,
2876ba597c5SAnurag S. Maskey dladm_secobj_class_t class)
2886ba597c5SAnurag S. Maskey {
2896ba597c5SAnurag S. Maskey size_t buf_len = strlen(buf);
2906ba597c5SAnurag S. Maskey
2916ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "before: key_string_to_secobj_value: buf_len = %d",
2926ba597c5SAnurag S. Maskey buf_len);
2936ba597c5SAnurag S. Maskey if (buf_len == 0) {
2946ba597c5SAnurag S. Maskey /* length zero means "delete" */
2956ba597c5SAnurag S. Maskey return (0);
2966ba597c5SAnurag S. Maskey }
2976ba597c5SAnurag S. Maskey
2986ba597c5SAnurag S. Maskey if (buf[buf_len - 1] == '\n')
2996ba597c5SAnurag S. Maskey buf[--buf_len] = '\0';
3006ba597c5SAnurag S. Maskey
3016ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "after: key_string_to_secobj_value: buf_len = %d",
3026ba597c5SAnurag S. Maskey buf_len);
3036ba597c5SAnurag S. Maskey
3046ba597c5SAnurag S. Maskey if (class == DLADM_SECOBJ_CLASS_WPA) {
3056ba597c5SAnurag S. Maskey /*
3066ba597c5SAnurag S. Maskey * Per IEEE802.11i spec, the Pre-shared key (PSK) length should
3076ba597c5SAnurag S. Maskey * be between 8 and 63.
3086ba597c5SAnurag S. Maskey */
3096ba597c5SAnurag S. Maskey if (buf_len < 8 || buf_len > 63) {
3106ba597c5SAnurag S. Maskey nlog(LOG_ERR,
3116ba597c5SAnurag S. Maskey "key_string_to_secobj_value:"
3126ba597c5SAnurag S. Maskey " invalid WPA key length: buf_len = %d", buf_len);
3136ba597c5SAnurag S. Maskey return (-1);
3146ba597c5SAnurag S. Maskey }
3156ba597c5SAnurag S. Maskey (void) memcpy(obj_val, buf, (uint_t)buf_len);
3166ba597c5SAnurag S. Maskey *obj_lenp = buf_len;
3176ba597c5SAnurag S. Maskey return (0);
3186ba597c5SAnurag S. Maskey }
3196ba597c5SAnurag S. Maskey
3206ba597c5SAnurag S. Maskey switch (buf_len) {
3216ba597c5SAnurag S. Maskey case 5: /* ASCII key sizes */
3226ba597c5SAnurag S. Maskey case 13:
3236ba597c5SAnurag S. Maskey (void) memcpy(obj_val, buf, (uint_t)buf_len);
3246ba597c5SAnurag S. Maskey *obj_lenp = (uint_t)buf_len;
3256ba597c5SAnurag S. Maskey break;
3266ba597c5SAnurag S. Maskey case 10:
3276ba597c5SAnurag S. Maskey case 26: /* Hex key sizes, not preceded by 0x */
3286ba597c5SAnurag S. Maskey if (hexascii_to_octet(buf, (uint_t)buf_len, obj_val, obj_lenp)
3296ba597c5SAnurag S. Maskey != 0) {
3306ba597c5SAnurag S. Maskey nlog(LOG_ERR,
3316ba597c5SAnurag S. Maskey "key_string_to_secobj_value: invalid WEP key");
3326ba597c5SAnurag S. Maskey return (-1);
3336ba597c5SAnurag S. Maskey }
3346ba597c5SAnurag S. Maskey break;
3356ba597c5SAnurag S. Maskey case 12:
3366ba597c5SAnurag S. Maskey case 28: /* Hex key sizes, preceded by 0x */
3376ba597c5SAnurag S. Maskey if (strncmp(buf, "0x", 2) != 0 ||
3386ba597c5SAnurag S. Maskey hexascii_to_octet(buf + 2, (uint_t)buf_len - 2, obj_val,
3396ba597c5SAnurag S. Maskey obj_lenp) != 0) {
3406ba597c5SAnurag S. Maskey nlog(LOG_ERR,
3416ba597c5SAnurag S. Maskey "key_string_to_secobj_value: invalid WEP key");
3426ba597c5SAnurag S. Maskey return (-1);
3436ba597c5SAnurag S. Maskey }
3446ba597c5SAnurag S. Maskey break;
3456ba597c5SAnurag S. Maskey default:
3466ba597c5SAnurag S. Maskey syslog(LOG_ERR,
3476ba597c5SAnurag S. Maskey "key_string_to_secobj_value: invalid WEP key length");
3486ba597c5SAnurag S. Maskey return (-1);
3496ba597c5SAnurag S. Maskey }
3506ba597c5SAnurag S. Maskey return (0);
3516ba597c5SAnurag S. Maskey }
3526ba597c5SAnurag S. Maskey
3536ba597c5SAnurag S. Maskey /*
354*c1976b83Senricop * Callback used on each known WLAN:
355*c1976b83Senricop * return 1 if a secobj, linked with an existing kwown wlan, has the same name
356*c1976b83Senricop * of the secobj that is being created.
357*c1976b83Senricop */
358*c1976b83Senricop
359*c1976b83Senricop static int
find_keyname_cb(nwam_known_wlan_handle_t kwh,void * new_keyname)360*c1976b83Senricop find_keyname_cb(nwam_known_wlan_handle_t kwh, void *new_keyname)
361*c1976b83Senricop {
362*c1976b83Senricop nwam_error_t err;
363*c1976b83Senricop nwam_value_t old_key;
364*c1976b83Senricop
365*c1976b83Senricop char **old_keyname;
366*c1976b83Senricop uint_t num_old_keyname, i;
367*c1976b83Senricop
368*c1976b83Senricop if ((err = nwam_known_wlan_get_prop_value(kwh,
369*c1976b83Senricop NWAM_KNOWN_WLAN_PROP_KEYNAME, &old_key)) != NWAM_SUCCESS) {
370*c1976b83Senricop nlog(LOG_ERR, "find_keyname_cb: nwam_known_wlan_get_prop: %s",
371*c1976b83Senricop nwam_strerror(err));
372*c1976b83Senricop return (0);
373*c1976b83Senricop }
374*c1976b83Senricop if ((err = nwam_value_get_string_array(old_key, &old_keyname,
375*c1976b83Senricop &num_old_keyname))
376*c1976b83Senricop != NWAM_SUCCESS) {
377*c1976b83Senricop nlog(LOG_ERR, "find_keyname_cb: nwam_value_get_string: %s",
378*c1976b83Senricop nwam_strerror(err));
379*c1976b83Senricop nwam_value_free(old_key);
380*c1976b83Senricop return (0);
381*c1976b83Senricop }
382*c1976b83Senricop nwam_value_free(old_key);
383*c1976b83Senricop for (i = 0; i < num_old_keyname; i++) {
384*c1976b83Senricop if (strcmp(old_keyname[i], (const char *)new_keyname) == 0)
385*c1976b83Senricop /* Found matching keyname so terminate walk */
386*c1976b83Senricop return (1);
387*c1976b83Senricop }
388*c1976b83Senricop return (0);
389*c1976b83Senricop }
390*c1976b83Senricop
391*c1976b83Senricop /*
3926ba597c5SAnurag S. Maskey * Print the key name format into the appropriate field, then convert any ":"
3936ba597c5SAnurag S. Maskey * characters to ".", as ":[1-4]" is the slot indicator, which otherwise
3946ba597c5SAnurag S. Maskey * would trip us up. Invalid characters for secobj names are ignored.
3956ba597c5SAnurag S. Maskey * The fourth parameter is expected to be of size DLADM_SECOBJ_NAME_MAX.
3966ba597c5SAnurag S. Maskey *
3976ba597c5SAnurag S. Maskey * (Note that much of the system uses DLADM_WLAN_MAX_KEYNAME_LEN, which is 64
3986ba597c5SAnurag S. Maskey * rather than 32, but that dladm_get_secobj will fail if a length greater than
3996ba597c5SAnurag S. Maskey * DLD_SECOBJ_NAME_MAX is seen, and that's 32. This is all horribly broken.)
4006ba597c5SAnurag S. Maskey */
4016ba597c5SAnurag S. Maskey void
nwamd_set_key_name(const char * essid,const char * bssid,char * name,size_t nsz)4026ba597c5SAnurag S. Maskey nwamd_set_key_name(const char *essid, const char *bssid, char *name, size_t nsz)
4036ba597c5SAnurag S. Maskey {
4046ba597c5SAnurag S. Maskey int i, j;
4056ba597c5SAnurag S. Maskey char secobj_name[DLADM_WLAN_MAX_KEYNAME_LEN];
4066ba597c5SAnurag S. Maskey
4076ba597c5SAnurag S. Maskey /* create a concatenated string with essid and bssid */
4086ba597c5SAnurag S. Maskey if (bssid == NULL || bssid[0] == '\0') {
4096ba597c5SAnurag S. Maskey (void) snprintf(secobj_name, sizeof (secobj_name), "nwam-%s",
4106ba597c5SAnurag S. Maskey essid);
4116ba597c5SAnurag S. Maskey } else {
4126ba597c5SAnurag S. Maskey (void) snprintf(secobj_name, sizeof (secobj_name), "nwam-%s-%s",
4136ba597c5SAnurag S. Maskey essid, bssid);
4146ba597c5SAnurag S. Maskey }
4156ba597c5SAnurag S. Maskey
4166ba597c5SAnurag S. Maskey /* copy only valid chars to the return string, terminating with \0 */
4176ba597c5SAnurag S. Maskey i = 0; /* index into secobj_name */
4186ba597c5SAnurag S. Maskey j = 0; /* index into name */
4196ba597c5SAnurag S. Maskey while (secobj_name[i] != '\0') {
4206ba597c5SAnurag S. Maskey if (j == nsz - 1)
4216ba597c5SAnurag S. Maskey break;
4226ba597c5SAnurag S. Maskey
4236ba597c5SAnurag S. Maskey if (secobj_name[i] == ':') {
4246ba597c5SAnurag S. Maskey name[j] = '.';
4256ba597c5SAnurag S. Maskey j++;
4266ba597c5SAnurag S. Maskey } else if (isalnum(secobj_name[i]) ||
4276ba597c5SAnurag S. Maskey secobj_name[i] == '.' || secobj_name[i] == '-' ||
4286ba597c5SAnurag S. Maskey secobj_name[i] == '_') {
4296ba597c5SAnurag S. Maskey name[j] = secobj_name[i];
4306ba597c5SAnurag S. Maskey j++;
4316ba597c5SAnurag S. Maskey }
4326ba597c5SAnurag S. Maskey i++;
4336ba597c5SAnurag S. Maskey }
4346ba597c5SAnurag S. Maskey name[j] = '\0';
4356ba597c5SAnurag S. Maskey }
4366ba597c5SAnurag S. Maskey
4376ba597c5SAnurag S. Maskey nwam_error_t
nwamd_wlan_set_key(const char * linkname,const char * essid,const char * bssid,uint32_t security_mode,uint_t keyslot,char * raw_key)4386ba597c5SAnurag S. Maskey nwamd_wlan_set_key(const char *linkname, const char *essid, const char *bssid,
4396ba597c5SAnurag S. Maskey uint32_t security_mode, uint_t keyslot, char *raw_key)
4406ba597c5SAnurag S. Maskey {
4416ba597c5SAnurag S. Maskey nwamd_object_t ncu_obj;
4426ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu;
4436ba597c5SAnurag S. Maskey nwamd_link_t *link;
444*c1976b83Senricop int ret = 0;
4456ba597c5SAnurag S. Maskey uint8_t obj_val[DLADM_SECOBJ_VAL_MAX];
4466ba597c5SAnurag S. Maskey uint_t obj_len = sizeof (obj_val);
4476ba597c5SAnurag S. Maskey char obj_name[DLADM_SECOBJ_NAME_MAX];
448*c1976b83Senricop char obj_tempname[DLADM_SECOBJ_NAME_MAX];
4496ba597c5SAnurag S. Maskey dladm_status_t status;
4506ba597c5SAnurag S. Maskey char errmsg[DLADM_STRSIZE];
4516ba597c5SAnurag S. Maskey dladm_secobj_class_t class;
4526ba597c5SAnurag S. Maskey
4536ba597c5SAnurag S. Maskey if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
4546ba597c5SAnurag S. Maskey == NULL) {
4556ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_set_key: could not find object "
4566ba597c5SAnurag S. Maskey "for link %s", linkname);
4576ba597c5SAnurag S. Maskey return (NWAM_ENTITY_NOT_FOUND);
4586ba597c5SAnurag S. Maskey }
4596ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
460f6da83d4SAnurag S. Maskey link = &ncu->ncu_link;
4616ba597c5SAnurag S. Maskey
4626ba597c5SAnurag S. Maskey class = (security_mode == DLADM_WLAN_SECMODE_WEP ?
4636ba597c5SAnurag S. Maskey DLADM_SECOBJ_CLASS_WEP : DLADM_SECOBJ_CLASS_WPA);
4646ba597c5SAnurag S. Maskey if (key_string_to_secobj_value(raw_key, obj_val, &obj_len,
4656ba597c5SAnurag S. Maskey class) != 0) {
4666ba597c5SAnurag S. Maskey /* above function logs internally on failure */
4676ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
4686ba597c5SAnurag S. Maskey return (NWAM_ERROR_INTERNAL);
4696ba597c5SAnurag S. Maskey }
4706ba597c5SAnurag S. Maskey
471*c1976b83Senricop nlog(LOG_DEBUG, "nwamd_wlan_set_key: running for link %s", linkname);
472*c1976b83Senricop /*
473*c1976b83Senricop * Name key object for this WLAN so it can be later retrieved.
474*c1976b83Senricop * (bssid is appended if an object, with the same keyname,
475*c1976b83Senricop * already exists and is associated to a known wlan)
476*c1976b83Senricop */
477*c1976b83Senricop nwamd_set_key_name(essid, NULL, obj_tempname, sizeof (obj_tempname));
478*c1976b83Senricop (void) nwam_walk_known_wlans(find_keyname_cb, obj_tempname, 0, &ret);
479*c1976b83Senricop /*
480*c1976b83Senricop * We also check if the keyval is the same. The user might want
481*c1976b83Senricop * to use the same key for more APs with the same ESSID.
482*c1976b83Senricop * This can result in a known wlan with multiple BSSIDs
483*c1976b83Senricop */
484*c1976b83Senricop if (ret == 1) {
485*c1976b83Senricop dladm_wlan_key_t *old_secobj = nwamd_wlan_get_key_named(
486*c1976b83Senricop obj_tempname, security_mode);
487*c1976b83Senricop nlog(LOG_DEBUG, "found existing obj_name %s", obj_tempname);
488*c1976b83Senricop ret = memcmp((*old_secobj).wk_val, obj_val, obj_len);
489*c1976b83Senricop nwamd_set_key_name(essid, ret ? bssid : NULL, obj_name,
490*c1976b83Senricop sizeof (obj_name));
491*c1976b83Senricop free(old_secobj);
492*c1976b83Senricop } else {
493*c1976b83Senricop nwamd_set_key_name(essid, NULL, obj_name,
494*c1976b83Senricop sizeof (obj_name));
495*c1976b83Senricop }
496*c1976b83Senricop nlog(LOG_DEBUG, "store_key: obj_name is %s", obj_name);
497*c1976b83Senricop
498*c1976b83Senricop /*
499*c1976b83Senricop * We have validated the new key, so remove the old one.
500*c1976b83Senricop * This will actually delete the keyobj only if the user had set
501*c1976b83Senricop * a wrong key and is replacing it with a new one for the same AP.
502*c1976b83Senricop */
5036ba597c5SAnurag S. Maskey status = dladm_unset_secobj(dld_handle, obj_name,
5046ba597c5SAnurag S. Maskey DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
5056ba597c5SAnurag S. Maskey if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND) {
5066ba597c5SAnurag S. Maskey nlog(LOG_ERR, "store_key: could not remove old secure object "
5076ba597c5SAnurag S. Maskey "'%s' for key: %s", obj_name,
5086ba597c5SAnurag S. Maskey dladm_status2str(status, errmsg));
5096ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
5106ba597c5SAnurag S. Maskey return (NWAM_ERROR_INTERNAL);
5116ba597c5SAnurag S. Maskey }
5126ba597c5SAnurag S. Maskey
5136ba597c5SAnurag S. Maskey /* if we're just deleting the key, then we're done */
5146ba597c5SAnurag S. Maskey if (raw_key[0] == '\0') {
5156ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
5166ba597c5SAnurag S. Maskey return (NWAM_SUCCESS);
5176ba597c5SAnurag S. Maskey }
5186ba597c5SAnurag S. Maskey
5196ba597c5SAnurag S. Maskey status = dladm_set_secobj(dld_handle, obj_name, class,
5206ba597c5SAnurag S. Maskey obj_val, obj_len,
5216ba597c5SAnurag S. Maskey DLADM_OPT_CREATE | DLADM_OPT_PERSIST | DLADM_OPT_ACTIVE);
5226ba597c5SAnurag S. Maskey if (status != DLADM_STATUS_OK) {
5236ba597c5SAnurag S. Maskey nlog(LOG_ERR, "store_key: could not create secure object "
5246ba597c5SAnurag S. Maskey "'%s' for key: %s", obj_name,
5256ba597c5SAnurag S. Maskey dladm_status2str(status, errmsg));
5266ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
5276ba597c5SAnurag S. Maskey return (NWAM_ERROR_INTERNAL);
5286ba597c5SAnurag S. Maskey }
5296ba597c5SAnurag S. Maskey link->nwamd_link_wifi_key = nwamd_wlan_get_key_named(obj_name,
5306ba597c5SAnurag S. Maskey security_mode);
5316ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_keyname, obj_name,
5326ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_keyname));
5336ba597c5SAnurag S. Maskey link->nwamd_link_wifi_security_mode = security_mode;
5346ba597c5SAnurag S. Maskey if (security_mode == DLADM_WLAN_SECMODE_WEP) {
5356ba597c5SAnurag S. Maskey link->nwamd_link_wifi_key->wk_idx =
5366ba597c5SAnurag S. Maskey (keyslot >= 1 && keyslot <= 4) ? keyslot : 1;
5376ba597c5SAnurag S. Maskey }
5386ba597c5SAnurag S. Maskey
5396ba597c5SAnurag S. Maskey /* If link NCU is offline* or online, (re)connect. */
5406ba597c5SAnurag S. Maskey switch (ncu_obj->nwamd_object_state) {
5416ba597c5SAnurag S. Maskey case NWAM_STATE_ONLINE:
5426ba597c5SAnurag S. Maskey /* if changing the key of the connected WLAN, reconnect */
5436ba597c5SAnurag S. Maskey if (strcmp(essid, link->nwamd_link_wifi_essid) == 0)
5446ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
5456ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name, NWAM_STATE_ONLINE,
5466ba597c5SAnurag S. Maskey NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
5476ba597c5SAnurag S. Maskey break;
5486ba597c5SAnurag S. Maskey case NWAM_STATE_OFFLINE_TO_ONLINE:
5496ba597c5SAnurag S. Maskey /* if we are waiting for the key, connect */
5506ba597c5SAnurag S. Maskey if (ncu_obj->nwamd_object_aux_state ==
5516ba597c5SAnurag S. Maskey NWAM_AUX_STATE_LINK_WIFI_NEED_KEY)
5526ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
5536ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
5546ba597c5SAnurag S. Maskey NWAM_STATE_OFFLINE_TO_ONLINE,
5556ba597c5SAnurag S. Maskey NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
5566ba597c5SAnurag S. Maskey break;
5576ba597c5SAnurag S. Maskey default:
5586ba597c5SAnurag S. Maskey break;
5596ba597c5SAnurag S. Maskey }
5606ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
5616ba597c5SAnurag S. Maskey
5626ba597c5SAnurag S. Maskey return (NWAM_SUCCESS);
5636ba597c5SAnurag S. Maskey }
5646ba597c5SAnurag S. Maskey
5656ba597c5SAnurag S. Maskey /*
5666ba597c5SAnurag S. Maskey * returns NULL if no key was recovered from libdladm. Passing in
5676ba597c5SAnurag S. Maskey * security mode of 0 means we don't care what key type it is.
5686ba597c5SAnurag S. Maskey */
5696ba597c5SAnurag S. Maskey dladm_wlan_key_t *
nwamd_wlan_get_key_named(const char * name,uint32_t security_mode)5706ba597c5SAnurag S. Maskey nwamd_wlan_get_key_named(const char *name, uint32_t security_mode)
5716ba597c5SAnurag S. Maskey {
5726ba597c5SAnurag S. Maskey dladm_status_t status;
5736ba597c5SAnurag S. Maskey char errmsg[DLADM_STRSIZE];
5746ba597c5SAnurag S. Maskey dladm_wlan_key_t *cooked_key;
5756ba597c5SAnurag S. Maskey dladm_secobj_class_t class;
5766ba597c5SAnurag S. Maskey
5776ba597c5SAnurag S. Maskey if (security_mode == DLADM_WLAN_SECMODE_NONE)
5786ba597c5SAnurag S. Maskey return (NULL);
5796ba597c5SAnurag S. Maskey
5806ba597c5SAnurag S. Maskey /*
5816ba597c5SAnurag S. Maskey * Newly-allocated key must be freed by caller, or by
5826ba597c5SAnurag S. Maskey * subsequent call to nwamd_wlan_get_key_named().
5836ba597c5SAnurag S. Maskey */
5846ba597c5SAnurag S. Maskey if ((cooked_key = malloc(sizeof (dladm_wlan_key_t))) == NULL) {
5856ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_get_key_named: malloc failed");
5866ba597c5SAnurag S. Maskey return (NULL);
5876ba597c5SAnurag S. Maskey }
5886ba597c5SAnurag S. Maskey
5896ba597c5SAnurag S. Maskey /*
5906ba597c5SAnurag S. Maskey * Set name appropriately to retrieve key for this WLAN. Note that we
5916ba597c5SAnurag S. Maskey * cannot use the actual wk_name buffer size, as it's two times too
5926ba597c5SAnurag S. Maskey * large for dladm_get_secobj.
5936ba597c5SAnurag S. Maskey */
5946ba597c5SAnurag S. Maskey (void) strlcpy(cooked_key->wk_name, name, DLADM_SECOBJ_NAME_MAX);
5956ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: len = %d, object = %s\n",
5966ba597c5SAnurag S. Maskey strlen(cooked_key->wk_name), cooked_key->wk_name);
5976ba597c5SAnurag S. Maskey cooked_key->wk_len = sizeof (cooked_key->wk_val);
5986ba597c5SAnurag S. Maskey cooked_key->wk_idx = 1;
5996ba597c5SAnurag S. Maskey
6006ba597c5SAnurag S. Maskey /* Try the kernel first, then fall back to persistent storage. */
6016ba597c5SAnurag S. Maskey status = dladm_get_secobj(dld_handle, cooked_key->wk_name, &class,
6026ba597c5SAnurag S. Maskey cooked_key->wk_val, &cooked_key->wk_len,
6036ba597c5SAnurag S. Maskey DLADM_OPT_ACTIVE);
6046ba597c5SAnurag S. Maskey if (status != DLADM_STATUS_OK) {
6056ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: "
6066ba597c5SAnurag S. Maskey "dladm_get_secobj(TEMP) failed: %s",
6076ba597c5SAnurag S. Maskey dladm_status2str(status, errmsg));
6086ba597c5SAnurag S. Maskey status = dladm_get_secobj(dld_handle, cooked_key->wk_name,
6096ba597c5SAnurag S. Maskey &class, cooked_key->wk_val, &cooked_key->wk_len,
6106ba597c5SAnurag S. Maskey DLADM_OPT_PERSIST);
6116ba597c5SAnurag S. Maskey }
6126ba597c5SAnurag S. Maskey
6136ba597c5SAnurag S. Maskey switch (status) {
6146ba597c5SAnurag S. Maskey case DLADM_STATUS_OK:
6156ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: "
6166ba597c5SAnurag S. Maskey "dladm_get_secobj succeeded: len %d", cooked_key->wk_len);
6176ba597c5SAnurag S. Maskey break;
6186ba597c5SAnurag S. Maskey case DLADM_STATUS_NOTFOUND:
6196ba597c5SAnurag S. Maskey /*
6206ba597c5SAnurag S. Maskey * We do not want an error in the case that the secobj
6216ba597c5SAnurag S. Maskey * is not found, since we then prompt for it.
6226ba597c5SAnurag S. Maskey */
6236ba597c5SAnurag S. Maskey free(cooked_key);
6246ba597c5SAnurag S. Maskey return (NULL);
6256ba597c5SAnurag S. Maskey default:
6266ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_get_key_named: could not get key "
6276ba597c5SAnurag S. Maskey "from secure object '%s': %s", cooked_key->wk_name,
6286ba597c5SAnurag S. Maskey dladm_status2str(status, errmsg));
6296ba597c5SAnurag S. Maskey free(cooked_key);
6306ba597c5SAnurag S. Maskey return (NULL);
6316ba597c5SAnurag S. Maskey }
6326ba597c5SAnurag S. Maskey
6336ba597c5SAnurag S. Maskey if (security_mode != 0) {
6346ba597c5SAnurag S. Maskey switch (class) {
6356ba597c5SAnurag S. Maskey case DLADM_SECOBJ_CLASS_WEP:
6366ba597c5SAnurag S. Maskey if (security_mode == DLADM_WLAN_SECMODE_WEP)
6376ba597c5SAnurag S. Maskey return (cooked_key);
6386ba597c5SAnurag S. Maskey break;
6396ba597c5SAnurag S. Maskey case DLADM_SECOBJ_CLASS_WPA:
6406ba597c5SAnurag S. Maskey if (security_mode == DLADM_WLAN_SECMODE_WPA)
6416ba597c5SAnurag S. Maskey return (cooked_key);
6426ba597c5SAnurag S. Maskey break;
6436ba597c5SAnurag S. Maskey default:
6446ba597c5SAnurag S. Maskey /* shouldn't happen */
6456ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_get_key: invalid class %d",
6466ba597c5SAnurag S. Maskey class);
6476ba597c5SAnurag S. Maskey break;
6486ba597c5SAnurag S. Maskey }
6496ba597c5SAnurag S. Maskey /* key type mismatch */
6506ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_get_key: key type mismatch"
6516ba597c5SAnurag S. Maskey " from secure object '%s'", cooked_key->wk_name);
6526ba597c5SAnurag S. Maskey free(cooked_key);
6536ba597c5SAnurag S. Maskey return (NULL);
6546ba597c5SAnurag S. Maskey }
6556ba597c5SAnurag S. Maskey
6566ba597c5SAnurag S. Maskey return (cooked_key);
6576ba597c5SAnurag S. Maskey }
6586ba597c5SAnurag S. Maskey
6596ba597c5SAnurag S. Maskey static dladm_wlan_key_t *
nwamd_wlan_get_key(const char * essid,const char * bssid,uint32_t security_mode)6606ba597c5SAnurag S. Maskey nwamd_wlan_get_key(const char *essid, const char *bssid, uint32_t security_mode)
6616ba597c5SAnurag S. Maskey {
6626ba597c5SAnurag S. Maskey char keyname[DLADM_SECOBJ_NAME_MAX];
6636ba597c5SAnurag S. Maskey
6646ba597c5SAnurag S. Maskey nwamd_set_key_name(essid, bssid, keyname, DLADM_SECOBJ_NAME_MAX);
6656ba597c5SAnurag S. Maskey
6666ba597c5SAnurag S. Maskey return (nwamd_wlan_get_key_named(keyname, security_mode));
6676ba597c5SAnurag S. Maskey }
6686ba597c5SAnurag S. Maskey
6696ba597c5SAnurag S. Maskey /*
6706ba597c5SAnurag S. Maskey * Checks if a wireless network can be selected or not. A wireless network
6716ba597c5SAnurag S. Maskey * CANNOT be selected if the NCU is DISABLED, or the NCU is OFFLINE or
6726ba597c5SAnurag S. Maskey * ONLINE* and has lower priority than the currently active priority-group.
6736ba597c5SAnurag S. Maskey * Called with object lock held.
6746ba597c5SAnurag S. Maskey */
6756ba597c5SAnurag S. Maskey static boolean_t
wireless_selection_possible(nwamd_object_t object)6766ba597c5SAnurag S. Maskey wireless_selection_possible(nwamd_object_t object)
6776ba597c5SAnurag S. Maskey {
6786ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu = object->nwamd_object_data;
6796ba597c5SAnurag S. Maskey
680f6da83d4SAnurag S. Maskey if (ncu->ncu_link.nwamd_link_media != DL_WIFI)
6816ba597c5SAnurag S. Maskey return (B_FALSE);
6826ba597c5SAnurag S. Maskey
6836ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&active_ncp_mutex);
6846ba597c5SAnurag S. Maskey if (object->nwamd_object_state == NWAM_STATE_DISABLED ||
6856ba597c5SAnurag S. Maskey ((object->nwamd_object_state == NWAM_STATE_OFFLINE ||
6866ba597c5SAnurag S. Maskey object->nwamd_object_state == NWAM_STATE_ONLINE_TO_OFFLINE) &&
687f6da83d4SAnurag S. Maskey ncu->ncu_link.nwamd_link_activation_mode ==
6886ba597c5SAnurag S. Maskey NWAM_ACTIVATION_MODE_PRIORITIZED &&
6896ba597c5SAnurag S. Maskey (current_ncu_priority_group == INVALID_PRIORITY_GROUP ||
690f6da83d4SAnurag S. Maskey ncu->ncu_link.nwamd_link_priority_group >
6916ba597c5SAnurag S. Maskey current_ncu_priority_group))) {
6926ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
6936ba597c5SAnurag S. Maskey return (B_FALSE);
6946ba597c5SAnurag S. Maskey }
6956ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
6966ba597c5SAnurag S. Maskey
6976ba597c5SAnurag S. Maskey return (B_TRUE);
6986ba597c5SAnurag S. Maskey }
6996ba597c5SAnurag S. Maskey
7006ba597c5SAnurag S. Maskey /*
7016ba597c5SAnurag S. Maskey * Update the selected and/or connected values for the
7026ba597c5SAnurag S. Maskey * scan data. If these change, we need to trigger a scan
7036ba597c5SAnurag S. Maskey * event since the updated values need to be communicated
7046ba597c5SAnurag S. Maskey * to the GUI.
7056ba597c5SAnurag S. Maskey */
7066ba597c5SAnurag S. Maskey void
nwamd_set_selected_connected(nwamd_ncu_t * ncu,boolean_t selected,boolean_t connected)7076ba597c5SAnurag S. Maskey nwamd_set_selected_connected(nwamd_ncu_t *ncu, boolean_t selected,
7086ba597c5SAnurag S. Maskey boolean_t connected)
7096ba597c5SAnurag S. Maskey {
710f6da83d4SAnurag S. Maskey nwamd_link_t *link = &ncu->ncu_link;
7116ba597c5SAnurag S. Maskey nwamd_wifi_scan_t *s = &link->nwamd_link_wifi_scan;
7126ba597c5SAnurag S. Maskey int i;
7136ba597c5SAnurag S. Maskey boolean_t trigger_scan_event = B_FALSE;
7146ba597c5SAnurag S. Maskey
7156ba597c5SAnurag S. Maskey for (i = 0; i < s->nwamd_wifi_scan_curr_num; i++) {
7166ba597c5SAnurag S. Maskey if (strcmp(s->nwamd_wifi_scan_curr[i].nww_essid,
7176ba597c5SAnurag S. Maskey link->nwamd_link_wifi_essid) != 0 ||
7186ba597c5SAnurag S. Maskey (link->nwamd_link_wifi_bssid[0] != '\0' &&
7196ba597c5SAnurag S. Maskey strcmp(s->nwamd_wifi_scan_curr[i].nww_bssid,
7206ba597c5SAnurag S. Maskey link->nwamd_link_wifi_bssid) != 0))
7216ba597c5SAnurag S. Maskey continue;
7226ba597c5SAnurag S. Maskey if (selected) {
7236ba597c5SAnurag S. Maskey if (!s->nwamd_wifi_scan_curr[i].nww_selected)
7246ba597c5SAnurag S. Maskey trigger_scan_event = B_TRUE;
7256ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[i].nww_selected = B_TRUE;
7266ba597c5SAnurag S. Maskey } else {
7276ba597c5SAnurag S. Maskey if (s->nwamd_wifi_scan_curr[i].nww_selected)
7286ba597c5SAnurag S. Maskey trigger_scan_event = B_TRUE;
7296ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[i].nww_selected = B_FALSE;
7306ba597c5SAnurag S. Maskey }
7316ba597c5SAnurag S. Maskey if (connected) {
7326ba597c5SAnurag S. Maskey if (!s->nwamd_wifi_scan_curr[i].nww_connected)
7336ba597c5SAnurag S. Maskey trigger_scan_event = B_TRUE;
7346ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[i].nww_connected = B_TRUE;
7356ba597c5SAnurag S. Maskey } else {
7366ba597c5SAnurag S. Maskey if (s->nwamd_wifi_scan_curr[i].nww_connected)
7376ba597c5SAnurag S. Maskey trigger_scan_event = B_TRUE;
7386ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[i].nww_connected = B_FALSE;
7396ba597c5SAnurag S. Maskey }
7406ba597c5SAnurag S. Maskey }
7416ba597c5SAnurag S. Maskey
7426ba597c5SAnurag S. Maskey if (trigger_scan_event || s->nwamd_wifi_scan_changed) {
7436ba597c5SAnurag S. Maskey nwamd_event_t scan_event = nwamd_event_init_wlan
7446ba597c5SAnurag S. Maskey (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_SCAN_REPORT, connected,
7456ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr, s->nwamd_wifi_scan_curr_num);
7466ba597c5SAnurag S. Maskey if (scan_event != NULL) {
7476ba597c5SAnurag S. Maskey /* Avoid sending same scan data multiple times */
7486ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_changed = B_FALSE;
7496ba597c5SAnurag S. Maskey nwamd_event_enqueue(scan_event);
7506ba597c5SAnurag S. Maskey }
7516ba597c5SAnurag S. Maskey }
7526ba597c5SAnurag S. Maskey }
7536ba597c5SAnurag S. Maskey
75419cbc0aaSAnurag S. Maskey /*
75519cbc0aaSAnurag S. Maskey * Callback used on each known WLAN - if the BSSID is matched, set
75619cbc0aaSAnurag S. Maskey * the ESSID of the hidden WLAN to the known WLAN name.
75719cbc0aaSAnurag S. Maskey */
75819cbc0aaSAnurag S. Maskey static int
find_bssid_cb(nwam_known_wlan_handle_t kwh,void * data)75919cbc0aaSAnurag S. Maskey find_bssid_cb(nwam_known_wlan_handle_t kwh, void *data)
76019cbc0aaSAnurag S. Maskey {
76119cbc0aaSAnurag S. Maskey nwamd_link_t *link = data;
76219cbc0aaSAnurag S. Maskey nwam_error_t err;
76319cbc0aaSAnurag S. Maskey nwam_value_t bssidval;
76419cbc0aaSAnurag S. Maskey char **bssids, *name;
76519cbc0aaSAnurag S. Maskey uint_t num_bssids, i;
76619cbc0aaSAnurag S. Maskey
76719cbc0aaSAnurag S. Maskey if ((err = nwam_known_wlan_get_prop_value(kwh,
76819cbc0aaSAnurag S. Maskey NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidval)) != NWAM_SUCCESS) {
76919cbc0aaSAnurag S. Maskey nlog(LOG_ERR, "find_bssid_cb: nwam_known_wlan_get_prop: %s",
77019cbc0aaSAnurag S. Maskey nwam_strerror(err));
77119cbc0aaSAnurag S. Maskey return (0);
77219cbc0aaSAnurag S. Maskey }
77319cbc0aaSAnurag S. Maskey if ((err = nwam_value_get_string_array(bssidval, &bssids, &num_bssids))
77419cbc0aaSAnurag S. Maskey != NWAM_SUCCESS) {
77519cbc0aaSAnurag S. Maskey nlog(LOG_ERR, "find_bssid_cb: nwam_value_get_string_array: %s",
77619cbc0aaSAnurag S. Maskey nwam_strerror(err));
77719cbc0aaSAnurag S. Maskey nwam_value_free(bssidval);
77819cbc0aaSAnurag S. Maskey return (0);
77919cbc0aaSAnurag S. Maskey }
78019cbc0aaSAnurag S. Maskey for (i = 0; i < num_bssids; i++) {
78119cbc0aaSAnurag S. Maskey if (strcmp(bssids[i], link->nwamd_link_wifi_bssid) == 0) {
78219cbc0aaSAnurag S. Maskey if ((err = nwam_known_wlan_get_name(kwh, &name))
78319cbc0aaSAnurag S. Maskey != NWAM_SUCCESS) {
78419cbc0aaSAnurag S. Maskey nlog(LOG_ERR, "find_bssid_cb: "
78519cbc0aaSAnurag S. Maskey "nwam_known_wlan_get_name: %s",
78619cbc0aaSAnurag S. Maskey nwam_strerror(err));
78719cbc0aaSAnurag S. Maskey continue;
78819cbc0aaSAnurag S. Maskey }
78919cbc0aaSAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_essid, name,
79019cbc0aaSAnurag S. Maskey sizeof (link->nwamd_link_wifi_essid));
79119cbc0aaSAnurag S. Maskey free(name);
79219cbc0aaSAnurag S. Maskey nwam_value_free(bssidval);
79319cbc0aaSAnurag S. Maskey /* Found ESSID for BSSID so terminate walk */
79419cbc0aaSAnurag S. Maskey return (1);
79519cbc0aaSAnurag S. Maskey }
79619cbc0aaSAnurag S. Maskey }
79719cbc0aaSAnurag S. Maskey nwam_value_free(bssidval);
79819cbc0aaSAnurag S. Maskey
79919cbc0aaSAnurag S. Maskey return (0);
80019cbc0aaSAnurag S. Maskey }
80119cbc0aaSAnurag S. Maskey
80219cbc0aaSAnurag S. Maskey /*
80319cbc0aaSAnurag S. Maskey * We may have encountered a BSSID for a hidden WLAN before and as a result
80419cbc0aaSAnurag S. Maskey * may have a known WLAN entry with this BSSID. Walk known WLANs, searching
80519cbc0aaSAnurag S. Maskey * for a BSSID match. Called with object lock held.
80619cbc0aaSAnurag S. Maskey */
80719cbc0aaSAnurag S. Maskey static void
check_if_hidden_wlan_was_visited(nwamd_link_t * link)80819cbc0aaSAnurag S. Maskey check_if_hidden_wlan_was_visited(nwamd_link_t *link)
80919cbc0aaSAnurag S. Maskey {
81019cbc0aaSAnurag S. Maskey (void) nwam_walk_known_wlans(find_bssid_cb, link,
81119cbc0aaSAnurag S. Maskey NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, NULL);
81219cbc0aaSAnurag S. Maskey }
81319cbc0aaSAnurag S. Maskey
8146ba597c5SAnurag S. Maskey nwam_error_t
nwamd_wlan_select(const char * linkname,const char * essid,const char * bssid,uint32_t security_mode,boolean_t add_to_known_wlans)8156ba597c5SAnurag S. Maskey nwamd_wlan_select(const char *linkname, const char *essid, const char *bssid,
8166ba597c5SAnurag S. Maskey uint32_t security_mode, boolean_t add_to_known_wlans)
8176ba597c5SAnurag S. Maskey {
8186ba597c5SAnurag S. Maskey nwamd_object_t ncu_obj;
8196ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu;
8206ba597c5SAnurag S. Maskey nwamd_link_t *link;
821*c1976b83Senricop boolean_t found_key = B_FALSE;
8226ba597c5SAnurag S. Maskey
8236ba597c5SAnurag S. Maskey if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
8246ba597c5SAnurag S. Maskey == NULL) {
8256ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_select: could not find object "
8266ba597c5SAnurag S. Maskey "for link %s", linkname);
8276ba597c5SAnurag S. Maskey return (NWAM_ENTITY_NOT_FOUND);
8286ba597c5SAnurag S. Maskey }
8296ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
830f6da83d4SAnurag S. Maskey link = &ncu->ncu_link;
8316ba597c5SAnurag S. Maskey
8326ba597c5SAnurag S. Maskey /*
8336ba597c5SAnurag S. Maskey * If wireless selection is not possible because of the current
8346ba597c5SAnurag S. Maskey * state or priority-group, then stop.
8356ba597c5SAnurag S. Maskey */
8366ba597c5SAnurag S. Maskey if (!wireless_selection_possible(ncu_obj)) {
8376ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
8386ba597c5SAnurag S. Maskey return (NWAM_ENTITY_INVALID_STATE);
8396ba597c5SAnurag S. Maskey }
8406ba597c5SAnurag S. Maskey
8416ba597c5SAnurag S. Maskey /* unset selected, connected flag for previously connected wlan */
8426ba597c5SAnurag S. Maskey nwamd_set_selected_connected(ncu, B_FALSE, B_FALSE);
8436ba597c5SAnurag S. Maskey
84419cbc0aaSAnurag S. Maskey /* Disconnect to allow new selection to go ahead */
84519cbc0aaSAnurag S. Maskey (void) dladm_wlan_disconnect(dld_handle, link->nwamd_link_id);
84619cbc0aaSAnurag S. Maskey
8476ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_essid, essid,
8486ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_essid));
8496ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
8506ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_bssid));
8516ba597c5SAnurag S. Maskey link->nwamd_link_wifi_security_mode = security_mode;
8526ba597c5SAnurag S. Maskey link->nwamd_link_wifi_add_to_known_wlans = add_to_known_wlans;
8536ba597c5SAnurag S. Maskey
85419cbc0aaSAnurag S. Maskey /* If this is a hidden wlan, then essid is empty */
85519cbc0aaSAnurag S. Maskey if (link->nwamd_link_wifi_essid[0] == '\0')
85619cbc0aaSAnurag S. Maskey check_if_hidden_wlan_was_visited(link);
8576ba597c5SAnurag S. Maskey
8586ba597c5SAnurag S. Maskey /* set selected flag for newly-selected WLAN */
8596ba597c5SAnurag S. Maskey nwamd_set_selected_connected(ncu, B_TRUE, B_FALSE);
8606ba597c5SAnurag S. Maskey
8616ba597c5SAnurag S. Maskey /* does this WLAN require a key? If so go to NEED_KEY */
8626ba597c5SAnurag S. Maskey if (NEED_ENC(link->nwamd_link_wifi_security_mode)) {
8636ba597c5SAnurag S. Maskey /*
864*c1976b83Senricop * nwam secobjs can have two formats: nwam-ESSID-BSSID and
865*c1976b83Senricop * nwam-ESSID. There is no reason for searching through known
866*c1976b83Senricop * wlan keynames since this is only the selection process.
8676ba597c5SAnurag S. Maskey */
868*c1976b83Senricop if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
869*c1976b83Senricop (link->nwamd_link_wifi_essid, link->nwamd_link_wifi_bssid,
8706ba597c5SAnurag S. Maskey link->nwamd_link_wifi_security_mode)) != NULL) {
871*c1976b83Senricop /*
872*c1976b83Senricop * Found old key format,
873*c1976b83Senricop * known wlans with similar names might exist
874*c1976b83Senricop */
875*c1976b83Senricop nwamd_set_key_name(link->nwamd_link_wifi_essid,
876*c1976b83Senricop link->nwamd_link_wifi_bssid,
877*c1976b83Senricop link->nwamd_link_wifi_keyname,
878*c1976b83Senricop DLADM_SECOBJ_NAME_MAX);
879*c1976b83Senricop nlog(LOG_DEBUG, "nwamd_wlan_select: got old format "
880*c1976b83Senricop "WLAN key %s",
881*c1976b83Senricop link->nwamd_link_wifi_keyname);
8826ba597c5SAnurag S. Maskey found_key = B_TRUE;
8836ba597c5SAnurag S. Maskey } else if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
8846ba597c5SAnurag S. Maskey (link->nwamd_link_wifi_essid, NULL,
8856ba597c5SAnurag S. Maskey link->nwamd_link_wifi_security_mode)) != NULL) {
8866ba597c5SAnurag S. Maskey nwamd_set_key_name(link->nwamd_link_wifi_essid, NULL,
8876ba597c5SAnurag S. Maskey link->nwamd_link_wifi_keyname,
8886ba597c5SAnurag S. Maskey DLADM_SECOBJ_NAME_MAX);
8896ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_select: got WLAN key %s",
8906ba597c5SAnurag S. Maskey link->nwamd_link_wifi_keyname);
8916ba597c5SAnurag S. Maskey found_key = B_TRUE;
8926ba597c5SAnurag S. Maskey } else {
8936ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_select: could not "
8946ba597c5SAnurag S. Maskey "find key for WLAN '%s'",
8956ba597c5SAnurag S. Maskey link->nwamd_link_wifi_essid);
8966ba597c5SAnurag S. Maskey }
8976ba597c5SAnurag S. Maskey } else {
8986ba597c5SAnurag S. Maskey free(link->nwamd_link_wifi_key);
8996ba597c5SAnurag S. Maskey link->nwamd_link_wifi_key = NULL;
9006ba597c5SAnurag S. Maskey link->nwamd_link_wifi_keyname[0] = '\0';
9016ba597c5SAnurag S. Maskey }
9026ba597c5SAnurag S. Maskey
9036ba597c5SAnurag S. Maskey if (NEED_ENC(link->nwamd_link_wifi_security_mode) && !found_key) {
9046ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
9056ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
9066ba597c5SAnurag S. Maskey NWAM_STATE_OFFLINE_TO_ONLINE,
9076ba597c5SAnurag S. Maskey NWAM_AUX_STATE_LINK_WIFI_NEED_KEY);
9086ba597c5SAnurag S. Maskey } else {
9096ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
9106ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name, NWAM_STATE_OFFLINE_TO_ONLINE,
9116ba597c5SAnurag S. Maskey NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
9126ba597c5SAnurag S. Maskey }
9136ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
9146ba597c5SAnurag S. Maskey
9156ba597c5SAnurag S. Maskey return (NWAM_SUCCESS);
9166ba597c5SAnurag S. Maskey }
9176ba597c5SAnurag S. Maskey
9186ba597c5SAnurag S. Maskey /*
9196ba597c5SAnurag S. Maskey * See if BSSID is in visited list of BSSIDs for known WLAN. Used for
9206ba597c5SAnurag S. Maskey * strict BSSID matching (depends on wireless_strict_bssid property value).
9216ba597c5SAnurag S. Maskey */
922*c1976b83Senricop static int
bssid_match(nwam_known_wlan_handle_t kwh,void * bssid)923*c1976b83Senricop bssid_match(nwam_known_wlan_handle_t kwh, void *bssid)
9246ba597c5SAnurag S. Maskey {
9256ba597c5SAnurag S. Maskey nwam_value_t bssidsval;
9266ba597c5SAnurag S. Maskey nwam_error_t err;
9276ba597c5SAnurag S. Maskey char **bssids;
9286ba597c5SAnurag S. Maskey uint_t nelem, i;
929*c1976b83Senricop int found = 0;
9306ba597c5SAnurag S. Maskey
9316ba597c5SAnurag S. Maskey if ((err = nwam_known_wlan_get_prop_value(kwh,
9326ba597c5SAnurag S. Maskey NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidsval)) != NWAM_SUCCESS) {
9336ba597c5SAnurag S. Maskey nlog(LOG_ERR, "bssid_match: %s", nwam_strerror(err));
934*c1976b83Senricop return (0);
9356ba597c5SAnurag S. Maskey }
9366ba597c5SAnurag S. Maskey if ((err = nwam_value_get_string_array(bssidsval, &bssids, &nelem))
9376ba597c5SAnurag S. Maskey != NWAM_SUCCESS) {
9386ba597c5SAnurag S. Maskey nwam_value_free(bssidsval);
939*c1976b83Senricop return (0);
9406ba597c5SAnurag S. Maskey }
9416ba597c5SAnurag S. Maskey for (i = 0; i < nelem; i++) {
942*c1976b83Senricop if (strcmp((const char *)bssid, bssids[i]) == 0) {
943*c1976b83Senricop found = 1;
9446ba597c5SAnurag S. Maskey break;
9456ba597c5SAnurag S. Maskey }
9466ba597c5SAnurag S. Maskey }
9476ba597c5SAnurag S. Maskey nwam_value_free(bssidsval);
9486ba597c5SAnurag S. Maskey
9496ba597c5SAnurag S. Maskey return (found);
9506ba597c5SAnurag S. Maskey }
9516ba597c5SAnurag S. Maskey
9526ba597c5SAnurag S. Maskey /* Find most prioritized AP with strongest signal in scan data. */
9536ba597c5SAnurag S. Maskey static int
find_best_wlan_cb(nwam_known_wlan_handle_t kwh,void * data)9546ba597c5SAnurag S. Maskey find_best_wlan_cb(nwam_known_wlan_handle_t kwh, void *data)
9556ba597c5SAnurag S. Maskey {
9566ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu = data;
957f6da83d4SAnurag S. Maskey nwamd_link_t *link = &ncu->ncu_link;
9586ba597c5SAnurag S. Maskey nwamd_wifi_scan_t *s = &link->nwamd_link_wifi_scan;
9596ba597c5SAnurag S. Maskey nwam_error_t err;
9606ba597c5SAnurag S. Maskey char *name = NULL;
9616ba597c5SAnurag S. Maskey int i;
9626ba597c5SAnurag S. Maskey dladm_wlan_strength_t curr_strength = 0;
9636ba597c5SAnurag S. Maskey dladm_wlan_strength_t max_strength = 0;
9646ba597c5SAnurag S. Maskey boolean_t found = B_FALSE;
9656ba597c5SAnurag S. Maskey
9666ba597c5SAnurag S. Maskey if ((err = nwam_known_wlan_get_name(kwh, &name)) != NWAM_SUCCESS) {
9676ba597c5SAnurag S. Maskey nlog(LOG_ERR, "find_best_wlan_cb: could not look up name: %s",
9686ba597c5SAnurag S. Maskey nwam_strerror(err));
9696ba597c5SAnurag S. Maskey return (0);
9706ba597c5SAnurag S. Maskey }
9716ba597c5SAnurag S. Maskey
9726ba597c5SAnurag S. Maskey if (link->nwamd_link_wifi_connected) {
9736ba597c5SAnurag S. Maskey (void) dladm_wlan_str2strength
9746ba597c5SAnurag S. Maskey (link->nwamd_link_wifi_signal_strength, &curr_strength);
9756ba597c5SAnurag S. Maskey }
9766ba597c5SAnurag S. Maskey
9776ba597c5SAnurag S. Maskey /*
9786ba597c5SAnurag S. Maskey * If we're >= scan level, don't pick another Known WLAN if still
9796ba597c5SAnurag S. Maskey * connected (even if a Known WLAN with higher priority is available).
9806ba597c5SAnurag S. Maskey * If the user wants to connect to a different Known WLAN, it can be
9816ba597c5SAnurag S. Maskey * done from the GUI or select-wifi subcommand of nwamadm(1M).
9826ba597c5SAnurag S. Maskey */
9836ba597c5SAnurag S. Maskey if (curr_strength >= wireless_scan_level &&
9846ba597c5SAnurag S. Maskey link->nwamd_link_wifi_connected) {
9856ba597c5SAnurag S. Maskey free(name);
9866ba597c5SAnurag S. Maskey return (1);
9876ba597c5SAnurag S. Maskey }
9886ba597c5SAnurag S. Maskey
9896ba597c5SAnurag S. Maskey for (i = 0; i < s->nwamd_wifi_scan_curr_num; i++) {
9906ba597c5SAnurag S. Maskey nwam_wlan_t *cur_wlan = &(s->nwamd_wifi_scan_curr[i]);
991*c1976b83Senricop int b_match = bssid_match(kwh, cur_wlan->nww_bssid);
9926ba597c5SAnurag S. Maskey
9936ba597c5SAnurag S. Maskey /*
9946ba597c5SAnurag S. Maskey * We need to either match the scanned essid, or in the case
9956ba597c5SAnurag S. Maskey * where the essid was not broadcast, match the scanned bssid.
9966ba597c5SAnurag S. Maskey */
9976ba597c5SAnurag S. Maskey if (strcmp(cur_wlan->nww_essid, name) != 0 &&
9986ba597c5SAnurag S. Maskey !(cur_wlan->nww_essid[0] == '\0' && b_match))
9996ba597c5SAnurag S. Maskey continue;
10006ba597c5SAnurag S. Maskey /*
10016ba597c5SAnurag S. Maskey * If wireless_strict_bssid is specified, need to match
10026ba597c5SAnurag S. Maskey * BSSID too.
10036ba597c5SAnurag S. Maskey */
10046ba597c5SAnurag S. Maskey if (wireless_strict_bssid && !b_match)
10056ba597c5SAnurag S. Maskey continue;
10066ba597c5SAnurag S. Maskey /*
10076ba597c5SAnurag S. Maskey * Found a match. Since we walk known WLANs in
10086ba597c5SAnurag S. Maskey * priority order, it's guaranteed to be the
10096ba597c5SAnurag S. Maskey * most prioritized. It may not be the strongest though -
10106ba597c5SAnurag S. Maskey * we continue the walk and record the strength along
10116ba597c5SAnurag S. Maskey * with the ESSID and BSSID, so that if we encounter
10126ba597c5SAnurag S. Maskey * another AP with the same ESSID but a higher signal strength,
10136ba597c5SAnurag S. Maskey * we will choose it - but only if the currently-connected
10146ba597c5SAnurag S. Maskey * WLAN is at or below wireless_scan_level.
10156ba597c5SAnurag S. Maskey */
10166ba597c5SAnurag S. Maskey (void) dladm_wlan_str2strength
10176ba597c5SAnurag S. Maskey (cur_wlan->nww_signal_strength, &curr_strength);
10186ba597c5SAnurag S. Maskey
10196ba597c5SAnurag S. Maskey if (curr_strength > max_strength) {
10206ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_essid,
10216ba597c5SAnurag S. Maskey cur_wlan->nww_essid,
10226ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_essid));
102383ca9a11SAnurag S. Maskey /*
102483ca9a11SAnurag S. Maskey * Set BSSID if wireless_strict_bssid is specified or
102583ca9a11SAnurag S. Maskey * if this is a hidden WLAN. Store the BSSID here and
102683ca9a11SAnurag S. Maskey * then later determine the hidden WLAN's name in the
102783ca9a11SAnurag S. Maskey * connect thread.
102883ca9a11SAnurag S. Maskey */
102983ca9a11SAnurag S. Maskey if (wireless_strict_bssid ||
103083ca9a11SAnurag S. Maskey cur_wlan->nww_essid[0] == '\0') {
10316ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_bssid,
10326ba597c5SAnurag S. Maskey cur_wlan->nww_bssid,
10336ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_bssid));
10346ba597c5SAnurag S. Maskey }
10356ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_signal_strength,
10366ba597c5SAnurag S. Maskey cur_wlan->nww_signal_strength,
10376ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_signal_strength));
10386ba597c5SAnurag S. Maskey link->nwamd_link_wifi_security_mode =
10396ba597c5SAnurag S. Maskey cur_wlan->nww_security_mode;
10406ba597c5SAnurag S. Maskey found = B_TRUE;
10416ba597c5SAnurag S. Maskey }
10426ba597c5SAnurag S. Maskey (void) dladm_wlan_str2strength
10436ba597c5SAnurag S. Maskey (link->nwamd_link_wifi_signal_strength, &max_strength);
10446ba597c5SAnurag S. Maskey }
10456ba597c5SAnurag S. Maskey free(name);
10466ba597c5SAnurag S. Maskey return (found ? 1 : 0);
10476ba597c5SAnurag S. Maskey }
10486ba597c5SAnurag S. Maskey
10496ba597c5SAnurag S. Maskey static boolean_t
nwamd_find_known_wlan(nwamd_object_t ncu_obj)10506ba597c5SAnurag S. Maskey nwamd_find_known_wlan(nwamd_object_t ncu_obj)
10516ba597c5SAnurag S. Maskey {
10526ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu = ncu_obj->nwamd_object_data;
10536ba597c5SAnurag S. Maskey int ret;
10546ba597c5SAnurag S. Maskey
10556ba597c5SAnurag S. Maskey /*
10566ba597c5SAnurag S. Maskey * Walk known WLANs, finding lowest priority (preferred) WLAN
10576ba597c5SAnurag S. Maskey * in our scan results.
10586ba597c5SAnurag S. Maskey */
10596ba597c5SAnurag S. Maskey (void) nwam_walk_known_wlans(find_best_wlan_cb, ncu,
10606ba597c5SAnurag S. Maskey NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, &ret);
10616ba597c5SAnurag S. Maskey
10626ba597c5SAnurag S. Maskey return (ret == 1);
10636ba597c5SAnurag S. Maskey }
10646ba597c5SAnurag S. Maskey
10656ba597c5SAnurag S. Maskey /*
10666ba597c5SAnurag S. Maskey * WLAN scan code for WIFI link NCUs.
10676ba597c5SAnurag S. Maskey */
10686ba597c5SAnurag S. Maskey
10696ba597c5SAnurag S. Maskey /* Create periodic scan event for object. Called with object lock held. */
10706ba597c5SAnurag S. Maskey void
nwamd_ncu_create_periodic_scan_event(nwamd_object_t ncu_obj)10716ba597c5SAnurag S. Maskey nwamd_ncu_create_periodic_scan_event(nwamd_object_t ncu_obj)
10726ba597c5SAnurag S. Maskey {
10736ba597c5SAnurag S. Maskey nwamd_event_t scan_event;
10746ba597c5SAnurag S. Maskey
10756ba597c5SAnurag S. Maskey if (wireless_scan_interval == 0) {
10766ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_ncu_create_periodic_scan_event: "
10776ba597c5SAnurag S. Maskey "wireless_scan_interval set to 0 so no periodic scanning");
10786ba597c5SAnurag S. Maskey return;
10796ba597c5SAnurag S. Maskey }
10806ba597c5SAnurag S. Maskey scan_event = nwamd_event_init(NWAM_EVENT_TYPE_PERIODIC_SCAN,
10816ba597c5SAnurag S. Maskey NWAM_OBJECT_TYPE_NCU, 0, ncu_obj->nwamd_object_name);
10826ba597c5SAnurag S. Maskey if (scan_event != NULL) {
10836ba597c5SAnurag S. Maskey nwamd_event_enqueue_timed(scan_event,
10846ba597c5SAnurag S. Maskey wireless_scan_interval > WIRELESS_SCAN_INTERVAL_MIN ?
10856ba597c5SAnurag S. Maskey wireless_scan_interval : WIRELESS_SCAN_INTERVAL_MIN);
10866ba597c5SAnurag S. Maskey }
10876ba597c5SAnurag S. Maskey }
10886ba597c5SAnurag S. Maskey
10896ba597c5SAnurag S. Maskey /* Handle periodic scan event (which puts link into WIFI_INIT state */
10906ba597c5SAnurag S. Maskey void
nwamd_ncu_handle_periodic_scan_event(nwamd_event_t event)10916ba597c5SAnurag S. Maskey nwamd_ncu_handle_periodic_scan_event(nwamd_event_t event)
10926ba597c5SAnurag S. Maskey {
10936ba597c5SAnurag S. Maskey nwamd_object_t ncu_obj;
10946ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu;
10956ba597c5SAnurag S. Maskey
10966ba597c5SAnurag S. Maskey ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
10976ba597c5SAnurag S. Maskey event->event_object);
10986ba597c5SAnurag S. Maskey if (ncu_obj == NULL) {
10996ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_ncu_handle_periodic_scan_event: "
11006ba597c5SAnurag S. Maskey "no object %s", event->event_object);
11016ba597c5SAnurag S. Maskey return;
11026ba597c5SAnurag S. Maskey }
11036ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
11046ba597c5SAnurag S. Maskey
11056ba597c5SAnurag S. Maskey /* Only rescan if state is offline* or online */
11066ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_ncu_handle_periodic_scan_event: doing rescan..");
11076ba597c5SAnurag S. Maskey
11086ba597c5SAnurag S. Maskey if (ncu_obj->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE ||
11096ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_state == NWAM_STATE_ONLINE) {
11106ba597c5SAnurag S. Maskey /* rescan, then create periodic scan event */
11116ba597c5SAnurag S. Maskey (void) nwamd_wlan_scan(ncu->ncu_name);
11126ba597c5SAnurag S. Maskey nwamd_ncu_create_periodic_scan_event(ncu_obj);
11136ba597c5SAnurag S. Maskey }
11146ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
11156ba597c5SAnurag S. Maskey }
11166ba597c5SAnurag S. Maskey
11176ba597c5SAnurag S. Maskey static boolean_t
get_scan_results(void * arg,dladm_wlan_attr_t * attrp)11186ba597c5SAnurag S. Maskey get_scan_results(void *arg, dladm_wlan_attr_t *attrp)
11196ba597c5SAnurag S. Maskey {
11206ba597c5SAnurag S. Maskey nwamd_wifi_scan_t *s = arg;
11216ba597c5SAnurag S. Maskey const char *linkname = s->nwamd_wifi_scan_link;
11226ba597c5SAnurag S. Maskey char essid_name[DLADM_STRSIZE];
11236ba597c5SAnurag S. Maskey char bssid_name[DLADM_STRSIZE];
11246ba597c5SAnurag S. Maskey char strength[DLADM_STRSIZE];
11256ba597c5SAnurag S. Maskey uint_t i, index = 0;
11266ba597c5SAnurag S. Maskey boolean_t found = B_FALSE;
11276ba597c5SAnurag S. Maskey
11286ba597c5SAnurag S. Maskey (void) dladm_wlan_essid2str(&attrp->wa_essid, essid_name);
11296ba597c5SAnurag S. Maskey (void) dladm_wlan_bssid2str(&attrp->wa_bssid, bssid_name);
11306ba597c5SAnurag S. Maskey (void) dladm_wlan_strength2str(&attrp->wa_strength, strength);
11316ba597c5SAnurag S. Maskey
11326ba597c5SAnurag S. Maskey index = s->nwamd_wifi_scan_curr_num;
11336ba597c5SAnurag S. Maskey if (index == NWAMD_MAX_NUM_WLANS) {
11346ba597c5SAnurag S. Maskey nlog(LOG_ERR, "get_scan_results: truncating WLAN scan results "
11356ba597c5SAnurag S. Maskey "for link %s: ommiting (%s, %s)", linkname, essid_name,
11366ba597c5SAnurag S. Maskey bssid_name);
11376ba597c5SAnurag S. Maskey return (B_TRUE);
11386ba597c5SAnurag S. Maskey }
11396ba597c5SAnurag S. Maskey
11406ba597c5SAnurag S. Maskey (void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_essid, essid_name,
11416ba597c5SAnurag S. Maskey sizeof (s->nwamd_wifi_scan_curr[index].nww_essid));
11426ba597c5SAnurag S. Maskey (void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_bssid, bssid_name,
11436ba597c5SAnurag S. Maskey sizeof (s->nwamd_wifi_scan_curr[index].nww_bssid));
11446ba597c5SAnurag S. Maskey (void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_signal_strength,
11456ba597c5SAnurag S. Maskey strength,
11466ba597c5SAnurag S. Maskey sizeof (s->nwamd_wifi_scan_curr[index].nww_signal_strength));
11476ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[index].nww_security_mode = attrp->wa_secmode;
11486ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[index].nww_speed = attrp->wa_speed;
11496ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[index].nww_channel = attrp->wa_channel;
11506ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[index].nww_bsstype = attrp->wa_bsstype;
11516ba597c5SAnurag S. Maskey
11526ba597c5SAnurag S. Maskey /*
11536ba597c5SAnurag S. Maskey * We fill in actual values for selected/connected/key later when we
11546ba597c5SAnurag S. Maskey * reacquire the object lock.
11556ba597c5SAnurag S. Maskey */
11566ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[index].nww_selected = B_FALSE;
11576ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[index].nww_connected = B_FALSE;
11586ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[index].nww_have_key = B_FALSE;
11596ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr[index].nww_keyindex = 1;
11606ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_curr_num++;
11616ba597c5SAnurag S. Maskey
11626ba597c5SAnurag S. Maskey /* Check if this AP was in previous scan results */
11636ba597c5SAnurag S. Maskey for (i = 0; i < s->nwamd_wifi_scan_last_num; i++) {
11646ba597c5SAnurag S. Maskey found = (strcmp(s->nwamd_wifi_scan_last[i].nww_essid,
11656ba597c5SAnurag S. Maskey essid_name) == 0 &&
11666ba597c5SAnurag S. Maskey strcmp(s->nwamd_wifi_scan_last[i].nww_bssid,
11676ba597c5SAnurag S. Maskey bssid_name) == 0);
11686ba597c5SAnurag S. Maskey if (found)
11696ba597c5SAnurag S. Maskey break;
11706ba597c5SAnurag S. Maskey }
11716ba597c5SAnurag S. Maskey if (!found)
11726ba597c5SAnurag S. Maskey s->nwamd_wifi_scan_changed = B_TRUE;
11736ba597c5SAnurag S. Maskey
11746ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "get_scan_results(%s, %d): ESSID %s, BSSID %s",
11756ba597c5SAnurag S. Maskey linkname, index, essid_name, bssid_name);
11766ba597c5SAnurag S. Maskey
11776ba597c5SAnurag S. Maskey return (B_TRUE);
11786ba597c5SAnurag S. Maskey }
11796ba597c5SAnurag S. Maskey
11806ba597c5SAnurag S. Maskey /*
11816ba597c5SAnurag S. Maskey * Check if we're connected to the expected WLAN, or in the case of autoconf
11826ba597c5SAnurag S. Maskey * record the WLAN we're connected to.
11836ba597c5SAnurag S. Maskey */
11846ba597c5SAnurag S. Maskey boolean_t
nwamd_wlan_connected(nwamd_object_t ncu_obj)11856ba597c5SAnurag S. Maskey nwamd_wlan_connected(nwamd_object_t ncu_obj)
11866ba597c5SAnurag S. Maskey {
11876ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu = ncu_obj->nwamd_object_data;
1188f6da83d4SAnurag S. Maskey nwamd_link_t *link = &ncu->ncu_link;
11896ba597c5SAnurag S. Maskey dladm_wlan_linkattr_t attr;
11906ba597c5SAnurag S. Maskey char essid[DLADM_STRSIZE];
11916ba597c5SAnurag S. Maskey char bssid[DLADM_STRSIZE];
11926ba597c5SAnurag S. Maskey boolean_t connected = B_FALSE;
11936ba597c5SAnurag S. Maskey int retries = 0;
11946ba597c5SAnurag S. Maskey
11956ba597c5SAnurag S. Maskey /*
11966ba597c5SAnurag S. Maskey * This is awful, but some wireless drivers
11976ba597c5SAnurag S. Maskey * (particularly 'ath') will erroneously report
11986ba597c5SAnurag S. Maskey * "disconnected" if queried right after a scan. If we
11996ba597c5SAnurag S. Maskey * see 'down' reported here, we retry a few times to
12006ba597c5SAnurag S. Maskey * make sure it's really down.
12016ba597c5SAnurag S. Maskey */
12026ba597c5SAnurag S. Maskey while (retries++ < 4) {
12036ba597c5SAnurag S. Maskey if (dladm_wlan_get_linkattr(dld_handle, link->nwamd_link_id,
12046ba597c5SAnurag S. Maskey &attr) != DLADM_STATUS_OK) {
12056ba597c5SAnurag S. Maskey attr.la_status = DLADM_WLAN_LINK_DISCONNECTED;
12066ba597c5SAnurag S. Maskey } else if (attr.la_status == DLADM_WLAN_LINK_CONNECTED) {
12076ba597c5SAnurag S. Maskey break;
12086ba597c5SAnurag S. Maskey }
12096ba597c5SAnurag S. Maskey }
12106ba597c5SAnurag S. Maskey
12116ba597c5SAnurag S. Maskey if (attr.la_status == DLADM_WLAN_LINK_CONNECTED) {
12126ba597c5SAnurag S. Maskey (void) dladm_wlan_essid2str(&attr.la_wlan_attr.wa_essid, essid);
12136ba597c5SAnurag S. Maskey (void) dladm_wlan_bssid2str(&attr.la_wlan_attr.wa_bssid, bssid);
12146ba597c5SAnurag S. Maskey connected = B_TRUE;
12156ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_connected: %s connected to %s %s",
12166ba597c5SAnurag S. Maskey ncu->ncu_name, essid, bssid);
12176ba597c5SAnurag S. Maskey } else {
12186ba597c5SAnurag S. Maskey return (B_FALSE);
12196ba597c5SAnurag S. Maskey }
12206ba597c5SAnurag S. Maskey /*
12216ba597c5SAnurag S. Maskey * If we're using autoconf, we have no control over what we connect to,
12226ba597c5SAnurag S. Maskey * so rather than verifying ESSSID, simply record ESSID/BSSID.
12236ba597c5SAnurag S. Maskey */
12246ba597c5SAnurag S. Maskey if (link->nwamd_link_wifi_autoconf) {
12256ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_essid, essid,
12266ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_essid));
12276ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
12286ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_bssid));
12296ba597c5SAnurag S. Maskey }
12306ba597c5SAnurag S. Maskey /*
12316ba597c5SAnurag S. Maskey * Are we connected to expected WLAN? Note:
12326ba597c5SAnurag S. Maskey * we'd like to verify BSSID, but we cannot due to CR 6772510.
12336ba597c5SAnurag S. Maskey */
12346ba597c5SAnurag S. Maskey if (strcmp(essid, link->nwamd_link_wifi_essid) == 0) {
12356ba597c5SAnurag S. Maskey /* Update connected signal strength */
12366ba597c5SAnurag S. Maskey (void) dladm_wlan_strength2str(&attr.la_wlan_attr.wa_strength,
12376ba597c5SAnurag S. Maskey link->nwamd_link_wifi_signal_strength);
12386ba597c5SAnurag S. Maskey
12396ba597c5SAnurag S. Maskey /* Store current BSSID */
12406ba597c5SAnurag S. Maskey (void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
12416ba597c5SAnurag S. Maskey sizeof (link->nwamd_link_wifi_bssid));
12426ba597c5SAnurag S. Maskey
12436ba597c5SAnurag S. Maskey if (attr.la_wlan_attr.wa_strength < wireless_scan_level) {
12446ba597c5SAnurag S. Maskey /*
12456ba597c5SAnurag S. Maskey * We're connected, but we've dropped below
12466ba597c5SAnurag S. Maskey * scan threshold. Initiate a scan.
12476ba597c5SAnurag S. Maskey */
12486ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_connected: "
12496ba597c5SAnurag S. Maskey "connected but signal under threshold...");
12506ba597c5SAnurag S. Maskey (void) nwamd_wlan_scan(ncu->ncu_name);
12516ba597c5SAnurag S. Maskey }
12526ba597c5SAnurag S. Maskey return (connected);
12536ba597c5SAnurag S. Maskey } else if (strlen(essid) == 0) {
12546ba597c5SAnurag S. Maskey /*
12556ba597c5SAnurag S. Maskey * For hidden WLANs, no ESSID is specified, so we cannot verify
12566ba597c5SAnurag S. Maskey * WLAN name.
12576ba597c5SAnurag S. Maskey */
12586ba597c5SAnurag S. Maskey nlog(LOG_DEBUG,
12596ba597c5SAnurag S. Maskey "nwamd_wlan_connected: connected to hidden WLAN, cannot "
12606ba597c5SAnurag S. Maskey "verify connection details");
12616ba597c5SAnurag S. Maskey return (connected);
12626ba597c5SAnurag S. Maskey } else {
12636ba597c5SAnurag S. Maskey (void) nlog(LOG_ERR,
12646ba597c5SAnurag S. Maskey "nwamd_wlan_connected: wrong AP on %s; expected %s %s",
12656ba597c5SAnurag S. Maskey ncu->ncu_name, link->nwamd_link_wifi_essid,
12666ba597c5SAnurag S. Maskey link->nwamd_link_wifi_bssid);
12676ba597c5SAnurag S. Maskey (void) dladm_wlan_disconnect(dld_handle, link->nwamd_link_id);
12686ba597c5SAnurag S. Maskey link->nwamd_link_wifi_connected = B_FALSE;
12696ba597c5SAnurag S. Maskey return (B_FALSE);
12706ba597c5SAnurag S. Maskey }
12716ba597c5SAnurag S. Maskey }
12726ba597c5SAnurag S. Maskey
12736ba597c5SAnurag S. Maskey /*
12746ba597c5SAnurag S. Maskey * WLAN scan thread. Called with the per-link WiFi mutex held.
12756ba597c5SAnurag S. Maskey */
12766ba597c5SAnurag S. Maskey static void *
wlan_scan_thread(void * arg)12776ba597c5SAnurag S. Maskey wlan_scan_thread(void *arg)
12786ba597c5SAnurag S. Maskey {
12796ba597c5SAnurag S. Maskey char *linkname = arg;
12806ba597c5SAnurag S. Maskey nwamd_object_t ncu_obj;
12816ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu;
12826ba597c5SAnurag S. Maskey nwamd_link_t *link;
12836ba597c5SAnurag S. Maskey dladm_status_t status;
12846ba597c5SAnurag S. Maskey char essid[DLADM_STRSIZE];
12856ba597c5SAnurag S. Maskey char bssid[DLADM_STRSIZE];
12866ba597c5SAnurag S. Maskey uint32_t now, link_id;
12876ba597c5SAnurag S. Maskey nwamd_wifi_scan_t s;
12886ba597c5SAnurag S. Maskey int i;
12896ba597c5SAnurag S. Maskey
12906ba597c5SAnurag S. Maskey if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
12916ba597c5SAnurag S. Maskey == NULL) {
12926ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_scan_thread: could not find object "
12936ba597c5SAnurag S. Maskey "for link %s", linkname);
12946ba597c5SAnurag S. Maskey free(linkname);
12956ba597c5SAnurag S. Maskey return (NULL);
12966ba597c5SAnurag S. Maskey }
12976ba597c5SAnurag S. Maskey
12986ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
1299f6da83d4SAnurag S. Maskey link = &ncu->ncu_link;
13006ba597c5SAnurag S. Maskey
13016ba597c5SAnurag S. Maskey /*
13026ba597c5SAnurag S. Maskey * It is possible multiple scan threads have queued up waiting for the
13036ba597c5SAnurag S. Maskey * object lock. We try to prevent excessive scanning by limiting the
13046ba597c5SAnurag S. Maskey * interval between scans to WIRELESS_SCAN_REQUESTED_INTERVAL_MIN sec.
13056ba597c5SAnurag S. Maskey */
13066ba597c5SAnurag S. Maskey now = NSEC_TO_SEC(gethrtime());
13076ba597c5SAnurag S. Maskey if ((now - link->nwamd_link_wifi_scan.nwamd_wifi_scan_last_time) <
13086ba597c5SAnurag S. Maskey WIRELESS_SCAN_REQUESTED_INTERVAL_MIN) {
13096ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_scan_thread: last scan for %s "
13106ba597c5SAnurag S. Maskey "was < %d sec ago, ignoring scan request",
13116ba597c5SAnurag S. Maskey linkname, WIRELESS_SCAN_REQUESTED_INTERVAL_MIN);
13126ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
13136ba597c5SAnurag S. Maskey free(linkname);
13146ba597c5SAnurag S. Maskey return (NULL);
13156ba597c5SAnurag S. Maskey }
13166ba597c5SAnurag S. Maskey
13176ba597c5SAnurag S. Maskey /*
13186ba597c5SAnurag S. Maskey * Prepare scan data - copy link name and copy previous "current"
13196ba597c5SAnurag S. Maskey * scan results from the nwamd_link_t to the last scan results for
13206ba597c5SAnurag S. Maskey * the next scan so that we can compare results to find if things
13216ba597c5SAnurag S. Maskey * have changed since last time.
13226ba597c5SAnurag S. Maskey */
13236ba597c5SAnurag S. Maskey (void) bzero(&s, sizeof (nwamd_wifi_scan_t));
13246ba597c5SAnurag S. Maskey (void) strlcpy(s.nwamd_wifi_scan_link, ncu->ncu_name,
13256ba597c5SAnurag S. Maskey sizeof (s.nwamd_wifi_scan_link));
13266ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_last_num =
13276ba597c5SAnurag S. Maskey link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num;
13286ba597c5SAnurag S. Maskey if (s.nwamd_wifi_scan_last_num > 0) {
13296ba597c5SAnurag S. Maskey (void) memcpy(s.nwamd_wifi_scan_last,
13306ba597c5SAnurag S. Maskey link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr,
13316ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_last_num * sizeof (nwam_wlan_t));
13326ba597c5SAnurag S. Maskey }
13336ba597c5SAnurag S. Maskey link_id = link->nwamd_link_id;
13346ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
13356ba597c5SAnurag S. Maskey
13366ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_scan_thread: initiating scan on %s",
13376ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_link);
13386ba597c5SAnurag S. Maskey
13396ba597c5SAnurag S. Maskey scanconnect_entry();
13406ba597c5SAnurag S. Maskey status = dladm_wlan_scan(dld_handle, link_id, &s, get_scan_results);
13416ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_last_time = NSEC_TO_SEC(gethrtime());
13426ba597c5SAnurag S. Maskey if (!s.nwamd_wifi_scan_changed) {
13436ba597c5SAnurag S. Maskey /* Scan may have lost WLANs, if so this qualifies as change */
13446ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_changed = (s.nwamd_wifi_scan_curr_num !=
13456ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_last_num);
13466ba597c5SAnurag S. Maskey }
13476ba597c5SAnurag S. Maskey scanconnect_exit();
13486ba597c5SAnurag S. Maskey
13496ba597c5SAnurag S. Maskey if (status != DLADM_STATUS_OK) {
13506ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_scan_thread: cannot scan link %s",
13516ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_link);
13526ba597c5SAnurag S. Maskey free(linkname);
13536ba597c5SAnurag S. Maskey return (NULL);
13546ba597c5SAnurag S. Maskey }
13556ba597c5SAnurag S. Maskey
13566ba597c5SAnurag S. Maskey if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
13576ba597c5SAnurag S. Maskey == NULL) {
13586ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_scan_thread: could not find object "
13596ba597c5SAnurag S. Maskey "for link %s after doing scan", linkname);
13606ba597c5SAnurag S. Maskey free(linkname);
13616ba597c5SAnurag S. Maskey return (NULL);
13626ba597c5SAnurag S. Maskey }
13636ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
1364f6da83d4SAnurag S. Maskey link = &ncu->ncu_link;
13656ba597c5SAnurag S. Maskey
13666ba597c5SAnurag S. Maskey /* For new scan data, add key info from known WLANs */
13676ba597c5SAnurag S. Maskey for (i = 0; i < s.nwamd_wifi_scan_curr_num; i++) {
13686ba597c5SAnurag S. Maskey if (NEED_ENC(s.nwamd_wifi_scan_curr[i].nww_security_mode)) {
13696ba597c5SAnurag S. Maskey char keyname[NWAM_MAX_VALUE_LEN];
13706ba597c5SAnurag S. Maskey dladm_wlan_key_t *key = NULL;
13716ba597c5SAnurag S. Maskey
1372*c1976b83Senricop /*
1373*c1976b83Senricop * If strict_bssid is true, we start checking for
1374*c1976b83Senricop * known wlans with the same BSSID.
1375*c1976b83Senricop * This would prevent the selection of secobjs
1376*c1976b83Senricop * that actually are referenced by different kwl
1377*c1976b83Senricop * with the same ESSID.
1378*c1976b83Senricop */
1379*c1976b83Senricop if (wireless_strict_bssid) {
1380*c1976b83Senricop int b_match = 0;
1381*c1976b83Senricop (void) nwam_walk_known_wlans(bssid_match,
1382*c1976b83Senricop s.nwamd_wifi_scan_curr[i].nww_bssid, 0,
1383*c1976b83Senricop &b_match);
1384*c1976b83Senricop if (b_match == 0)
1385*c1976b83Senricop continue;
1386*c1976b83Senricop }
1387*c1976b83Senricop
13886ba597c5SAnurag S. Maskey if (known_wlan_get_keyname
13896ba597c5SAnurag S. Maskey (s.nwamd_wifi_scan_curr[i].nww_essid, keyname)
13906ba597c5SAnurag S. Maskey == NWAM_SUCCESS &&
13916ba597c5SAnurag S. Maskey (key = nwamd_wlan_get_key_named(keyname,
13926ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_curr[i].nww_security_mode))
13936ba597c5SAnurag S. Maskey != NULL) {
13946ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_curr[i].nww_have_key =
13956ba597c5SAnurag S. Maskey B_TRUE;
13966ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_curr[i].nww_keyindex =
13976ba597c5SAnurag S. Maskey s.nwamd_wifi_scan_curr[i].
13986ba597c5SAnurag S. Maskey nww_security_mode ==
13996ba597c5SAnurag S. Maskey DLADM_WLAN_SECMODE_WEP ?
14006ba597c5SAnurag S. Maskey key->wk_idx : 1;
1401*c1976b83Senricop nlog(LOG_DEBUG, "found matching keyname for \
1402*c1976b83Senricop %s", s.nwamd_wifi_scan_curr[i].nww_bssid);
14036ba597c5SAnurag S. Maskey free(key);
14046ba597c5SAnurag S. Maskey }
14056ba597c5SAnurag S. Maskey }
14066ba597c5SAnurag S. Maskey }
14076ba597c5SAnurag S. Maskey /* Copy scan data into nwamd_link_t */
14086ba597c5SAnurag S. Maskey link->nwamd_link_wifi_scan = s;
14096ba597c5SAnurag S. Maskey /* Set selected, connected and send scan event if we've got new data */
14106ba597c5SAnurag S. Maskey nwamd_set_selected_connected(ncu,
14116ba597c5SAnurag S. Maskey link->nwamd_link_wifi_essid[0] != '\0',
14126ba597c5SAnurag S. Maskey link->nwamd_link_wifi_connected);
14136ba597c5SAnurag S. Maskey
14146ba597c5SAnurag S. Maskey /*
14156ba597c5SAnurag S. Maskey * If wireless selection is not possible because of the current
14166ba597c5SAnurag S. Maskey * state or priority-group, then this was just a scan request.
14176ba597c5SAnurag S. Maskey * Nothing else to do.
14186ba597c5SAnurag S. Maskey */
14196ba597c5SAnurag S. Maskey if (!wireless_selection_possible(ncu_obj)) {
14206ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
14216ba597c5SAnurag S. Maskey free(linkname);
14226ba597c5SAnurag S. Maskey return (NULL);
14236ba597c5SAnurag S. Maskey }
14246ba597c5SAnurag S. Maskey
14256ba597c5SAnurag S. Maskey /*
14266ba597c5SAnurag S. Maskey * Check if WLAN is on our known WLAN list. If no
14276ba597c5SAnurag S. Maskey * previously-visited WLANs are found in scan data, set
14286ba597c5SAnurag S. Maskey * new state to NEED_SELECTION (provided we're not currently
14296ba597c5SAnurag S. Maskey * connected, as can be the case during a periodic scan or
14306ba597c5SAnurag S. Maskey * monitor-triggered scan where the signal strength recovers.
14316ba597c5SAnurag S. Maskey */
14326ba597c5SAnurag S. Maskey if (!nwamd_find_known_wlan(ncu_obj)) {
14336ba597c5SAnurag S. Maskey if (!nwamd_wlan_connected(ncu_obj)) {
14346ba597c5SAnurag S. Maskey if (link->nwamd_link_wifi_connected) {
14356ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_scan_thread: "
14366ba597c5SAnurag S. Maskey "unexpected disconnect after scan");
14376ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
14386ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
14396ba597c5SAnurag S. Maskey NWAM_STATE_ONLINE_TO_OFFLINE,
14406ba597c5SAnurag S. Maskey NWAM_AUX_STATE_DOWN);
14416ba597c5SAnurag S. Maskey } else {
14426ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_scan_thread: "
14436ba597c5SAnurag S. Maskey "no known WLANs - ask user");
14446ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
14456ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
14466ba597c5SAnurag S. Maskey NWAM_STATE_OFFLINE_TO_ONLINE,
14476ba597c5SAnurag S. Maskey NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION);
14486ba597c5SAnurag S. Maskey }
14496ba597c5SAnurag S. Maskey } else {
14506ba597c5SAnurag S. Maskey /* still connected. if not online, change to online */
14516ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_scan_thread: still connected to "
14526ba597c5SAnurag S. Maskey "%s %s", link->nwamd_link_wifi_essid,
14536ba597c5SAnurag S. Maskey link->nwamd_link_wifi_bssid);
14546ba597c5SAnurag S. Maskey if (ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
14556ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
14566ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
14576ba597c5SAnurag S. Maskey NWAM_STATE_OFFLINE_TO_ONLINE,
14586ba597c5SAnurag S. Maskey NWAM_AUX_STATE_UP);
14596ba597c5SAnurag S. Maskey }
14606ba597c5SAnurag S. Maskey }
14616ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
14626ba597c5SAnurag S. Maskey
14636ba597c5SAnurag S. Maskey } else {
14646ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_scan_thread: found known WLAN %s %s",
14656ba597c5SAnurag S. Maskey link->nwamd_link_wifi_essid, link->nwamd_link_wifi_bssid);
14666ba597c5SAnurag S. Maskey
14676ba597c5SAnurag S. Maskey if (!nwamd_wlan_connected(ncu_obj)) {
14686ba597c5SAnurag S. Maskey /* Copy selected ESSID/BSSID, unlock, call select */
14696ba597c5SAnurag S. Maskey (void) strlcpy(essid, link->nwamd_link_wifi_essid,
14706ba597c5SAnurag S. Maskey sizeof (essid));
14716ba597c5SAnurag S. Maskey (void) strlcpy(bssid, link->nwamd_link_wifi_bssid,
14726ba597c5SAnurag S. Maskey sizeof (bssid));
14736ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
14746ba597c5SAnurag S. Maskey (void) nwamd_wlan_select(linkname, essid, bssid,
14756ba597c5SAnurag S. Maskey link->nwamd_link_wifi_security_mode, B_TRUE);
14766ba597c5SAnurag S. Maskey } else {
14776ba597c5SAnurag S. Maskey /* still connected. if not online, change to online */
14786ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_scan_thread: still connected to "
14796ba597c5SAnurag S. Maskey "known WLAN %s %s", link->nwamd_link_wifi_essid,
14806ba597c5SAnurag S. Maskey link->nwamd_link_wifi_bssid);
14816ba597c5SAnurag S. Maskey if (ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
14826ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
14836ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
14846ba597c5SAnurag S. Maskey NWAM_STATE_OFFLINE_TO_ONLINE,
14856ba597c5SAnurag S. Maskey NWAM_AUX_STATE_UP);
14866ba597c5SAnurag S. Maskey }
14876ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
14886ba597c5SAnurag S. Maskey }
14896ba597c5SAnurag S. Maskey }
14906ba597c5SAnurag S. Maskey free(linkname);
14916ba597c5SAnurag S. Maskey return (NULL);
14926ba597c5SAnurag S. Maskey }
14936ba597c5SAnurag S. Maskey
14946ba597c5SAnurag S. Maskey nwam_error_t
nwamd_wlan_scan(const char * linkname)14956ba597c5SAnurag S. Maskey nwamd_wlan_scan(const char *linkname)
14966ba597c5SAnurag S. Maskey {
14976ba597c5SAnurag S. Maskey pthread_t wifi_thread;
14986ba597c5SAnurag S. Maskey char *link = strdup(linkname);
14996ba597c5SAnurag S. Maskey
15006ba597c5SAnurag S. Maskey if (link == NULL) {
15016ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_scan: out of memory");
15026ba597c5SAnurag S. Maskey return (NWAM_NO_MEMORY);
15036ba597c5SAnurag S. Maskey }
15046ba597c5SAnurag S. Maskey
15056ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_scan: WLAN scan for %s",
15066ba597c5SAnurag S. Maskey link);
15076ba597c5SAnurag S. Maskey
15086ba597c5SAnurag S. Maskey if (pthread_create(&wifi_thread, NULL, wlan_scan_thread,
15096ba597c5SAnurag S. Maskey link) != 0) {
15106ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_scan: could not start scan");
15116ba597c5SAnurag S. Maskey free(link);
15126ba597c5SAnurag S. Maskey return (NWAM_ERROR_INTERNAL);
15136ba597c5SAnurag S. Maskey }
15146ba597c5SAnurag S. Maskey /* detach thread so that it doesn't become a zombie */
15156ba597c5SAnurag S. Maskey (void) pthread_detach(wifi_thread);
15166ba597c5SAnurag S. Maskey return (NWAM_SUCCESS);
15176ba597c5SAnurag S. Maskey }
15186ba597c5SAnurag S. Maskey
15196ba597c5SAnurag S. Maskey /*
15206ba597c5SAnurag S. Maskey * WLAN connection code.
15216ba597c5SAnurag S. Maskey */
15226ba597c5SAnurag S. Maskey
15236ba597c5SAnurag S. Maskey static dladm_status_t
do_connect(uint32_t link_id,dladm_wlan_attr_t * attrp,dladm_wlan_key_t * key,uint_t keycount,uint_t flags)15246ba597c5SAnurag S. Maskey do_connect(uint32_t link_id, dladm_wlan_attr_t *attrp, dladm_wlan_key_t *key,
15256ba597c5SAnurag S. Maskey uint_t keycount, uint_t flags)
15266ba597c5SAnurag S. Maskey {
15276ba597c5SAnurag S. Maskey dladm_status_t status;
15286ba597c5SAnurag S. Maskey char errmsg[DLADM_STRSIZE];
15296ba597c5SAnurag S. Maskey
15306ba597c5SAnurag S. Maskey scanconnect_entry();
15316ba597c5SAnurag S. Maskey status = dladm_wlan_connect(dld_handle, link_id, attrp,
15326ba597c5SAnurag S. Maskey DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT, key, keycount, flags);
15336ba597c5SAnurag S. Maskey scanconnect_exit();
15346ba597c5SAnurag S. Maskey
15356ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_do_connect: dladm_wlan_connect returned %s",
15366ba597c5SAnurag S. Maskey dladm_status2str(status, errmsg));
15376ba597c5SAnurag S. Maskey
15386ba597c5SAnurag S. Maskey return (status);
15396ba597c5SAnurag S. Maskey }
15406ba597c5SAnurag S. Maskey
15416ba597c5SAnurag S. Maskey static void *
wlan_connect_thread(void * arg)15426ba597c5SAnurag S. Maskey wlan_connect_thread(void *arg)
15436ba597c5SAnurag S. Maskey {
15446ba597c5SAnurag S. Maskey char *linkname = arg;
15456ba597c5SAnurag S. Maskey nwamd_object_t ncu_obj;
15466ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu;
15476ba597c5SAnurag S. Maskey nwamd_link_t *link;
15486ba597c5SAnurag S. Maskey nwam_error_t err;
15496ba597c5SAnurag S. Maskey uint_t keycount;
15506ba597c5SAnurag S. Maskey uint32_t link_id;
15516ba597c5SAnurag S. Maskey dladm_wlan_key_t *key = NULL;
15526ba597c5SAnurag S. Maskey dladm_wlan_attr_t attr;
15536ba597c5SAnurag S. Maskey dladm_status_t status;
15546ba597c5SAnurag S. Maskey boolean_t autoconf = B_FALSE;
15556ba597c5SAnurag S. Maskey
15566ba597c5SAnurag S. Maskey if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
15576ba597c5SAnurag S. Maskey == NULL) {
15586ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_connect_thread: could not find object "
15596ba597c5SAnurag S. Maskey "for link %s", linkname);
15606ba597c5SAnurag S. Maskey free(linkname);
15616ba597c5SAnurag S. Maskey return (NULL);
15626ba597c5SAnurag S. Maskey }
15636ba597c5SAnurag S. Maskey
15646ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
1565f6da83d4SAnurag S. Maskey link = &ncu->ncu_link;
15666ba597c5SAnurag S. Maskey
15676ba597c5SAnurag S. Maskey if (!wireless_selection_possible(ncu_obj)) {
15686ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_connect_thread: %s in invalid state or "
15696ba597c5SAnurag S. Maskey "has lower priority", ncu->ncu_name);
15706ba597c5SAnurag S. Maskey goto done;
15716ba597c5SAnurag S. Maskey }
15726ba597c5SAnurag S. Maskey
15736ba597c5SAnurag S. Maskey /* If it is already connected to the required AP, just return. */
15746ba597c5SAnurag S. Maskey if (nwamd_wlan_connected(ncu_obj)) {
15756ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
15766ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
15776ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_state, NWAM_AUX_STATE_UP);
15786ba597c5SAnurag S. Maskey goto done;
15796ba597c5SAnurag S. Maskey }
15806ba597c5SAnurag S. Maskey
158119cbc0aaSAnurag S. Maskey (void) memset(&attr, 0, sizeof (attr));
15826ba597c5SAnurag S. Maskey if (dladm_wlan_str2essid(link->nwamd_link_wifi_essid, &attr.wa_essid)
15836ba597c5SAnurag S. Maskey != DLADM_STATUS_OK) {
15846ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_connect_thread: invalid ESSID '%s' "
15856ba597c5SAnurag S. Maskey "for '%s'", link->nwamd_link_wifi_essid, ncu->ncu_name);
15866ba597c5SAnurag S. Maskey goto done;
15876ba597c5SAnurag S. Maskey }
15886ba597c5SAnurag S. Maskey attr.wa_valid = DLADM_WLAN_ATTR_ESSID;
15896ba597c5SAnurag S. Maskey
15906ba597c5SAnurag S. Maskey /* note: bssid logic here is non-functional */
15916ba597c5SAnurag S. Maskey if (link->nwamd_link_wifi_bssid[0] != '\0') {
15926ba597c5SAnurag S. Maskey if (dladm_wlan_str2bssid(link->nwamd_link_wifi_bssid,
15936ba597c5SAnurag S. Maskey &attr.wa_bssid) != DLADM_STATUS_OK) {
15946ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_connect_thread: invalid BSSID '%s'",
15956ba597c5SAnurag S. Maskey "for '%s'", link->nwamd_link_wifi_bssid,
15966ba597c5SAnurag S. Maskey ncu->ncu_name);
15976ba597c5SAnurag S. Maskey } else {
15986ba597c5SAnurag S. Maskey attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
15996ba597c5SAnurag S. Maskey }
16006ba597c5SAnurag S. Maskey }
16016ba597c5SAnurag S. Maskey
16026ba597c5SAnurag S. Maskey /* First check for the key */
16036ba597c5SAnurag S. Maskey if (NEED_ENC(link->nwamd_link_wifi_security_mode)) {
16046ba597c5SAnurag S. Maskey if (link->nwamd_link_wifi_key == NULL) {
16056ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_connect_thread: could not find "
16066ba597c5SAnurag S. Maskey "key for WLAN '%s'", link->nwamd_link_wifi_essid);
16076ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
16086ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
16096ba597c5SAnurag S. Maskey NWAM_STATE_OFFLINE_TO_ONLINE,
16106ba597c5SAnurag S. Maskey NWAM_AUX_STATE_LINK_WIFI_NEED_KEY);
16116ba597c5SAnurag S. Maskey goto done;
16126ba597c5SAnurag S. Maskey }
16136ba597c5SAnurag S. Maskey /* Make a copy of the key as we need to unlock the object */
16146ba597c5SAnurag S. Maskey if ((key = calloc(1, sizeof (dladm_wlan_key_t))) == NULL) {
16156ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_connect_thread: out of memory");
16166ba597c5SAnurag S. Maskey goto done;
16176ba597c5SAnurag S. Maskey }
16186ba597c5SAnurag S. Maskey (void) memcpy(key, link->nwamd_link_wifi_key,
16196ba597c5SAnurag S. Maskey sizeof (dladm_wlan_key_t));
16206ba597c5SAnurag S. Maskey
16216ba597c5SAnurag S. Maskey attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
16226ba597c5SAnurag S. Maskey attr.wa_secmode = link->nwamd_link_wifi_security_mode;
16236ba597c5SAnurag S. Maskey keycount = 1;
16246ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_connect_thread: retrieved key");
16256ba597c5SAnurag S. Maskey } else {
16266ba597c5SAnurag S. Maskey key = NULL;
16276ba597c5SAnurag S. Maskey keycount = 0;
16286ba597c5SAnurag S. Maskey }
16296ba597c5SAnurag S. Maskey
16306ba597c5SAnurag S. Maskey /*
16316ba597c5SAnurag S. Maskey * Connect; only scan if a bssid was not specified. If it times out,
16326ba597c5SAnurag S. Maskey * try a second time using autoconf. Drop the object lock during the
16336ba597c5SAnurag S. Maskey * connect attempt since connecting may take some time, and access to
16346ba597c5SAnurag S. Maskey * the link object during that period would be impossible if we held the
16356ba597c5SAnurag S. Maskey * lock.
16366ba597c5SAnurag S. Maskey */
16376ba597c5SAnurag S. Maskey
16386ba597c5SAnurag S. Maskey link->nwamd_link_wifi_autoconf = B_FALSE;
16396ba597c5SAnurag S. Maskey link_id = link->nwamd_link_id;
16406ba597c5SAnurag S. Maskey
16416ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
16426ba597c5SAnurag S. Maskey
16436ba597c5SAnurag S. Maskey status = do_connect(link_id, &attr, key, keycount,
16446ba597c5SAnurag S. Maskey DLADM_WLAN_CONNECT_NOSCAN);
16456ba597c5SAnurag S. Maskey if (status != DLADM_STATUS_OK) {
16466ba597c5SAnurag S. Maskey /* Connect failed, try autoconf */
16476ba597c5SAnurag S. Maskey if (!wireless_autoconf || (status = do_connect(link_id, &attr,
16486ba597c5SAnurag S. Maskey NULL, 0, 0)) != DLADM_STATUS_OK) {
16496ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_connect_thread: connect failed for "
16506ba597c5SAnurag S. Maskey "%s", linkname);
16516ba597c5SAnurag S. Maskey goto done_unlocked;
16526ba597c5SAnurag S. Maskey }
16536ba597c5SAnurag S. Maskey if (status == DLADM_STATUS_OK)
16546ba597c5SAnurag S. Maskey autoconf = B_TRUE;
16556ba597c5SAnurag S. Maskey }
16566ba597c5SAnurag S. Maskey
16576ba597c5SAnurag S. Maskey /* Connect succeeded, reacquire object */
16586ba597c5SAnurag S. Maskey if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
16596ba597c5SAnurag S. Maskey == NULL) {
16606ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_connect_thread: could not find object "
16616ba597c5SAnurag S. Maskey "for link %s", linkname);
16626ba597c5SAnurag S. Maskey goto done_unlocked;
16636ba597c5SAnurag S. Maskey }
16646ba597c5SAnurag S. Maskey
16656ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
1666f6da83d4SAnurag S. Maskey link = &ncu->ncu_link;
16676ba597c5SAnurag S. Maskey
16686ba597c5SAnurag S. Maskey if (autoconf)
16696ba597c5SAnurag S. Maskey link->nwamd_link_wifi_autoconf = B_TRUE;
16706ba597c5SAnurag S. Maskey
16716ba597c5SAnurag S. Maskey /*
16726ba597c5SAnurag S. Maskey * If WLAN is WEP/WPA, we would like to test the connection as the key
16736ba597c5SAnurag S. Maskey * may be wrong. It is difficult to find a reliable test that works
16746ba597c5SAnurag S. Maskey * across APs however. Do nothing for now.
16756ba597c5SAnurag S. Maskey */
16766ba597c5SAnurag S. Maskey link->nwamd_link_wifi_connected = nwamd_wlan_connected(ncu_obj);
16776ba597c5SAnurag S. Maskey
16786ba597c5SAnurag S. Maskey if (link->nwamd_link_wifi_connected) {
16796ba597c5SAnurag S. Maskey if (link->nwamd_link_wifi_add_to_known_wlans) {
16806ba597c5SAnurag S. Maskey /* add to known WLANs */
16816ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_connect_thread: "
16826ba597c5SAnurag S. Maskey "add '%s' to known WLANs",
16836ba597c5SAnurag S. Maskey link->nwamd_link_wifi_essid);
16846ba597c5SAnurag S. Maskey if ((err = nwam_known_wlan_add_to_known_wlans
16856ba597c5SAnurag S. Maskey (link->nwamd_link_wifi_essid,
16866ba597c5SAnurag S. Maskey link->nwamd_link_wifi_bssid[0] != '\0' ?
16876ba597c5SAnurag S. Maskey link->nwamd_link_wifi_bssid : NULL,
16886ba597c5SAnurag S. Maskey link->nwamd_link_wifi_security_mode,
16896ba597c5SAnurag S. Maskey link->nwamd_link_wifi_security_mode ==
16906ba597c5SAnurag S. Maskey DLADM_WLAN_SECMODE_WEP ?
16916ba597c5SAnurag S. Maskey (uint_t)link->nwamd_link_wifi_key->wk_idx : 1,
16926ba597c5SAnurag S. Maskey NEED_ENC(link->nwamd_link_wifi_security_mode) ?
16936ba597c5SAnurag S. Maskey link->nwamd_link_wifi_keyname : NULL))
16946ba597c5SAnurag S. Maskey != NWAM_SUCCESS) {
16956ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_connect_thread: "
16966ba597c5SAnurag S. Maskey "could not add to known WLANs: %s",
16976ba597c5SAnurag S. Maskey nwam_strerror(err));
16986ba597c5SAnurag S. Maskey }
16996ba597c5SAnurag S. Maskey }
17006ba597c5SAnurag S. Maskey nwamd_set_selected_connected(ncu, B_TRUE, B_TRUE);
17016ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "wlan_connect_thread: connect "
17026ba597c5SAnurag S. Maskey "succeeded, setting state online");
17036ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
17046ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name, NWAM_STATE_ONLINE,
17056ba597c5SAnurag S. Maskey NWAM_AUX_STATE_UP);
17066ba597c5SAnurag S. Maskey }
17076ba597c5SAnurag S. Maskey
17086ba597c5SAnurag S. Maskey done:
17096ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
17106ba597c5SAnurag S. Maskey done_unlocked:
17116ba597c5SAnurag S. Maskey free(linkname);
17126ba597c5SAnurag S. Maskey free(key);
17136ba597c5SAnurag S. Maskey
17146ba597c5SAnurag S. Maskey return (NULL);
17156ba597c5SAnurag S. Maskey }
17166ba597c5SAnurag S. Maskey
17176ba597c5SAnurag S. Maskey void
nwamd_wlan_connect(const char * linkname)17186ba597c5SAnurag S. Maskey nwamd_wlan_connect(const char *linkname)
17196ba597c5SAnurag S. Maskey {
17206ba597c5SAnurag S. Maskey pthread_t wifi_thread;
17216ba597c5SAnurag S. Maskey char *link = strdup(linkname);
17226ba597c5SAnurag S. Maskey
17236ba597c5SAnurag S. Maskey if (link == NULL) {
17246ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_connect: out of memory");
17256ba597c5SAnurag S. Maskey return;
17266ba597c5SAnurag S. Maskey }
17276ba597c5SAnurag S. Maskey
17286ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_connect: WLAN connect for %s",
17296ba597c5SAnurag S. Maskey link);
17306ba597c5SAnurag S. Maskey
17316ba597c5SAnurag S. Maskey if (pthread_create(&wifi_thread, NULL, wlan_connect_thread, link) != 0)
17326ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_connect: could not start connect");
17336ba597c5SAnurag S. Maskey
17346ba597c5SAnurag S. Maskey /* detach thread so that it doesn't become a zombie */
17356ba597c5SAnurag S. Maskey (void) pthread_detach(wifi_thread);
17366ba597c5SAnurag S. Maskey }
17376ba597c5SAnurag S. Maskey
17386ba597c5SAnurag S. Maskey /*
17396ba597c5SAnurag S. Maskey * Launch signal strength-monitoring thread which periodically
17406ba597c5SAnurag S. Maskey * checks connection and signal strength. If we become disconnected
17416ba597c5SAnurag S. Maskey * or signal drops below threshold specified by wireless_scan_level,
17426ba597c5SAnurag S. Maskey * initiate a scan. The scan initiation is taken care of by
17436ba597c5SAnurag S. Maskey * the call to nwamd_wlan_connected().
17446ba597c5SAnurag S. Maskey */
17456ba597c5SAnurag S. Maskey static void *
wlan_monitor_signal_thread(void * arg)17466ba597c5SAnurag S. Maskey wlan_monitor_signal_thread(void *arg)
17476ba597c5SAnurag S. Maskey {
17486ba597c5SAnurag S. Maskey char *linkname = arg;
17496ba597c5SAnurag S. Maskey nwamd_object_t ncu_obj;
17506ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu;
17516ba597c5SAnurag S. Maskey nwamd_link_t *link;
17526ba597c5SAnurag S. Maskey boolean_t first_time = B_TRUE;
17536ba597c5SAnurag S. Maskey
17546ba597c5SAnurag S. Maskey for (;;) {
17556ba597c5SAnurag S. Maskey if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK,
17566ba597c5SAnurag S. Maskey linkname)) == NULL) {
17576ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_monitor_signal_thread: could "
17586ba597c5SAnurag S. Maskey "not find object for link %s", linkname);
17596ba597c5SAnurag S. Maskey break;
17606ba597c5SAnurag S. Maskey }
17616ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
1762f6da83d4SAnurag S. Maskey link = &ncu->ncu_link;
17636ba597c5SAnurag S. Maskey
17646ba597c5SAnurag S. Maskey /* If the NCU is DISABLED/OFFLINE, exit the monitoring thread */
17656ba597c5SAnurag S. Maskey if (ncu_obj->nwamd_object_state == NWAM_STATE_OFFLINE ||
17666ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_state == NWAM_STATE_DISABLED) {
17676ba597c5SAnurag S. Maskey nlog(LOG_INFO, "wlan_monitor_signal_thread: "
17686ba597c5SAnurag S. Maskey "%s is %s, stopping thread", linkname,
17696ba597c5SAnurag S. Maskey nwam_state_to_string(ncu_obj->nwamd_object_state));
17706ba597c5SAnurag S. Maskey link->nwamd_link_wifi_monitor_thread = 0;
17716ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
17726ba597c5SAnurag S. Maskey break;
17736ba597c5SAnurag S. Maskey }
17746ba597c5SAnurag S. Maskey
17756ba597c5SAnurag S. Maskey /*
17766ba597c5SAnurag S. Maskey * First time thru loop, we check if there is another
17776ba597c5SAnurag S. Maskey * link monitoring thread in operation - if so exit this
17786ba597c5SAnurag S. Maskey * thread.
17796ba597c5SAnurag S. Maskey */
17806ba597c5SAnurag S. Maskey if (first_time) {
17816ba597c5SAnurag S. Maskey first_time = B_FALSE;
17826ba597c5SAnurag S. Maskey
17836ba597c5SAnurag S. Maskey if (link->nwamd_link_wifi_monitor_thread != 0) {
17846ba597c5SAnurag S. Maskey /* Already have a monitor thread for link? */
17856ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
17866ba597c5SAnurag S. Maskey break;
17876ba597c5SAnurag S. Maskey } else {
17886ba597c5SAnurag S. Maskey link->nwamd_link_wifi_monitor_thread =
17896ba597c5SAnurag S. Maskey pthread_self();
17906ba597c5SAnurag S. Maskey }
17916ba597c5SAnurag S. Maskey }
17926ba597c5SAnurag S. Maskey if (!nwamd_wlan_connected(ncu_obj)) {
17936ba597c5SAnurag S. Maskey nlog(LOG_ERR, "wlan_monitor_signal_thread: "
17946ba597c5SAnurag S. Maskey "disconnect occured for WLAN on link %s", linkname);
17956ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
17966ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name,
17976ba597c5SAnurag S. Maskey NWAM_STATE_ONLINE_TO_OFFLINE,
17986ba597c5SAnurag S. Maskey NWAM_AUX_STATE_DOWN);
17996ba597c5SAnurag S. Maskey link->nwamd_link_wifi_monitor_thread = 0;
18006ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
18016ba597c5SAnurag S. Maskey break;
18026ba597c5SAnurag S. Maskey }
18036ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
18046ba597c5SAnurag S. Maskey (void) sleep(WIRELESS_MONITOR_SIGNAL_INTERVAL);
18056ba597c5SAnurag S. Maskey }
18066ba597c5SAnurag S. Maskey free(linkname);
18076ba597c5SAnurag S. Maskey
18086ba597c5SAnurag S. Maskey return (NULL);
18096ba597c5SAnurag S. Maskey }
18106ba597c5SAnurag S. Maskey
18116ba597c5SAnurag S. Maskey void
nwamd_wlan_monitor_signal(const char * linkname)18126ba597c5SAnurag S. Maskey nwamd_wlan_monitor_signal(const char *linkname)
18136ba597c5SAnurag S. Maskey {
18146ba597c5SAnurag S. Maskey pthread_t wifi_thread;
18156ba597c5SAnurag S. Maskey char *link = strdup(linkname);
18166ba597c5SAnurag S. Maskey
18176ba597c5SAnurag S. Maskey if (link == NULL) {
18186ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_monitor_signal: out of memory");
18196ba597c5SAnurag S. Maskey return;
18206ba597c5SAnurag S. Maskey }
18216ba597c5SAnurag S. Maskey
18226ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_wlan_monitor_signal: WLAN monitor for %s",
18236ba597c5SAnurag S. Maskey link);
18246ba597c5SAnurag S. Maskey
18256ba597c5SAnurag S. Maskey if (pthread_create(&wifi_thread, NULL, wlan_monitor_signal_thread,
18266ba597c5SAnurag S. Maskey link) != 0) {
18276ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_wlan_monitor_signal: could not monitor "
18286ba597c5SAnurag S. Maskey "link %s", link);
18296ba597c5SAnurag S. Maskey free(link);
18306ba597c5SAnurag S. Maskey return;
18316ba597c5SAnurag S. Maskey }
18326ba597c5SAnurag S. Maskey
18336ba597c5SAnurag S. Maskey /* detach thread so that it doesn't become a zombie */
18346ba597c5SAnurag S. Maskey (void) pthread_detach(wifi_thread);
18356ba597c5SAnurag S. Maskey }
18366ba597c5SAnurag S. Maskey
18376ba597c5SAnurag S. Maskey void
nwamd_ncu_handle_link_state_event(nwamd_event_t event)18386ba597c5SAnurag S. Maskey nwamd_ncu_handle_link_state_event(nwamd_event_t event)
18396ba597c5SAnurag S. Maskey {
18406ba597c5SAnurag S. Maskey nwam_event_t evm;
18416ba597c5SAnurag S. Maskey nwamd_object_t ncu_obj;
18426ba597c5SAnurag S. Maskey nwamd_ncu_t *ncu;
18436ba597c5SAnurag S. Maskey nwamd_link_t *link;
18446ba597c5SAnurag S. Maskey
18456ba597c5SAnurag S. Maskey ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, event->event_object);
18466ba597c5SAnurag S. Maskey if (ncu_obj == NULL) {
1847f6904bc3SRenee Danson Sommerfeld nlog(LOG_INFO, "nwamd_ncu_handle_link_state_event: no object "
1848f6904bc3SRenee Danson Sommerfeld "%s", event->event_object);
18496ba597c5SAnurag S. Maskey nwamd_event_do_not_send(event);
18506ba597c5SAnurag S. Maskey return;
18516ba597c5SAnurag S. Maskey }
18526ba597c5SAnurag S. Maskey ncu = ncu_obj->nwamd_object_data;
1853f6da83d4SAnurag S. Maskey link = &ncu->ncu_link;
18546ba597c5SAnurag S. Maskey evm = event->event_msg;
18556ba597c5SAnurag S. Maskey
18566ba597c5SAnurag S. Maskey /*
18576ba597c5SAnurag S. Maskey * We ignore link state events for WiFi because it is very flaky.
18586ba597c5SAnurag S. Maskey * Instead we use the monitor thread and drive WiFi state changes from
18596ba597c5SAnurag S. Maskey * there.
18606ba597c5SAnurag S. Maskey */
18616ba597c5SAnurag S. Maskey if (link->nwamd_link_media == DL_WIFI) {
18626ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
18636ba597c5SAnurag S. Maskey return;
18646ba597c5SAnurag S. Maskey }
18656ba597c5SAnurag S. Maskey
18666ba597c5SAnurag S. Maskey /*
18676ba597c5SAnurag S. Maskey * If it's a link up event and we're not disabled, go online.
18686ba597c5SAnurag S. Maskey */
18696ba597c5SAnurag S. Maskey if (evm->nwe_data.nwe_link_state.nwe_link_up &&
18706ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_state != NWAM_STATE_DISABLED) {
18716ba597c5SAnurag S. Maskey
18726ba597c5SAnurag S. Maskey if (link->nwamd_link_activation_mode ==
18736ba597c5SAnurag S. Maskey NWAM_ACTIVATION_MODE_PRIORITIZED) {
18746ba597c5SAnurag S. Maskey int64_t priority_group;
18756ba597c5SAnurag S. Maskey
18766ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&active_ncp_mutex);
18776ba597c5SAnurag S. Maskey priority_group = current_ncu_priority_group;
18786ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
18796ba597c5SAnurag S. Maskey
18806ba597c5SAnurag S. Maskey /* compare priority groups */
18816ba597c5SAnurag S. Maskey if (link->nwamd_link_priority_group > priority_group) {
18826ba597c5SAnurag S. Maskey nlog(LOG_DEBUG,
18836ba597c5SAnurag S. Maskey "nwamd_ncu_handle_link_state_event: "
18846ba597c5SAnurag S. Maskey "got LINK UP event for priority group "
18856ba597c5SAnurag S. Maskey "%lld, less preferred than current %lld, "
18866ba597c5SAnurag S. Maskey "ignoring",
18876ba597c5SAnurag S. Maskey link->nwamd_link_priority_group,
18886ba597c5SAnurag S. Maskey priority_group);
18896ba597c5SAnurag S. Maskey
18906ba597c5SAnurag S. Maskey } else if (link->nwamd_link_priority_group ==
18916ba597c5SAnurag S. Maskey priority_group) {
18926ba597c5SAnurag S. Maskey nlog(LOG_DEBUG,
18936ba597c5SAnurag S. Maskey "nwamd_ncu_handle_link_state_event: "
18946ba597c5SAnurag S. Maskey "got LINK UP event for priority group "
18956ba597c5SAnurag S. Maskey "%lld, same as current %lld",
18966ba597c5SAnurag S. Maskey link->nwamd_link_priority_group,
18976ba597c5SAnurag S. Maskey priority_group);
18986ba597c5SAnurag S. Maskey /*
18996ba597c5SAnurag S. Maskey * Change link state to UP. It will be
19006ba597c5SAnurag S. Maskey * propagated to IP state machine. Only do
19016ba597c5SAnurag S. Maskey * the NCU check if and when the interface
19026ba597c5SAnurag S. Maskey * NCU is online.
19036ba597c5SAnurag S. Maskey */
19046ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
19056ba597c5SAnurag S. Maskey event->event_object,
19066ba597c5SAnurag S. Maskey NWAM_STATE_OFFLINE_TO_ONLINE,
19076ba597c5SAnurag S. Maskey NWAM_AUX_STATE_UP);
19086ba597c5SAnurag S. Maskey } else {
19096ba597c5SAnurag S. Maskey nlog(LOG_DEBUG,
19106ba597c5SAnurag S. Maskey "nwamd_ncu_handle_link_state_event: "
19116ba597c5SAnurag S. Maskey "got LINK UP event for priority group "
19126ba597c5SAnurag S. Maskey "%lld, more preferred than current %lld",
19136ba597c5SAnurag S. Maskey link->nwamd_link_priority_group,
19146ba597c5SAnurag S. Maskey priority_group);
19156ba597c5SAnurag S. Maskey
19166ba597c5SAnurag S. Maskey /*
19176ba597c5SAnurag S. Maskey * We need to mark the link as up so that when
19186ba597c5SAnurag S. Maskey * it is activated we will bring the interface
19196ba597c5SAnurag S. Maskey * up.
19206ba597c5SAnurag S. Maskey */
19216ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
19226ba597c5SAnurag S. Maskey event->event_object,
19236ba597c5SAnurag S. Maskey NWAM_STATE_OFFLINE_TO_ONLINE,
19246ba597c5SAnurag S. Maskey NWAM_AUX_STATE_UP);
19256ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
19266ba597c5SAnurag S. Maskey nwamd_ncp_deactivate_priority_group
19276ba597c5SAnurag S. Maskey (priority_group);
19286ba597c5SAnurag S. Maskey nwamd_ncp_activate_priority_group
19296ba597c5SAnurag S. Maskey (link->nwamd_link_priority_group);
19306ba597c5SAnurag S. Maskey return;
19316ba597c5SAnurag S. Maskey }
19326ba597c5SAnurag S. Maskey
19336ba597c5SAnurag S. Maskey } else if (link->nwamd_link_activation_mode ==
19346ba597c5SAnurag S. Maskey NWAM_ACTIVATION_MODE_MANUAL) {
19356ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_ncu_handle_link_state_event: "
19366ba597c5SAnurag S. Maskey "got LINK UP event for manual NCU %s",
19376ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name);
19386ba597c5SAnurag S. Maskey
19396ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
19406ba597c5SAnurag S. Maskey event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE,
19416ba597c5SAnurag S. Maskey NWAM_AUX_STATE_UP);
19426ba597c5SAnurag S. Maskey }
19436ba597c5SAnurag S. Maskey }
19446ba597c5SAnurag S. Maskey
19456ba597c5SAnurag S. Maskey /*
19466ba597c5SAnurag S. Maskey * If the link is down then start or continue transition down.
19476ba597c5SAnurag S. Maskey */
19486ba597c5SAnurag S. Maskey if (!evm->nwe_data.nwe_link_state.nwe_link_up &&
19496ba597c5SAnurag S. Maskey (ncu_obj->nwamd_object_state == NWAM_STATE_ONLINE ||
19506ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE)) {
19516ba597c5SAnurag S. Maskey
19526ba597c5SAnurag S. Maskey if (link->nwamd_link_activation_mode ==
19536ba597c5SAnurag S. Maskey NWAM_ACTIVATION_MODE_PRIORITIZED) {
19546ba597c5SAnurag S. Maskey nlog(LOG_DEBUG,
19556ba597c5SAnurag S. Maskey "nwamd_ncu_handle_link_state_event: "
19566ba597c5SAnurag S. Maskey "got LINK DOWN for priority group %lld",
19576ba597c5SAnurag S. Maskey link->nwamd_link_priority_group);
19586ba597c5SAnurag S. Maskey /* Moving to offline checks priority group */
19596ba597c5SAnurag S. Maskey } else {
19606ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_ncu_handle_link_state_event: "
19616ba597c5SAnurag S. Maskey "got LINK DOWN event for manual NCU %s",
19626ba597c5SAnurag S. Maskey ncu_obj->nwamd_object_name);
19636ba597c5SAnurag S. Maskey }
19646ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
19656ba597c5SAnurag S. Maskey event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE,
19666ba597c5SAnurag S. Maskey NWAM_AUX_STATE_DOWN);
19676ba597c5SAnurag S. Maskey }
19686ba597c5SAnurag S. Maskey
19696ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
19706ba597c5SAnurag S. Maskey }
1971