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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 * 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 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 * 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 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 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