xref: /onnv-gate/usr/src/cmd/cmd-inet/lib/nwamd/ncu_phys.c (revision 12923:eb113dc3db0b)
111767SAnurag.Maskey@Sun.COM /*
211767SAnurag.Maskey@Sun.COM  * CDDL HEADER START
311767SAnurag.Maskey@Sun.COM  *
411767SAnurag.Maskey@Sun.COM  * The contents of this file are subject to the terms of the
511767SAnurag.Maskey@Sun.COM  * Common Development and Distribution License (the "License").
611767SAnurag.Maskey@Sun.COM  * You may not use this file except in compliance with the License.
711767SAnurag.Maskey@Sun.COM  *
811767SAnurag.Maskey@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911767SAnurag.Maskey@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011767SAnurag.Maskey@Sun.COM  * See the License for the specific language governing permissions
1111767SAnurag.Maskey@Sun.COM  * and limitations under the License.
1211767SAnurag.Maskey@Sun.COM  *
1311767SAnurag.Maskey@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411767SAnurag.Maskey@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511767SAnurag.Maskey@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611767SAnurag.Maskey@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711767SAnurag.Maskey@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811767SAnurag.Maskey@Sun.COM  *
1911767SAnurag.Maskey@Sun.COM  * CDDL HEADER END
2011767SAnurag.Maskey@Sun.COM  */
2111767SAnurag.Maskey@Sun.COM 
2211767SAnurag.Maskey@Sun.COM /*
2312080SAnurag.Maskey@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411767SAnurag.Maskey@Sun.COM  */
2511767SAnurag.Maskey@Sun.COM 
2611767SAnurag.Maskey@Sun.COM #include <assert.h>
2711767SAnurag.Maskey@Sun.COM #include <ctype.h>
2811767SAnurag.Maskey@Sun.COM #include <err.h>
2911767SAnurag.Maskey@Sun.COM #include <errno.h>
3011767SAnurag.Maskey@Sun.COM #include <execinfo.h>
3111767SAnurag.Maskey@Sun.COM #include <kstat.h>
3211767SAnurag.Maskey@Sun.COM #include <libdladm.h>
3311767SAnurag.Maskey@Sun.COM #include <libdllink.h>
3411767SAnurag.Maskey@Sun.COM #include <libdlstat.h>
3511767SAnurag.Maskey@Sun.COM #include <libdlwlan.h>
3611767SAnurag.Maskey@Sun.COM #include <libnwam.h>
3711767SAnurag.Maskey@Sun.COM #include <limits.h>
3811767SAnurag.Maskey@Sun.COM #include <pthread.h>
3911767SAnurag.Maskey@Sun.COM #include <stdio.h>
4011767SAnurag.Maskey@Sun.COM #include <stdlib.h>
4111767SAnurag.Maskey@Sun.COM #include <string.h>
4211767SAnurag.Maskey@Sun.COM #include <strings.h>
4311767SAnurag.Maskey@Sun.COM #include <sys/stat.h>
4411767SAnurag.Maskey@Sun.COM #include <sys/time.h>
4511767SAnurag.Maskey@Sun.COM #include <sys/types.h>
4611767SAnurag.Maskey@Sun.COM #include <unistd.h>
4711767SAnurag.Maskey@Sun.COM #include <libdlpi.h>
4811767SAnurag.Maskey@Sun.COM #include <ucontext.h>
4911767SAnurag.Maskey@Sun.COM 
5011767SAnurag.Maskey@Sun.COM #include "events.h"
5111767SAnurag.Maskey@Sun.COM #include "llp.h"
5211767SAnurag.Maskey@Sun.COM #include "objects.h"
5311767SAnurag.Maskey@Sun.COM #include "ncp.h"
5411767SAnurag.Maskey@Sun.COM #include "ncu.h"
5511767SAnurag.Maskey@Sun.COM #include "known_wlans.h"
5611767SAnurag.Maskey@Sun.COM #include "util.h"
5711767SAnurag.Maskey@Sun.COM 
5811767SAnurag.Maskey@Sun.COM /*
5911767SAnurag.Maskey@Sun.COM  * ncu_phys.c - contains routines that are physical-link specific.
6011767SAnurag.Maskey@Sun.COM  * Mostly WiFi code.
6111767SAnurag.Maskey@Sun.COM  */
6211767SAnurag.Maskey@Sun.COM 
6311767SAnurag.Maskey@Sun.COM /*
6411767SAnurag.Maskey@Sun.COM  * Get link state from kstats. Used to determine initial link state for
6511767SAnurag.Maskey@Sun.COM  * cases where drivers do not support DL_NOTE_LINK_UP/DOWN.  If link
6611767SAnurag.Maskey@Sun.COM  * state is LINK_STATE_UNKNOWN, we assume the link is up and the IP NCU
6711767SAnurag.Maskey@Sun.COM  * timeout will cause us to move on to other links.
6811767SAnurag.Maskey@Sun.COM  */
6911767SAnurag.Maskey@Sun.COM link_state_t
nwamd_get_link_state(const char * name)7011767SAnurag.Maskey@Sun.COM nwamd_get_link_state(const char *name)
7111767SAnurag.Maskey@Sun.COM {
7211767SAnurag.Maskey@Sun.COM 	kstat_ctl_t *kcp;
7311767SAnurag.Maskey@Sun.COM 	kstat_t *ksp;
7411767SAnurag.Maskey@Sun.COM 	char module[DLPI_LINKNAME_MAX];
7511767SAnurag.Maskey@Sun.COM 	uint_t instance;
7611767SAnurag.Maskey@Sun.COM 	link_state_t link_state = LINK_STATE_UNKNOWN;
7711767SAnurag.Maskey@Sun.COM 
7811767SAnurag.Maskey@Sun.COM 	if ((kcp = kstat_open()) == NULL)
7911767SAnurag.Maskey@Sun.COM 		return (link_state);
8011767SAnurag.Maskey@Sun.COM 
8111767SAnurag.Maskey@Sun.COM 	if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
8211767SAnurag.Maskey@Sun.COM 		goto out;
8311767SAnurag.Maskey@Sun.COM 
8411767SAnurag.Maskey@Sun.COM 	if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL) {
8511767SAnurag.Maskey@Sun.COM 		/*
8611767SAnurag.Maskey@Sun.COM 		 * The kstat query could fail if the underlying MAC
8711767SAnurag.Maskey@Sun.COM 		 * driver was already detached.
8811767SAnurag.Maskey@Sun.COM 		 */
8911767SAnurag.Maskey@Sun.COM 		goto out;
9011767SAnurag.Maskey@Sun.COM 	}
9111767SAnurag.Maskey@Sun.COM 
9211767SAnurag.Maskey@Sun.COM 	if (kstat_read(kcp, ksp, NULL) == -1)
9311767SAnurag.Maskey@Sun.COM 		goto out;
9411767SAnurag.Maskey@Sun.COM 
9511767SAnurag.Maskey@Sun.COM 	(void) dladm_kstat_value(ksp, "link_state", KSTAT_DATA_UINT32,
9611767SAnurag.Maskey@Sun.COM 	    &link_state);
9711767SAnurag.Maskey@Sun.COM 
9811767SAnurag.Maskey@Sun.COM out:
9911767SAnurag.Maskey@Sun.COM 	(void) kstat_close(kcp);
10011767SAnurag.Maskey@Sun.COM 
10111767SAnurag.Maskey@Sun.COM 	return (link_state);
10211767SAnurag.Maskey@Sun.COM }
10311767SAnurag.Maskey@Sun.COM 
10411767SAnurag.Maskey@Sun.COM /*
10511767SAnurag.Maskey@Sun.COM  * Set/unset link propeties.  At present, these are MAC address, link MTU and
10611767SAnurag.Maskey@Sun.COM  * autopush modules.  We set MAC address last as setting it may cause a chip
10711767SAnurag.Maskey@Sun.COM  * reset which can prevent other device property setting succeeding.
10811767SAnurag.Maskey@Sun.COM  */
10911767SAnurag.Maskey@Sun.COM void
nwamd_set_unset_link_properties(nwamd_ncu_t * ncu,boolean_t set)11011767SAnurag.Maskey@Sun.COM nwamd_set_unset_link_properties(nwamd_ncu_t *ncu, boolean_t set)
11111767SAnurag.Maskey@Sun.COM {
11212576SAnurag.Maskey@Oracle.COM 	dlpi_handle_t dh = ncu->ncu_link.nwamd_link_dhp;
11312576SAnurag.Maskey@Oracle.COM 	char *addr = set ? ncu->ncu_link.nwamd_link_mac_addr : NULL;
11412576SAnurag.Maskey@Oracle.COM 	uint64_t mtu = set ? ncu->ncu_link.nwamd_link_mtu : 0;
11512576SAnurag.Maskey@Oracle.COM 	char **autopush = set ? ncu->ncu_link.nwamd_link_autopush : NULL;
11612576SAnurag.Maskey@Oracle.COM 	uint_t num_autopush = set ? ncu->ncu_link.nwamd_link_num_autopush : 0;
11711767SAnurag.Maskey@Sun.COM 	uchar_t *hwaddr = NULL, curraddr[DLPI_PHYSADDR_MAX];
11811767SAnurag.Maskey@Sun.COM 	size_t hwaddrlen = DLPI_PHYSADDR_MAX;
11911767SAnurag.Maskey@Sun.COM 	int retval;
12011767SAnurag.Maskey@Sun.COM 	dladm_status_t status;
12111767SAnurag.Maskey@Sun.COM 	char mtustr[DLADM_PROP_VAL_MAX];
12211767SAnurag.Maskey@Sun.COM 	char *cp;
12311767SAnurag.Maskey@Sun.COM 	char errmsg[DLADM_STRSIZE];
12411767SAnurag.Maskey@Sun.COM 	uint_t cnt = 1;
12511767SAnurag.Maskey@Sun.COM 
12611767SAnurag.Maskey@Sun.COM 	/*
12711767SAnurag.Maskey@Sun.COM 	 * Set MTU here - either default value (if mtu == 0 indicating it has
12811767SAnurag.Maskey@Sun.COM 	 * not been set) or specified value.
12911767SAnurag.Maskey@Sun.COM 	 */
13011767SAnurag.Maskey@Sun.COM 	if (mtu == 0) {
13111767SAnurag.Maskey@Sun.COM 		cp = mtustr;
13211767SAnurag.Maskey@Sun.COM 		status = dladm_get_linkprop(dld_handle,
13312576SAnurag.Maskey@Oracle.COM 		    ncu->ncu_link.nwamd_link_id, DLADM_PROP_VAL_DEFAULT, "mtu",
13412576SAnurag.Maskey@Oracle.COM 		    &cp, &cnt);
13511767SAnurag.Maskey@Sun.COM 		if (status != DLADM_STATUS_OK) {
13611767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
13711767SAnurag.Maskey@Sun.COM 			    "dladm_get_linkprop failed: %s",
13811767SAnurag.Maskey@Sun.COM 			    dladm_status2str(status, errmsg));
13911767SAnurag.Maskey@Sun.COM 			return;
14011767SAnurag.Maskey@Sun.COM 		}
14111767SAnurag.Maskey@Sun.COM 	} else {
14211767SAnurag.Maskey@Sun.COM 		(void) snprintf(mtustr, DLADM_PROP_VAL_MAX, "%lld", mtu);
14311767SAnurag.Maskey@Sun.COM 	}
14411767SAnurag.Maskey@Sun.COM 
14511767SAnurag.Maskey@Sun.COM 	cp = mtustr;
14611767SAnurag.Maskey@Sun.COM 
14711767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_set_unset_link_properties: setting MTU of %s "
14811767SAnurag.Maskey@Sun.COM 	    "for link %s", mtustr, ncu->ncu_name);
14912576SAnurag.Maskey@Oracle.COM 	status = dladm_set_linkprop(dld_handle, ncu->ncu_link.nwamd_link_id,
15012576SAnurag.Maskey@Oracle.COM 	    "mtu", &cp, 1, DLADM_OPT_ACTIVE);
15111767SAnurag.Maskey@Sun.COM 	if (status != DLADM_STATUS_OK) {
15211767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
15311767SAnurag.Maskey@Sun.COM 		    "dladm_set_linkprop failed: %s",
15411767SAnurag.Maskey@Sun.COM 		    dladm_status2str(status, errmsg));
15511767SAnurag.Maskey@Sun.COM 	}
15611767SAnurag.Maskey@Sun.COM 
15711767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_set_unset_link_properties: setting %d "
15811767SAnurag.Maskey@Sun.COM 	    "autopush module for link %s", num_autopush, ncu->ncu_name);
15912576SAnurag.Maskey@Oracle.COM 	status = dladm_set_linkprop(dld_handle, ncu->ncu_link.nwamd_link_id,
16012576SAnurag.Maskey@Oracle.COM 	    "autopush", autopush, num_autopush, DLADM_OPT_ACTIVE);
16111767SAnurag.Maskey@Sun.COM 	if (status != DLADM_STATUS_OK) {
16211767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
16311767SAnurag.Maskey@Sun.COM 		    "dladm_set_linkprop failed for autopush property: %s",
16411767SAnurag.Maskey@Sun.COM 		    dladm_status2str(status, errmsg));
16511767SAnurag.Maskey@Sun.COM 	}
16611767SAnurag.Maskey@Sun.COM 
16711767SAnurag.Maskey@Sun.COM 	/*
16811767SAnurag.Maskey@Sun.COM 	 * Set physical address - either factory (if link_mac_addr is NULL
16911767SAnurag.Maskey@Sun.COM 	 * or we are unsetting properties) or specified MAC address string.
17011767SAnurag.Maskey@Sun.COM 	 */
17111767SAnurag.Maskey@Sun.COM 	if (addr == NULL) {
17211767SAnurag.Maskey@Sun.COM 		if ((hwaddr = calloc(1, DLPI_PHYSADDR_MAX)) == NULL) {
17311767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR,
17411767SAnurag.Maskey@Sun.COM 			    "nwamd_set_unset_link_properties: malloc() failed");
17511767SAnurag.Maskey@Sun.COM 			return;
17611767SAnurag.Maskey@Sun.COM 		}
17711767SAnurag.Maskey@Sun.COM 		if ((retval = dlpi_get_physaddr(dh, DL_FACT_PHYS_ADDR,
17811767SAnurag.Maskey@Sun.COM 		    hwaddr, &hwaddrlen)) != DLPI_SUCCESS) {
17911767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
18011767SAnurag.Maskey@Sun.COM 			    "could not get physical address for %s: %s",
18111767SAnurag.Maskey@Sun.COM 			    ncu->ncu_name, dlpi_strerror(retval));
18211767SAnurag.Maskey@Sun.COM 			free(hwaddr);
18311767SAnurag.Maskey@Sun.COM 			return;
18411767SAnurag.Maskey@Sun.COM 		}
18511767SAnurag.Maskey@Sun.COM 	} else {
18611767SAnurag.Maskey@Sun.COM 		int addrlen = hwaddrlen;
18711767SAnurag.Maskey@Sun.COM 		if ((hwaddr = _link_aton(addr, &addrlen)) == NULL) {
18811767SAnurag.Maskey@Sun.COM 			if (addrlen == -1) {
18911767SAnurag.Maskey@Sun.COM 				nlog(LOG_ERR,
19011767SAnurag.Maskey@Sun.COM 				    "nwamd_set_unset_link_properties: "
19111767SAnurag.Maskey@Sun.COM 				    "%s: bad address for %s",
19211767SAnurag.Maskey@Sun.COM 				    addr, ncu->ncu_name);
19311767SAnurag.Maskey@Sun.COM 				return;
19411767SAnurag.Maskey@Sun.COM 			} else {
19511767SAnurag.Maskey@Sun.COM 				nlog(LOG_ERR, "nwamd_set_unset_link_properties:"
19611767SAnurag.Maskey@Sun.COM 				    " malloc() failed");
19711767SAnurag.Maskey@Sun.COM 				return;
19811767SAnurag.Maskey@Sun.COM 			}
19911767SAnurag.Maskey@Sun.COM 		}
20011767SAnurag.Maskey@Sun.COM 		hwaddrlen = addrlen;
20111767SAnurag.Maskey@Sun.COM 	}
20211767SAnurag.Maskey@Sun.COM 
20311767SAnurag.Maskey@Sun.COM 	/*
20411767SAnurag.Maskey@Sun.COM 	 * Only set physical address if desired address differs from current -
20511767SAnurag.Maskey@Sun.COM 	 * this avoids unnecessary chip resets for some drivers.
20611767SAnurag.Maskey@Sun.COM 	 */
20711767SAnurag.Maskey@Sun.COM 	retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, curraddr,
20811767SAnurag.Maskey@Sun.COM 	    &hwaddrlen);
20911767SAnurag.Maskey@Sun.COM 	if (retval != DLPI_SUCCESS || bcmp(curraddr, hwaddr, hwaddrlen) != 0) {
21011767SAnurag.Maskey@Sun.COM 		retval = dlpi_set_physaddr(dh, DL_CURR_PHYS_ADDR, hwaddr,
21111767SAnurag.Maskey@Sun.COM 		    hwaddrlen);
21211767SAnurag.Maskey@Sun.COM 		if (retval != DLPI_SUCCESS) {
21311767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_set_unset_link_properties:"
21411767SAnurag.Maskey@Sun.COM 			    "failed setting mac address on %s: %s",
21511767SAnurag.Maskey@Sun.COM 			    ncu->ncu_name, dlpi_strerror(retval));
21611767SAnurag.Maskey@Sun.COM 		}
21711767SAnurag.Maskey@Sun.COM 	}
21811767SAnurag.Maskey@Sun.COM 	free(hwaddr);
21911767SAnurag.Maskey@Sun.COM }
22011767SAnurag.Maskey@Sun.COM 
22111767SAnurag.Maskey@Sun.COM #define	WLAN_ENC(sec)						\
22211767SAnurag.Maskey@Sun.COM 	((sec == DLADM_WLAN_SECMODE_WPA ? "WPA" : 		\
22311767SAnurag.Maskey@Sun.COM 	(sec == DLADM_WLAN_SECMODE_WEP ? "WEP" : "none")))
22411767SAnurag.Maskey@Sun.COM 
22511767SAnurag.Maskey@Sun.COM #define	NEED_ENC(sec)						\
22611767SAnurag.Maskey@Sun.COM 	(sec == DLADM_WLAN_SECMODE_WPA || sec == DLADM_WLAN_SECMODE_WEP)
22711767SAnurag.Maskey@Sun.COM 
22811767SAnurag.Maskey@Sun.COM #define	WIRELESS_LAN_INIT_COUNT	8
22911767SAnurag.Maskey@Sun.COM 
23011767SAnurag.Maskey@Sun.COM /*
23111767SAnurag.Maskey@Sun.COM  * The variable wireless_scan_level specifies the signal level
23211767SAnurag.Maskey@Sun.COM  * that we will initiate connections to previously-visited APs
23311767SAnurag.Maskey@Sun.COM  * at when we are in the connected state.
23411767SAnurag.Maskey@Sun.COM  */
23511767SAnurag.Maskey@Sun.COM dladm_wlan_strength_t wireless_scan_level = DLADM_WLAN_STRENGTH_WEAK;
23611767SAnurag.Maskey@Sun.COM 
23711767SAnurag.Maskey@Sun.COM /*
23811767SAnurag.Maskey@Sun.COM  * The variable wireless_scan_interval specifies how often the periodic
23911767SAnurag.Maskey@Sun.COM  * scan occurs.
24011767SAnurag.Maskey@Sun.COM  */
24111767SAnurag.Maskey@Sun.COM uint64_t wireless_scan_interval = WIRELESS_SCAN_INTERVAL_DEFAULT;
24211767SAnurag.Maskey@Sun.COM 
24311767SAnurag.Maskey@Sun.COM /*
24411767SAnurag.Maskey@Sun.COM  * The variable wireless_autoconf specifies if we use dladm_wlan_autoconf()
24511767SAnurag.Maskey@Sun.COM  * to connect.
24611767SAnurag.Maskey@Sun.COM  */
24711767SAnurag.Maskey@Sun.COM boolean_t wireless_autoconf = B_FALSE;
24811767SAnurag.Maskey@Sun.COM 
24911767SAnurag.Maskey@Sun.COM /*
25011767SAnurag.Maskey@Sun.COM  * The variable wireless_strict_bssid specifies if we only connect
25111767SAnurag.Maskey@Sun.COM  * to WLANs with BSSIDs that we previously connected to.
25211767SAnurag.Maskey@Sun.COM  */
25311767SAnurag.Maskey@Sun.COM boolean_t wireless_strict_bssid = B_FALSE;
25411767SAnurag.Maskey@Sun.COM 
25511767SAnurag.Maskey@Sun.COM /*
25611767SAnurag.Maskey@Sun.COM  * We need to ensure scan or connect threads do not run concurrently
25711767SAnurag.Maskey@Sun.COM  * on any links - otherwise we get radio interference.  Acquire this
25811767SAnurag.Maskey@Sun.COM  * lock on entering scan/connect threads to prevent this.
25911767SAnurag.Maskey@Sun.COM  */
26011767SAnurag.Maskey@Sun.COM pthread_mutex_t wireless_mutex = PTHREAD_MUTEX_INITIALIZER;
26111767SAnurag.Maskey@Sun.COM 
26211767SAnurag.Maskey@Sun.COM static void
scanconnect_entry(void)26311767SAnurag.Maskey@Sun.COM scanconnect_entry(void)
26411767SAnurag.Maskey@Sun.COM {
26511767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&wireless_mutex);
26611767SAnurag.Maskey@Sun.COM }
26711767SAnurag.Maskey@Sun.COM 
26811767SAnurag.Maskey@Sun.COM static void
scanconnect_exit(void)26911767SAnurag.Maskey@Sun.COM scanconnect_exit(void)
27011767SAnurag.Maskey@Sun.COM {
27111767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&wireless_mutex);
27211767SAnurag.Maskey@Sun.COM }
27311767SAnurag.Maskey@Sun.COM 
27411767SAnurag.Maskey@Sun.COM /*
27511767SAnurag.Maskey@Sun.COM  * Below are functions used to handle storage/retrieval of keys
27611767SAnurag.Maskey@Sun.COM  * for a given WLAN. The keys are stored/retrieved using dladm_set_secobj()
27711767SAnurag.Maskey@Sun.COM  * and dladm_get_secobj().
27811767SAnurag.Maskey@Sun.COM  */
27911767SAnurag.Maskey@Sun.COM 
28011767SAnurag.Maskey@Sun.COM /*
28111767SAnurag.Maskey@Sun.COM  * Convert key hexascii string to raw secobj value. This
28211767SAnurag.Maskey@Sun.COM  * code is very similar to convert_secobj() in dladm.c, it would
28311767SAnurag.Maskey@Sun.COM  * be good to have a libdladm function to convert values.
28411767SAnurag.Maskey@Sun.COM  */
28511767SAnurag.Maskey@Sun.COM static int
key_string_to_secobj_value(char * buf,uint8_t * obj_val,uint_t * obj_lenp,dladm_secobj_class_t class)28611767SAnurag.Maskey@Sun.COM key_string_to_secobj_value(char *buf, uint8_t *obj_val, uint_t *obj_lenp,
28711767SAnurag.Maskey@Sun.COM     dladm_secobj_class_t class)
28811767SAnurag.Maskey@Sun.COM {
28911767SAnurag.Maskey@Sun.COM 	size_t buf_len = strlen(buf);
29011767SAnurag.Maskey@Sun.COM 
29111767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "before: key_string_to_secobj_value: buf_len = %d",
29211767SAnurag.Maskey@Sun.COM 	    buf_len);
29311767SAnurag.Maskey@Sun.COM 	if (buf_len == 0) {
29411767SAnurag.Maskey@Sun.COM 		/* length zero means "delete" */
29511767SAnurag.Maskey@Sun.COM 		return (0);
29611767SAnurag.Maskey@Sun.COM 	}
29711767SAnurag.Maskey@Sun.COM 
29811767SAnurag.Maskey@Sun.COM 	if (buf[buf_len - 1] == '\n')
29911767SAnurag.Maskey@Sun.COM 		buf[--buf_len] = '\0';
30011767SAnurag.Maskey@Sun.COM 
30111767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "after: key_string_to_secobj_value: buf_len = %d",
30211767SAnurag.Maskey@Sun.COM 	    buf_len);
30311767SAnurag.Maskey@Sun.COM 
30411767SAnurag.Maskey@Sun.COM 	if (class == DLADM_SECOBJ_CLASS_WPA) {
30511767SAnurag.Maskey@Sun.COM 		/*
30611767SAnurag.Maskey@Sun.COM 		 * Per IEEE802.11i spec, the Pre-shared key (PSK) length should
30711767SAnurag.Maskey@Sun.COM 		 * be between 8 and 63.
30811767SAnurag.Maskey@Sun.COM 		 */
30911767SAnurag.Maskey@Sun.COM 		if (buf_len < 8 || buf_len > 63) {
31011767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR,
31111767SAnurag.Maskey@Sun.COM 			    "key_string_to_secobj_value:"
31211767SAnurag.Maskey@Sun.COM 			    " invalid WPA key length: buf_len = %d", buf_len);
31311767SAnurag.Maskey@Sun.COM 			return (-1);
31411767SAnurag.Maskey@Sun.COM 		}
31511767SAnurag.Maskey@Sun.COM 		(void) memcpy(obj_val, buf, (uint_t)buf_len);
31611767SAnurag.Maskey@Sun.COM 		*obj_lenp = buf_len;
31711767SAnurag.Maskey@Sun.COM 		return (0);
31811767SAnurag.Maskey@Sun.COM 	}
31911767SAnurag.Maskey@Sun.COM 
32011767SAnurag.Maskey@Sun.COM 	switch (buf_len) {
32111767SAnurag.Maskey@Sun.COM 	case 5:		/* ASCII key sizes */
32211767SAnurag.Maskey@Sun.COM 	case 13:
32311767SAnurag.Maskey@Sun.COM 		(void) memcpy(obj_val, buf, (uint_t)buf_len);
32411767SAnurag.Maskey@Sun.COM 		*obj_lenp = (uint_t)buf_len;
32511767SAnurag.Maskey@Sun.COM 		break;
32611767SAnurag.Maskey@Sun.COM 	case 10:
32711767SAnurag.Maskey@Sun.COM 	case 26:	/* Hex key sizes, not preceded by 0x */
32811767SAnurag.Maskey@Sun.COM 		if (hexascii_to_octet(buf, (uint_t)buf_len, obj_val, obj_lenp)
32911767SAnurag.Maskey@Sun.COM 		    != 0) {
33011767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR,
33111767SAnurag.Maskey@Sun.COM 			    "key_string_to_secobj_value: invalid WEP key");
33211767SAnurag.Maskey@Sun.COM 			return (-1);
33311767SAnurag.Maskey@Sun.COM 		}
33411767SAnurag.Maskey@Sun.COM 		break;
33511767SAnurag.Maskey@Sun.COM 	case 12:
33611767SAnurag.Maskey@Sun.COM 	case 28:	/* Hex key sizes, preceded by 0x */
33711767SAnurag.Maskey@Sun.COM 		if (strncmp(buf, "0x", 2) != 0 ||
33811767SAnurag.Maskey@Sun.COM 		    hexascii_to_octet(buf + 2, (uint_t)buf_len - 2, obj_val,
33911767SAnurag.Maskey@Sun.COM 		    obj_lenp) != 0) {
34011767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR,
34111767SAnurag.Maskey@Sun.COM 			    "key_string_to_secobj_value: invalid WEP key");
34211767SAnurag.Maskey@Sun.COM 			return (-1);
34311767SAnurag.Maskey@Sun.COM 		}
34411767SAnurag.Maskey@Sun.COM 		break;
34511767SAnurag.Maskey@Sun.COM 	default:
34611767SAnurag.Maskey@Sun.COM 		syslog(LOG_ERR,
34711767SAnurag.Maskey@Sun.COM 		    "key_string_to_secobj_value: invalid WEP key length");
34811767SAnurag.Maskey@Sun.COM 		return (-1);
34911767SAnurag.Maskey@Sun.COM 	}
35011767SAnurag.Maskey@Sun.COM 	return (0);
35111767SAnurag.Maskey@Sun.COM }
35211767SAnurag.Maskey@Sun.COM 
35311767SAnurag.Maskey@Sun.COM /*
35411767SAnurag.Maskey@Sun.COM  * Print the key name format into the appropriate field, then convert any ":"
35511767SAnurag.Maskey@Sun.COM  * characters to ".", as ":[1-4]" is the slot indicator, which otherwise
35611767SAnurag.Maskey@Sun.COM  * would trip us up.  Invalid characters for secobj names are ignored.
35711767SAnurag.Maskey@Sun.COM  * The fourth parameter is expected to be of size DLADM_SECOBJ_NAME_MAX.
35811767SAnurag.Maskey@Sun.COM  *
35911767SAnurag.Maskey@Sun.COM  * (Note that much of the system uses DLADM_WLAN_MAX_KEYNAME_LEN, which is 64
36011767SAnurag.Maskey@Sun.COM  * rather than 32, but that dladm_get_secobj will fail if a length greater than
36111767SAnurag.Maskey@Sun.COM  * DLD_SECOBJ_NAME_MAX is seen, and that's 32.  This is all horribly broken.)
36211767SAnurag.Maskey@Sun.COM  */
36311767SAnurag.Maskey@Sun.COM void
nwamd_set_key_name(const char * essid,const char * bssid,char * name,size_t nsz)36411767SAnurag.Maskey@Sun.COM nwamd_set_key_name(const char *essid, const char *bssid, char *name, size_t nsz)
36511767SAnurag.Maskey@Sun.COM {
36611767SAnurag.Maskey@Sun.COM 	int i, j;
36711767SAnurag.Maskey@Sun.COM 	char secobj_name[DLADM_WLAN_MAX_KEYNAME_LEN];
36811767SAnurag.Maskey@Sun.COM 
36911767SAnurag.Maskey@Sun.COM 	/* create a concatenated string with essid and bssid */
37011767SAnurag.Maskey@Sun.COM 	if (bssid == NULL || bssid[0] == '\0') {
37111767SAnurag.Maskey@Sun.COM 		(void) snprintf(secobj_name, sizeof (secobj_name), "nwam-%s",
37211767SAnurag.Maskey@Sun.COM 		    essid);
37311767SAnurag.Maskey@Sun.COM 	} else {
37411767SAnurag.Maskey@Sun.COM 		(void) snprintf(secobj_name, sizeof (secobj_name), "nwam-%s-%s",
37511767SAnurag.Maskey@Sun.COM 		    essid, bssid);
37611767SAnurag.Maskey@Sun.COM 	}
37711767SAnurag.Maskey@Sun.COM 
37811767SAnurag.Maskey@Sun.COM 	/* copy only valid chars to the return string, terminating with \0 */
37911767SAnurag.Maskey@Sun.COM 	i = 0; /* index into secobj_name */
38011767SAnurag.Maskey@Sun.COM 	j = 0; /* index into name */
38111767SAnurag.Maskey@Sun.COM 	while (secobj_name[i] != '\0') {
38211767SAnurag.Maskey@Sun.COM 		if (j == nsz - 1)
38311767SAnurag.Maskey@Sun.COM 			break;
38411767SAnurag.Maskey@Sun.COM 
38511767SAnurag.Maskey@Sun.COM 		if (secobj_name[i] == ':') {
38611767SAnurag.Maskey@Sun.COM 			name[j] = '.';
38711767SAnurag.Maskey@Sun.COM 			j++;
38811767SAnurag.Maskey@Sun.COM 		} else if (isalnum(secobj_name[i]) ||
38911767SAnurag.Maskey@Sun.COM 		    secobj_name[i] == '.' || secobj_name[i] == '-' ||
39011767SAnurag.Maskey@Sun.COM 		    secobj_name[i] == '_') {
39111767SAnurag.Maskey@Sun.COM 			name[j] = secobj_name[i];
39211767SAnurag.Maskey@Sun.COM 			j++;
39311767SAnurag.Maskey@Sun.COM 		}
39411767SAnurag.Maskey@Sun.COM 		i++;
39511767SAnurag.Maskey@Sun.COM 	}
39611767SAnurag.Maskey@Sun.COM 	name[j] = '\0';
39711767SAnurag.Maskey@Sun.COM }
39811767SAnurag.Maskey@Sun.COM 
39911767SAnurag.Maskey@Sun.COM nwam_error_t
nwamd_wlan_set_key(const char * linkname,const char * essid,const char * bssid,uint32_t security_mode,uint_t keyslot,char * raw_key)40011767SAnurag.Maskey@Sun.COM nwamd_wlan_set_key(const char *linkname, const char *essid, const char *bssid,
40111767SAnurag.Maskey@Sun.COM     uint32_t security_mode, uint_t keyslot, char *raw_key)
40211767SAnurag.Maskey@Sun.COM {
40311767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
40411767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
40511767SAnurag.Maskey@Sun.COM 	nwamd_link_t *link;
40611767SAnurag.Maskey@Sun.COM 	uint8_t obj_val[DLADM_SECOBJ_VAL_MAX];
40711767SAnurag.Maskey@Sun.COM 	uint_t obj_len = sizeof (obj_val);
40811767SAnurag.Maskey@Sun.COM 	char obj_name[DLADM_SECOBJ_NAME_MAX];
40911767SAnurag.Maskey@Sun.COM 	dladm_status_t status;
41011767SAnurag.Maskey@Sun.COM 	char errmsg[DLADM_STRSIZE];
41111767SAnurag.Maskey@Sun.COM 	dladm_secobj_class_t class;
41211767SAnurag.Maskey@Sun.COM 
41311767SAnurag.Maskey@Sun.COM 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
41411767SAnurag.Maskey@Sun.COM 	    == NULL) {
41511767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_set_key: could not find object  "
41611767SAnurag.Maskey@Sun.COM 		    "for link %s", linkname);
41711767SAnurag.Maskey@Sun.COM 		return (NWAM_ENTITY_NOT_FOUND);
41811767SAnurag.Maskey@Sun.COM 	}
41911767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
42012576SAnurag.Maskey@Oracle.COM 	link = &ncu->ncu_link;
42111767SAnurag.Maskey@Sun.COM 
42211767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_wlan_set_key: running for link %s", linkname);
42311767SAnurag.Maskey@Sun.COM 	/*
42411767SAnurag.Maskey@Sun.COM 	 * Name key object for this WLAN so it can be later retrieved
42511767SAnurag.Maskey@Sun.COM 	 * (name is unique for each ESSID/BSSID combination).
42611767SAnurag.Maskey@Sun.COM 	 */
42711767SAnurag.Maskey@Sun.COM 	nwamd_set_key_name(essid, bssid, obj_name, sizeof (obj_name));
42811767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "store_key: obj_name is %s", obj_name);
42911767SAnurag.Maskey@Sun.COM 
43011767SAnurag.Maskey@Sun.COM 	class = (security_mode == DLADM_WLAN_SECMODE_WEP ?
43111767SAnurag.Maskey@Sun.COM 	    DLADM_SECOBJ_CLASS_WEP : DLADM_SECOBJ_CLASS_WPA);
43211767SAnurag.Maskey@Sun.COM 	if (key_string_to_secobj_value(raw_key, obj_val, &obj_len,
43311767SAnurag.Maskey@Sun.COM 	    class) != 0) {
43411767SAnurag.Maskey@Sun.COM 		/* above function logs internally on failure */
43511767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
43611767SAnurag.Maskey@Sun.COM 		return (NWAM_ERROR_INTERNAL);
43711767SAnurag.Maskey@Sun.COM 	}
43811767SAnurag.Maskey@Sun.COM 
43911767SAnurag.Maskey@Sun.COM 	/* we've validated the new key, so remove the old one */
44011767SAnurag.Maskey@Sun.COM 	status = dladm_unset_secobj(dld_handle, obj_name,
44111767SAnurag.Maskey@Sun.COM 	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
44211767SAnurag.Maskey@Sun.COM 	if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND) {
44311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "store_key: could not remove old secure object "
44411767SAnurag.Maskey@Sun.COM 		    "'%s' for key: %s", obj_name,
44511767SAnurag.Maskey@Sun.COM 		    dladm_status2str(status, errmsg));
44611767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
44711767SAnurag.Maskey@Sun.COM 		return (NWAM_ERROR_INTERNAL);
44811767SAnurag.Maskey@Sun.COM 	}
44911767SAnurag.Maskey@Sun.COM 
45011767SAnurag.Maskey@Sun.COM 	/* if we're just deleting the key, then we're done */
45111767SAnurag.Maskey@Sun.COM 	if (raw_key[0] == '\0') {
45211767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
45311767SAnurag.Maskey@Sun.COM 		return (NWAM_SUCCESS);
45411767SAnurag.Maskey@Sun.COM 	}
45511767SAnurag.Maskey@Sun.COM 
45611767SAnurag.Maskey@Sun.COM 	status = dladm_set_secobj(dld_handle, obj_name, class,
45711767SAnurag.Maskey@Sun.COM 	    obj_val, obj_len,
45811767SAnurag.Maskey@Sun.COM 	    DLADM_OPT_CREATE | DLADM_OPT_PERSIST | DLADM_OPT_ACTIVE);
45911767SAnurag.Maskey@Sun.COM 	if (status != DLADM_STATUS_OK) {
46011767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "store_key: could not create secure object "
46111767SAnurag.Maskey@Sun.COM 		    "'%s' for key: %s", obj_name,
46211767SAnurag.Maskey@Sun.COM 		    dladm_status2str(status, errmsg));
46311767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
46411767SAnurag.Maskey@Sun.COM 		return (NWAM_ERROR_INTERNAL);
46511767SAnurag.Maskey@Sun.COM 	}
46611767SAnurag.Maskey@Sun.COM 	link->nwamd_link_wifi_key = nwamd_wlan_get_key_named(obj_name,
46711767SAnurag.Maskey@Sun.COM 	    security_mode);
46811767SAnurag.Maskey@Sun.COM 	(void) strlcpy(link->nwamd_link_wifi_keyname, obj_name,
46911767SAnurag.Maskey@Sun.COM 	    sizeof (link->nwamd_link_wifi_keyname));
47011767SAnurag.Maskey@Sun.COM 	link->nwamd_link_wifi_security_mode = security_mode;
47111767SAnurag.Maskey@Sun.COM 	if (security_mode == DLADM_WLAN_SECMODE_WEP) {
47211767SAnurag.Maskey@Sun.COM 		link->nwamd_link_wifi_key->wk_idx =
47311767SAnurag.Maskey@Sun.COM 		    (keyslot >= 1 && keyslot <= 4) ? keyslot : 1;
47411767SAnurag.Maskey@Sun.COM 	}
47511767SAnurag.Maskey@Sun.COM 
47611767SAnurag.Maskey@Sun.COM 	/* If link NCU is offline* or online, (re)connect. */
47711767SAnurag.Maskey@Sun.COM 	switch (ncu_obj->nwamd_object_state) {
47811767SAnurag.Maskey@Sun.COM 	case NWAM_STATE_ONLINE:
47911767SAnurag.Maskey@Sun.COM 		/* if changing the key of the connected WLAN, reconnect */
48011767SAnurag.Maskey@Sun.COM 		if (strcmp(essid, link->nwamd_link_wifi_essid) == 0)
48111767SAnurag.Maskey@Sun.COM 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
48211767SAnurag.Maskey@Sun.COM 			    ncu_obj->nwamd_object_name, NWAM_STATE_ONLINE,
48311767SAnurag.Maskey@Sun.COM 			    NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
48411767SAnurag.Maskey@Sun.COM 		break;
48511767SAnurag.Maskey@Sun.COM 	case NWAM_STATE_OFFLINE_TO_ONLINE:
48611767SAnurag.Maskey@Sun.COM 		/* if we are waiting for the key, connect */
48711767SAnurag.Maskey@Sun.COM 		if (ncu_obj->nwamd_object_aux_state ==
48811767SAnurag.Maskey@Sun.COM 		    NWAM_AUX_STATE_LINK_WIFI_NEED_KEY)
48911767SAnurag.Maskey@Sun.COM 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
49011767SAnurag.Maskey@Sun.COM 			    ncu_obj->nwamd_object_name,
49111767SAnurag.Maskey@Sun.COM 			    NWAM_STATE_OFFLINE_TO_ONLINE,
49211767SAnurag.Maskey@Sun.COM 			    NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
49311767SAnurag.Maskey@Sun.COM 		break;
49411767SAnurag.Maskey@Sun.COM 	default:
49511767SAnurag.Maskey@Sun.COM 		break;
49611767SAnurag.Maskey@Sun.COM 	}
49711767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
49811767SAnurag.Maskey@Sun.COM 
49911767SAnurag.Maskey@Sun.COM 	return (NWAM_SUCCESS);
50011767SAnurag.Maskey@Sun.COM }
50111767SAnurag.Maskey@Sun.COM 
50211767SAnurag.Maskey@Sun.COM /*
50311767SAnurag.Maskey@Sun.COM  * returns NULL if no key was recovered from libdladm.  Passing in
50411767SAnurag.Maskey@Sun.COM  * security mode of 0 means we don't care what key type it is.
50511767SAnurag.Maskey@Sun.COM  */
50611767SAnurag.Maskey@Sun.COM dladm_wlan_key_t *
nwamd_wlan_get_key_named(const char * name,uint32_t security_mode)50711767SAnurag.Maskey@Sun.COM nwamd_wlan_get_key_named(const char *name, uint32_t security_mode)
50811767SAnurag.Maskey@Sun.COM {
50911767SAnurag.Maskey@Sun.COM 	dladm_status_t status;
51011767SAnurag.Maskey@Sun.COM 	char errmsg[DLADM_STRSIZE];
51111767SAnurag.Maskey@Sun.COM 	dladm_wlan_key_t *cooked_key;
51211767SAnurag.Maskey@Sun.COM 	dladm_secobj_class_t class;
51311767SAnurag.Maskey@Sun.COM 
51411767SAnurag.Maskey@Sun.COM 	if (security_mode == DLADM_WLAN_SECMODE_NONE)
51511767SAnurag.Maskey@Sun.COM 		return (NULL);
51611767SAnurag.Maskey@Sun.COM 
51711767SAnurag.Maskey@Sun.COM 	/*
51811767SAnurag.Maskey@Sun.COM 	 * Newly-allocated key must be freed by caller, or by
51911767SAnurag.Maskey@Sun.COM 	 * subsequent call to nwamd_wlan_get_key_named().
52011767SAnurag.Maskey@Sun.COM 	 */
52111767SAnurag.Maskey@Sun.COM 	if ((cooked_key = malloc(sizeof (dladm_wlan_key_t))) == NULL) {
52211767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_get_key_named: malloc failed");
52311767SAnurag.Maskey@Sun.COM 		return (NULL);
52411767SAnurag.Maskey@Sun.COM 	}
52511767SAnurag.Maskey@Sun.COM 
52611767SAnurag.Maskey@Sun.COM 	/*
52711767SAnurag.Maskey@Sun.COM 	 * Set name appropriately to retrieve key for this WLAN.  Note that we
52811767SAnurag.Maskey@Sun.COM 	 * cannot use the actual wk_name buffer size, as it's two times too
52911767SAnurag.Maskey@Sun.COM 	 * large for dladm_get_secobj.
53011767SAnurag.Maskey@Sun.COM 	 */
53111767SAnurag.Maskey@Sun.COM 	(void) strlcpy(cooked_key->wk_name, name, DLADM_SECOBJ_NAME_MAX);
53211767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: len = %d, object = %s\n",
53311767SAnurag.Maskey@Sun.COM 	    strlen(cooked_key->wk_name), cooked_key->wk_name);
53411767SAnurag.Maskey@Sun.COM 	cooked_key->wk_len = sizeof (cooked_key->wk_val);
53511767SAnurag.Maskey@Sun.COM 	cooked_key->wk_idx = 1;
53611767SAnurag.Maskey@Sun.COM 
53711767SAnurag.Maskey@Sun.COM 	/* Try the kernel first, then fall back to persistent storage. */
53811767SAnurag.Maskey@Sun.COM 	status = dladm_get_secobj(dld_handle, cooked_key->wk_name, &class,
53911767SAnurag.Maskey@Sun.COM 	    cooked_key->wk_val, &cooked_key->wk_len,
54011767SAnurag.Maskey@Sun.COM 	    DLADM_OPT_ACTIVE);
54111767SAnurag.Maskey@Sun.COM 	if (status != DLADM_STATUS_OK) {
54211767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: "
54311767SAnurag.Maskey@Sun.COM 		    "dladm_get_secobj(TEMP) failed: %s",
54411767SAnurag.Maskey@Sun.COM 		    dladm_status2str(status, errmsg));
54511767SAnurag.Maskey@Sun.COM 		status = dladm_get_secobj(dld_handle, cooked_key->wk_name,
54611767SAnurag.Maskey@Sun.COM 		    &class, cooked_key->wk_val, &cooked_key->wk_len,
54711767SAnurag.Maskey@Sun.COM 		    DLADM_OPT_PERSIST);
54811767SAnurag.Maskey@Sun.COM 	}
54911767SAnurag.Maskey@Sun.COM 
55011767SAnurag.Maskey@Sun.COM 	switch (status) {
55111767SAnurag.Maskey@Sun.COM 	case DLADM_STATUS_OK:
55211767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: "
55311767SAnurag.Maskey@Sun.COM 		    "dladm_get_secobj succeeded: len %d", cooked_key->wk_len);
55411767SAnurag.Maskey@Sun.COM 		break;
55511767SAnurag.Maskey@Sun.COM 	case DLADM_STATUS_NOTFOUND:
55611767SAnurag.Maskey@Sun.COM 		/*
55711767SAnurag.Maskey@Sun.COM 		 * We do not want an error in the case that the secobj
55811767SAnurag.Maskey@Sun.COM 		 * is not found, since we then prompt for it.
55911767SAnurag.Maskey@Sun.COM 		 */
56011767SAnurag.Maskey@Sun.COM 		free(cooked_key);
56111767SAnurag.Maskey@Sun.COM 		return (NULL);
56211767SAnurag.Maskey@Sun.COM 	default:
56311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_get_key_named: could not get key "
56411767SAnurag.Maskey@Sun.COM 		    "from secure object '%s': %s", cooked_key->wk_name,
56511767SAnurag.Maskey@Sun.COM 		    dladm_status2str(status, errmsg));
56611767SAnurag.Maskey@Sun.COM 		free(cooked_key);
56711767SAnurag.Maskey@Sun.COM 		return (NULL);
56811767SAnurag.Maskey@Sun.COM 	}
56911767SAnurag.Maskey@Sun.COM 
57011767SAnurag.Maskey@Sun.COM 	if (security_mode != 0) {
57111767SAnurag.Maskey@Sun.COM 		switch (class) {
57211767SAnurag.Maskey@Sun.COM 		case DLADM_SECOBJ_CLASS_WEP:
57311767SAnurag.Maskey@Sun.COM 			if (security_mode == DLADM_WLAN_SECMODE_WEP)
57411767SAnurag.Maskey@Sun.COM 				return (cooked_key);
57511767SAnurag.Maskey@Sun.COM 			break;
57611767SAnurag.Maskey@Sun.COM 		case DLADM_SECOBJ_CLASS_WPA:
57711767SAnurag.Maskey@Sun.COM 			if (security_mode == DLADM_WLAN_SECMODE_WPA)
57811767SAnurag.Maskey@Sun.COM 				return (cooked_key);
57911767SAnurag.Maskey@Sun.COM 			break;
58011767SAnurag.Maskey@Sun.COM 		default:
58111767SAnurag.Maskey@Sun.COM 			/* shouldn't happen */
58211767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_wlan_get_key: invalid class %d",
58311767SAnurag.Maskey@Sun.COM 			    class);
58411767SAnurag.Maskey@Sun.COM 			break;
58511767SAnurag.Maskey@Sun.COM 		}
58611767SAnurag.Maskey@Sun.COM 		/* key type mismatch */
58711767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_get_key: key type mismatch"
58811767SAnurag.Maskey@Sun.COM 		    " from secure object '%s'", cooked_key->wk_name);
58911767SAnurag.Maskey@Sun.COM 		free(cooked_key);
59011767SAnurag.Maskey@Sun.COM 		return (NULL);
59111767SAnurag.Maskey@Sun.COM 	}
59211767SAnurag.Maskey@Sun.COM 
59311767SAnurag.Maskey@Sun.COM 	return (cooked_key);
59411767SAnurag.Maskey@Sun.COM }
59511767SAnurag.Maskey@Sun.COM 
59611767SAnurag.Maskey@Sun.COM static dladm_wlan_key_t *
nwamd_wlan_get_key(const char * essid,const char * bssid,uint32_t security_mode)59711767SAnurag.Maskey@Sun.COM nwamd_wlan_get_key(const char *essid, const char *bssid, uint32_t security_mode)
59811767SAnurag.Maskey@Sun.COM {
59911767SAnurag.Maskey@Sun.COM 	char keyname[DLADM_SECOBJ_NAME_MAX];
60011767SAnurag.Maskey@Sun.COM 
60111767SAnurag.Maskey@Sun.COM 	nwamd_set_key_name(essid, bssid, keyname, DLADM_SECOBJ_NAME_MAX);
60211767SAnurag.Maskey@Sun.COM 
60311767SAnurag.Maskey@Sun.COM 	return (nwamd_wlan_get_key_named(keyname, security_mode));
60411767SAnurag.Maskey@Sun.COM }
60511767SAnurag.Maskey@Sun.COM 
60611767SAnurag.Maskey@Sun.COM /*
60711767SAnurag.Maskey@Sun.COM  * Checks if a wireless network can be selected or not.  A wireless network
60811767SAnurag.Maskey@Sun.COM  * CANNOT be selected if the NCU is DISABLED, or the NCU is OFFLINE or
60911767SAnurag.Maskey@Sun.COM  * ONLINE* and has lower priority than the currently active priority-group.
61011767SAnurag.Maskey@Sun.COM  * Called with object lock held.
61111767SAnurag.Maskey@Sun.COM  */
61211767SAnurag.Maskey@Sun.COM static boolean_t
wireless_selection_possible(nwamd_object_t object)61311767SAnurag.Maskey@Sun.COM wireless_selection_possible(nwamd_object_t object)
61411767SAnurag.Maskey@Sun.COM {
61511767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu = object->nwamd_object_data;
61611767SAnurag.Maskey@Sun.COM 
61712576SAnurag.Maskey@Oracle.COM 	if (ncu->ncu_link.nwamd_link_media != DL_WIFI)
61811767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
61911767SAnurag.Maskey@Sun.COM 
62011767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&active_ncp_mutex);
62111767SAnurag.Maskey@Sun.COM 	if (object->nwamd_object_state == NWAM_STATE_DISABLED ||
62211767SAnurag.Maskey@Sun.COM 	    ((object->nwamd_object_state == NWAM_STATE_OFFLINE ||
62311767SAnurag.Maskey@Sun.COM 	    object->nwamd_object_state == NWAM_STATE_ONLINE_TO_OFFLINE) &&
62412576SAnurag.Maskey@Oracle.COM 	    ncu->ncu_link.nwamd_link_activation_mode ==
62511767SAnurag.Maskey@Sun.COM 	    NWAM_ACTIVATION_MODE_PRIORITIZED &&
62611767SAnurag.Maskey@Sun.COM 	    (current_ncu_priority_group == INVALID_PRIORITY_GROUP ||
62712576SAnurag.Maskey@Oracle.COM 	    ncu->ncu_link.nwamd_link_priority_group >
62811767SAnurag.Maskey@Sun.COM 	    current_ncu_priority_group))) {
62911767SAnurag.Maskey@Sun.COM 		(void) pthread_mutex_unlock(&active_ncp_mutex);
63011767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
63111767SAnurag.Maskey@Sun.COM 	}
63211767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&active_ncp_mutex);
63311767SAnurag.Maskey@Sun.COM 
63411767SAnurag.Maskey@Sun.COM 	return (B_TRUE);
63511767SAnurag.Maskey@Sun.COM }
63611767SAnurag.Maskey@Sun.COM 
63711767SAnurag.Maskey@Sun.COM /*
63811767SAnurag.Maskey@Sun.COM  * Update the selected and/or connected values for the
63911767SAnurag.Maskey@Sun.COM  * scan data.  If these change, we need to trigger a scan
64011767SAnurag.Maskey@Sun.COM  * event since the updated values need to be communicated
64111767SAnurag.Maskey@Sun.COM  * to the GUI.
64211767SAnurag.Maskey@Sun.COM  */
64311767SAnurag.Maskey@Sun.COM void
nwamd_set_selected_connected(nwamd_ncu_t * ncu,boolean_t selected,boolean_t connected)64411767SAnurag.Maskey@Sun.COM nwamd_set_selected_connected(nwamd_ncu_t *ncu, boolean_t selected,
64511767SAnurag.Maskey@Sun.COM     boolean_t connected)
64611767SAnurag.Maskey@Sun.COM {
64712576SAnurag.Maskey@Oracle.COM 	nwamd_link_t *link = &ncu->ncu_link;
64811767SAnurag.Maskey@Sun.COM 	nwamd_wifi_scan_t *s = &link->nwamd_link_wifi_scan;
64911767SAnurag.Maskey@Sun.COM 	int i;
65011767SAnurag.Maskey@Sun.COM 	boolean_t trigger_scan_event = B_FALSE;
65111767SAnurag.Maskey@Sun.COM 
65211767SAnurag.Maskey@Sun.COM 	for (i = 0; i < s->nwamd_wifi_scan_curr_num; i++) {
65311767SAnurag.Maskey@Sun.COM 		if (strcmp(s->nwamd_wifi_scan_curr[i].nww_essid,
65411767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_essid) != 0 ||
65511767SAnurag.Maskey@Sun.COM 		    (link->nwamd_link_wifi_bssid[0] != '\0' &&
65611767SAnurag.Maskey@Sun.COM 		    strcmp(s->nwamd_wifi_scan_curr[i].nww_bssid,
65711767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_bssid) != 0))
65811767SAnurag.Maskey@Sun.COM 			continue;
65911767SAnurag.Maskey@Sun.COM 		if (selected) {
66011767SAnurag.Maskey@Sun.COM 			if (!s->nwamd_wifi_scan_curr[i].nww_selected)
66111767SAnurag.Maskey@Sun.COM 				trigger_scan_event = B_TRUE;
66211767SAnurag.Maskey@Sun.COM 			s->nwamd_wifi_scan_curr[i].nww_selected = B_TRUE;
66311767SAnurag.Maskey@Sun.COM 		} else {
66411767SAnurag.Maskey@Sun.COM 			if (s->nwamd_wifi_scan_curr[i].nww_selected)
66511767SAnurag.Maskey@Sun.COM 				trigger_scan_event = B_TRUE;
66611767SAnurag.Maskey@Sun.COM 			s->nwamd_wifi_scan_curr[i].nww_selected = B_FALSE;
66711767SAnurag.Maskey@Sun.COM 		}
66811767SAnurag.Maskey@Sun.COM 		if (connected) {
66911767SAnurag.Maskey@Sun.COM 			if (!s->nwamd_wifi_scan_curr[i].nww_connected)
67011767SAnurag.Maskey@Sun.COM 				trigger_scan_event = B_TRUE;
67111767SAnurag.Maskey@Sun.COM 			s->nwamd_wifi_scan_curr[i].nww_connected = B_TRUE;
67211767SAnurag.Maskey@Sun.COM 		} else {
67311767SAnurag.Maskey@Sun.COM 			if (s->nwamd_wifi_scan_curr[i].nww_connected)
67411767SAnurag.Maskey@Sun.COM 				trigger_scan_event = B_TRUE;
67511767SAnurag.Maskey@Sun.COM 			s->nwamd_wifi_scan_curr[i].nww_connected = B_FALSE;
67611767SAnurag.Maskey@Sun.COM 		}
67711767SAnurag.Maskey@Sun.COM 	}
67811767SAnurag.Maskey@Sun.COM 
67911767SAnurag.Maskey@Sun.COM 	if (trigger_scan_event || s->nwamd_wifi_scan_changed) {
68011767SAnurag.Maskey@Sun.COM 		nwamd_event_t scan_event = nwamd_event_init_wlan
68111767SAnurag.Maskey@Sun.COM 		    (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_SCAN_REPORT, connected,
68211767SAnurag.Maskey@Sun.COM 		    s->nwamd_wifi_scan_curr, s->nwamd_wifi_scan_curr_num);
68311767SAnurag.Maskey@Sun.COM 		if (scan_event != NULL) {
68411767SAnurag.Maskey@Sun.COM 			/* Avoid sending same scan data multiple times */
68511767SAnurag.Maskey@Sun.COM 			s->nwamd_wifi_scan_changed = B_FALSE;
68611767SAnurag.Maskey@Sun.COM 			nwamd_event_enqueue(scan_event);
68711767SAnurag.Maskey@Sun.COM 		}
68811767SAnurag.Maskey@Sun.COM 	}
68911767SAnurag.Maskey@Sun.COM }
69011767SAnurag.Maskey@Sun.COM 
69112145SAnurag.Maskey@Sun.COM /*
69212145SAnurag.Maskey@Sun.COM  * Callback used on each known WLAN - if the BSSID is matched, set
69312145SAnurag.Maskey@Sun.COM  * the ESSID of the hidden WLAN to the known WLAN name.
69412145SAnurag.Maskey@Sun.COM  */
69512145SAnurag.Maskey@Sun.COM static int
find_bssid_cb(nwam_known_wlan_handle_t kwh,void * data)69612145SAnurag.Maskey@Sun.COM find_bssid_cb(nwam_known_wlan_handle_t kwh, void *data)
69712145SAnurag.Maskey@Sun.COM {
69812145SAnurag.Maskey@Sun.COM 	nwamd_link_t *link = data;
69912145SAnurag.Maskey@Sun.COM 	nwam_error_t err;
70012145SAnurag.Maskey@Sun.COM 	nwam_value_t bssidval;
70112145SAnurag.Maskey@Sun.COM 	char **bssids, *name;
70212145SAnurag.Maskey@Sun.COM 	uint_t num_bssids, i;
70312145SAnurag.Maskey@Sun.COM 
70412145SAnurag.Maskey@Sun.COM 	if ((err = nwam_known_wlan_get_prop_value(kwh,
70512145SAnurag.Maskey@Sun.COM 	    NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidval)) != NWAM_SUCCESS) {
70612145SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "find_bssid_cb: nwam_known_wlan_get_prop: %s",
70712145SAnurag.Maskey@Sun.COM 		    nwam_strerror(err));
70812145SAnurag.Maskey@Sun.COM 		return (0);
70912145SAnurag.Maskey@Sun.COM 	}
71012145SAnurag.Maskey@Sun.COM 	if ((err = nwam_value_get_string_array(bssidval, &bssids, &num_bssids))
71112145SAnurag.Maskey@Sun.COM 	    != NWAM_SUCCESS) {
71212145SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "find_bssid_cb: nwam_value_get_string_array: %s",
71312145SAnurag.Maskey@Sun.COM 		    nwam_strerror(err));
71412145SAnurag.Maskey@Sun.COM 		nwam_value_free(bssidval);
71512145SAnurag.Maskey@Sun.COM 		return (0);
71612145SAnurag.Maskey@Sun.COM 	}
71712145SAnurag.Maskey@Sun.COM 	for (i = 0; i < num_bssids; i++) {
71812145SAnurag.Maskey@Sun.COM 		if (strcmp(bssids[i], link->nwamd_link_wifi_bssid) == 0) {
71912145SAnurag.Maskey@Sun.COM 			if ((err = nwam_known_wlan_get_name(kwh, &name))
72012145SAnurag.Maskey@Sun.COM 			    != NWAM_SUCCESS) {
72112145SAnurag.Maskey@Sun.COM 				nlog(LOG_ERR, "find_bssid_cb: "
72212145SAnurag.Maskey@Sun.COM 				    "nwam_known_wlan_get_name: %s",
72312145SAnurag.Maskey@Sun.COM 				    nwam_strerror(err));
72412145SAnurag.Maskey@Sun.COM 				continue;
72512145SAnurag.Maskey@Sun.COM 			}
72612145SAnurag.Maskey@Sun.COM 			(void) strlcpy(link->nwamd_link_wifi_essid, name,
72712145SAnurag.Maskey@Sun.COM 			    sizeof (link->nwamd_link_wifi_essid));
72812145SAnurag.Maskey@Sun.COM 			free(name);
72912145SAnurag.Maskey@Sun.COM 			nwam_value_free(bssidval);
73012145SAnurag.Maskey@Sun.COM 			/* Found ESSID for BSSID so terminate walk */
73112145SAnurag.Maskey@Sun.COM 			return (1);
73212145SAnurag.Maskey@Sun.COM 		}
73312145SAnurag.Maskey@Sun.COM 	}
73412145SAnurag.Maskey@Sun.COM 	nwam_value_free(bssidval);
73512145SAnurag.Maskey@Sun.COM 
73612145SAnurag.Maskey@Sun.COM 	return (0);
73712145SAnurag.Maskey@Sun.COM }
73812145SAnurag.Maskey@Sun.COM 
73912145SAnurag.Maskey@Sun.COM /*
74012145SAnurag.Maskey@Sun.COM  * We may have encountered a BSSID for a hidden WLAN before and as a result
74112145SAnurag.Maskey@Sun.COM  * may have a known WLAN entry with this BSSID.  Walk known WLANs, searching
74212145SAnurag.Maskey@Sun.COM  * for a BSSID match.  Called with object lock held.
74312145SAnurag.Maskey@Sun.COM  */
74412145SAnurag.Maskey@Sun.COM static void
check_if_hidden_wlan_was_visited(nwamd_link_t * link)74512145SAnurag.Maskey@Sun.COM check_if_hidden_wlan_was_visited(nwamd_link_t *link)
74612145SAnurag.Maskey@Sun.COM {
74712145SAnurag.Maskey@Sun.COM 	(void) nwam_walk_known_wlans(find_bssid_cb, link,
74812145SAnurag.Maskey@Sun.COM 	    NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, NULL);
74912145SAnurag.Maskey@Sun.COM }
75012145SAnurag.Maskey@Sun.COM 
75111767SAnurag.Maskey@Sun.COM nwam_error_t
nwamd_wlan_select(const char * linkname,const char * essid,const char * bssid,uint32_t security_mode,boolean_t add_to_known_wlans)75211767SAnurag.Maskey@Sun.COM nwamd_wlan_select(const char *linkname, const char *essid, const char *bssid,
75311767SAnurag.Maskey@Sun.COM     uint32_t security_mode, boolean_t add_to_known_wlans)
75411767SAnurag.Maskey@Sun.COM {
75511767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
75611767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
75711767SAnurag.Maskey@Sun.COM 	nwamd_link_t *link;
75811767SAnurag.Maskey@Sun.COM 	char key[DLADM_STRSIZE];
75911767SAnurag.Maskey@Sun.COM 	boolean_t found_old_key = B_FALSE, found_key = B_FALSE;
76011767SAnurag.Maskey@Sun.COM 
76111767SAnurag.Maskey@Sun.COM 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
76211767SAnurag.Maskey@Sun.COM 	    == NULL) {
76311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_select: could not find object  "
76411767SAnurag.Maskey@Sun.COM 		    "for link %s", linkname);
76511767SAnurag.Maskey@Sun.COM 		return (NWAM_ENTITY_NOT_FOUND);
76611767SAnurag.Maskey@Sun.COM 	}
76711767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
76812576SAnurag.Maskey@Oracle.COM 	link = &ncu->ncu_link;
76911767SAnurag.Maskey@Sun.COM 
77011767SAnurag.Maskey@Sun.COM 	/*
77111767SAnurag.Maskey@Sun.COM 	 * If wireless selection is not possible because of the current
77211767SAnurag.Maskey@Sun.COM 	 * state or priority-group, then stop.
77311767SAnurag.Maskey@Sun.COM 	 */
77411767SAnurag.Maskey@Sun.COM 	if (!wireless_selection_possible(ncu_obj)) {
77511767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
77611767SAnurag.Maskey@Sun.COM 		return (NWAM_ENTITY_INVALID_STATE);
77711767SAnurag.Maskey@Sun.COM 	}
77811767SAnurag.Maskey@Sun.COM 
77911767SAnurag.Maskey@Sun.COM 	/* unset selected, connected flag for previously connected wlan */
78011767SAnurag.Maskey@Sun.COM 	nwamd_set_selected_connected(ncu, B_FALSE, B_FALSE);
78111767SAnurag.Maskey@Sun.COM 
78212145SAnurag.Maskey@Sun.COM 	/* Disconnect to allow new selection to go ahead */
78312145SAnurag.Maskey@Sun.COM 	(void) dladm_wlan_disconnect(dld_handle, link->nwamd_link_id);
78412145SAnurag.Maskey@Sun.COM 
78511767SAnurag.Maskey@Sun.COM 	(void) strlcpy(link->nwamd_link_wifi_essid, essid,
78611767SAnurag.Maskey@Sun.COM 	    sizeof (link->nwamd_link_wifi_essid));
78711767SAnurag.Maskey@Sun.COM 	(void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
78811767SAnurag.Maskey@Sun.COM 	    sizeof (link->nwamd_link_wifi_bssid));
78911767SAnurag.Maskey@Sun.COM 	link->nwamd_link_wifi_security_mode = security_mode;
79011767SAnurag.Maskey@Sun.COM 	link->nwamd_link_wifi_add_to_known_wlans = add_to_known_wlans;
79111767SAnurag.Maskey@Sun.COM 
79212145SAnurag.Maskey@Sun.COM 	/* If this is a hidden wlan, then essid is empty */
79312145SAnurag.Maskey@Sun.COM 	if (link->nwamd_link_wifi_essid[0] == '\0')
79412145SAnurag.Maskey@Sun.COM 		check_if_hidden_wlan_was_visited(link);
79511767SAnurag.Maskey@Sun.COM 
79611767SAnurag.Maskey@Sun.COM 	/* set selected flag for newly-selected WLAN */
79711767SAnurag.Maskey@Sun.COM 	nwamd_set_selected_connected(ncu, B_TRUE, B_FALSE);
79811767SAnurag.Maskey@Sun.COM 
79911767SAnurag.Maskey@Sun.COM 	/* does this WLAN require a key? If so go to NEED_KEY */
80011767SAnurag.Maskey@Sun.COM 	if (NEED_ENC(link->nwamd_link_wifi_security_mode)) {
80111767SAnurag.Maskey@Sun.COM 		/*
80211767SAnurag.Maskey@Sun.COM 		 * First, if a key name may have been specified for a
80311767SAnurag.Maskey@Sun.COM 		 * known WLAN.  If so, use it.  Otherwise, try both the
80411767SAnurag.Maskey@Sun.COM 		 * new nwamd key name format (ESSID) and old (ESSID/BSSID).
80511767SAnurag.Maskey@Sun.COM 		 * The user may have set the key without adding a known WLAN,
80611767SAnurag.Maskey@Sun.COM 		 * so we need to try all these options to save going to
80711767SAnurag.Maskey@Sun.COM 		 * NEED_KEY state.
80811767SAnurag.Maskey@Sun.COM 		 */
80911767SAnurag.Maskey@Sun.COM 		if (known_wlan_get_keyname(link->nwamd_link_wifi_essid,
81011767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_keyname) == NWAM_SUCCESS &&
81111767SAnurag.Maskey@Sun.COM 		    (link->nwamd_link_wifi_key = nwamd_wlan_get_key_named
81211767SAnurag.Maskey@Sun.COM 		    (link->nwamd_link_wifi_keyname,
81311767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_security_mode)) != NULL) {
81411767SAnurag.Maskey@Sun.COM 			(void) known_wlan_get_keyslot
81511767SAnurag.Maskey@Sun.COM 			    (link->nwamd_link_wifi_essid,
81611767SAnurag.Maskey@Sun.COM 			    &link->nwamd_link_wifi_key->wk_idx);
81711767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_wlan_select: got known WLAN "
81811767SAnurag.Maskey@Sun.COM 			    "key %s, slot %d", link->nwamd_link_wifi_keyname,
81911767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_key->wk_idx);
82011767SAnurag.Maskey@Sun.COM 			found_key = B_TRUE;
82111767SAnurag.Maskey@Sun.COM 		} else if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
82211767SAnurag.Maskey@Sun.COM 		    (link->nwamd_link_wifi_essid, NULL,
82311767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_security_mode)) != NULL) {
82411767SAnurag.Maskey@Sun.COM 			nwamd_set_key_name(link->nwamd_link_wifi_essid, NULL,
82511767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_keyname,
82611767SAnurag.Maskey@Sun.COM 			    DLADM_SECOBJ_NAME_MAX);
82711767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_wlan_select: got WLAN key %s",
82811767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_keyname);
82911767SAnurag.Maskey@Sun.COM 			found_key = B_TRUE;
83011767SAnurag.Maskey@Sun.COM 		} else if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
83111767SAnurag.Maskey@Sun.COM 		    (link->nwamd_link_wifi_essid, link->nwamd_link_wifi_bssid,
83211767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_security_mode)) != NULL) {
83311767SAnurag.Maskey@Sun.COM 			/*
83411767SAnurag.Maskey@Sun.COM 			 * Found old key format - prepare to save
83511767SAnurag.Maskey@Sun.COM 			 * it as new ESSID-only key, but don't
83611767SAnurag.Maskey@Sun.COM 			 * do it until we're released the object
83711767SAnurag.Maskey@Sun.COM 			 * lock (since nwamd_wlan_set_key()
83811767SAnurag.Maskey@Sun.COM 			 * takes the object lock).
83911767SAnurag.Maskey@Sun.COM 			 */
84011767SAnurag.Maskey@Sun.COM 			(void) strlcpy(key,
84111767SAnurag.Maskey@Sun.COM 			    (char *)link->nwamd_link_wifi_key->wk_val,
84211767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_key->wk_len + 1);
84311767SAnurag.Maskey@Sun.COM 			found_old_key = B_TRUE;
84411767SAnurag.Maskey@Sun.COM 			found_key = B_TRUE;
84511767SAnurag.Maskey@Sun.COM 			nwamd_set_key_name(link->nwamd_link_wifi_essid, NULL,
84611767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_keyname,
84711767SAnurag.Maskey@Sun.COM 			    DLADM_SECOBJ_NAME_MAX);
84811767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_wlan_select: got old format "
84911767SAnurag.Maskey@Sun.COM 			    "WLAN key, converting to %s",
85011767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_keyname);
85111767SAnurag.Maskey@Sun.COM 		} else {
85211767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_wlan_select: could not "
85311767SAnurag.Maskey@Sun.COM 			    "find key for WLAN '%s'",
85411767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_essid);
85511767SAnurag.Maskey@Sun.COM 		}
85611767SAnurag.Maskey@Sun.COM 	} else {
85711767SAnurag.Maskey@Sun.COM 		free(link->nwamd_link_wifi_key);
85811767SAnurag.Maskey@Sun.COM 		link->nwamd_link_wifi_key = NULL;
85911767SAnurag.Maskey@Sun.COM 		link->nwamd_link_wifi_keyname[0] = '\0';
86011767SAnurag.Maskey@Sun.COM 	}
86111767SAnurag.Maskey@Sun.COM 
86211767SAnurag.Maskey@Sun.COM 	if (NEED_ENC(link->nwamd_link_wifi_security_mode) && !found_key) {
86311767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
86411767SAnurag.Maskey@Sun.COM 		    ncu_obj->nwamd_object_name,
86511767SAnurag.Maskey@Sun.COM 		    NWAM_STATE_OFFLINE_TO_ONLINE,
86611767SAnurag.Maskey@Sun.COM 		    NWAM_AUX_STATE_LINK_WIFI_NEED_KEY);
86711767SAnurag.Maskey@Sun.COM 	} else {
86811767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
86911767SAnurag.Maskey@Sun.COM 		    ncu_obj->nwamd_object_name, NWAM_STATE_OFFLINE_TO_ONLINE,
87011767SAnurag.Maskey@Sun.COM 		    NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
87111767SAnurag.Maskey@Sun.COM 	}
87211767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
87311767SAnurag.Maskey@Sun.COM 
87411767SAnurag.Maskey@Sun.COM 	if (found_old_key) {
87511767SAnurag.Maskey@Sun.COM 		(void) nwamd_wlan_set_key(linkname, essid, NULL, security_mode,
87611767SAnurag.Maskey@Sun.COM 		    1, key);
87711767SAnurag.Maskey@Sun.COM 	}
87811767SAnurag.Maskey@Sun.COM 	return (NWAM_SUCCESS);
87911767SAnurag.Maskey@Sun.COM }
88011767SAnurag.Maskey@Sun.COM 
88111767SAnurag.Maskey@Sun.COM /*
88211767SAnurag.Maskey@Sun.COM  * See if BSSID is in visited list of BSSIDs for known WLAN. Used for
88311767SAnurag.Maskey@Sun.COM  * strict BSSID matching (depends on wireless_strict_bssid property value).
88411767SAnurag.Maskey@Sun.COM  */
88511767SAnurag.Maskey@Sun.COM static boolean_t
bssid_match(nwam_known_wlan_handle_t kwh,const char * bssid)88611767SAnurag.Maskey@Sun.COM bssid_match(nwam_known_wlan_handle_t kwh, const char *bssid)
88711767SAnurag.Maskey@Sun.COM {
88811767SAnurag.Maskey@Sun.COM 	nwam_value_t bssidsval;
88911767SAnurag.Maskey@Sun.COM 	nwam_error_t err;
89011767SAnurag.Maskey@Sun.COM 	char **bssids;
89111767SAnurag.Maskey@Sun.COM 	uint_t nelem, i;
89211767SAnurag.Maskey@Sun.COM 	boolean_t found = B_FALSE;
89311767SAnurag.Maskey@Sun.COM 
89411767SAnurag.Maskey@Sun.COM 	if ((err = nwam_known_wlan_get_prop_value(kwh,
89511767SAnurag.Maskey@Sun.COM 	    NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidsval)) != NWAM_SUCCESS) {
89611767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "bssid_match: %s", nwam_strerror(err));
89711767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
89811767SAnurag.Maskey@Sun.COM 	}
89911767SAnurag.Maskey@Sun.COM 	if ((err = nwam_value_get_string_array(bssidsval, &bssids, &nelem))
90011767SAnurag.Maskey@Sun.COM 	    != NWAM_SUCCESS) {
90111767SAnurag.Maskey@Sun.COM 		nwam_value_free(bssidsval);
90211767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
90311767SAnurag.Maskey@Sun.COM 	}
90411767SAnurag.Maskey@Sun.COM 	for (i = 0; i < nelem; i++) {
90511767SAnurag.Maskey@Sun.COM 		if (strcmp(bssid, bssids[i]) == 0) {
90611767SAnurag.Maskey@Sun.COM 			found = B_TRUE;
90711767SAnurag.Maskey@Sun.COM 			break;
90811767SAnurag.Maskey@Sun.COM 		}
90911767SAnurag.Maskey@Sun.COM 	}
91011767SAnurag.Maskey@Sun.COM 	nwam_value_free(bssidsval);
91111767SAnurag.Maskey@Sun.COM 
91211767SAnurag.Maskey@Sun.COM 	return (found);
91311767SAnurag.Maskey@Sun.COM }
91411767SAnurag.Maskey@Sun.COM 
91511767SAnurag.Maskey@Sun.COM /* Find most prioritized AP with strongest signal in scan data. */
91611767SAnurag.Maskey@Sun.COM static int
find_best_wlan_cb(nwam_known_wlan_handle_t kwh,void * data)91711767SAnurag.Maskey@Sun.COM find_best_wlan_cb(nwam_known_wlan_handle_t kwh, void *data)
91811767SAnurag.Maskey@Sun.COM {
91911767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu = data;
92012576SAnurag.Maskey@Oracle.COM 	nwamd_link_t *link = &ncu->ncu_link;
92111767SAnurag.Maskey@Sun.COM 	nwamd_wifi_scan_t *s = &link->nwamd_link_wifi_scan;
92211767SAnurag.Maskey@Sun.COM 	nwam_error_t err;
92311767SAnurag.Maskey@Sun.COM 	char *name = NULL;
92411767SAnurag.Maskey@Sun.COM 	int i;
92511767SAnurag.Maskey@Sun.COM 	dladm_wlan_strength_t curr_strength = 0;
92611767SAnurag.Maskey@Sun.COM 	dladm_wlan_strength_t max_strength = 0;
92711767SAnurag.Maskey@Sun.COM 	boolean_t found = B_FALSE;
92811767SAnurag.Maskey@Sun.COM 
92911767SAnurag.Maskey@Sun.COM 	if ((err = nwam_known_wlan_get_name(kwh, &name)) != NWAM_SUCCESS) {
93011767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "find_best_wlan_cb: could not look up name: %s",
93111767SAnurag.Maskey@Sun.COM 		    nwam_strerror(err));
93211767SAnurag.Maskey@Sun.COM 		return (0);
93311767SAnurag.Maskey@Sun.COM 	}
93411767SAnurag.Maskey@Sun.COM 
93511767SAnurag.Maskey@Sun.COM 	if (link->nwamd_link_wifi_connected) {
93611767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_str2strength
93711767SAnurag.Maskey@Sun.COM 		    (link->nwamd_link_wifi_signal_strength, &curr_strength);
93811767SAnurag.Maskey@Sun.COM 	}
93911767SAnurag.Maskey@Sun.COM 
94011767SAnurag.Maskey@Sun.COM 	/*
94111767SAnurag.Maskey@Sun.COM 	 * If we're >= scan level, don't pick another Known WLAN if still
94211767SAnurag.Maskey@Sun.COM 	 * connected (even if a Known WLAN with higher priority is available).
94311767SAnurag.Maskey@Sun.COM 	 * If the user wants to connect to a different Known WLAN, it can be
94411767SAnurag.Maskey@Sun.COM 	 * done from the GUI or select-wifi subcommand of nwamadm(1M).
94511767SAnurag.Maskey@Sun.COM 	 */
94611767SAnurag.Maskey@Sun.COM 	if (curr_strength >= wireless_scan_level &&
94711767SAnurag.Maskey@Sun.COM 	    link->nwamd_link_wifi_connected) {
94811767SAnurag.Maskey@Sun.COM 		free(name);
94911767SAnurag.Maskey@Sun.COM 		return (1);
95011767SAnurag.Maskey@Sun.COM 	}
95111767SAnurag.Maskey@Sun.COM 
95211767SAnurag.Maskey@Sun.COM 	for (i = 0; i < s->nwamd_wifi_scan_curr_num; i++) {
95311767SAnurag.Maskey@Sun.COM 		nwam_wlan_t *cur_wlan = &(s->nwamd_wifi_scan_curr[i]);
95411767SAnurag.Maskey@Sun.COM 		boolean_t b_match = bssid_match(kwh, cur_wlan->nww_bssid);
95511767SAnurag.Maskey@Sun.COM 
95611767SAnurag.Maskey@Sun.COM 		/*
95711767SAnurag.Maskey@Sun.COM 		 * We need to either match the scanned essid, or in the case
95811767SAnurag.Maskey@Sun.COM 		 * where the essid was not broadcast, match the scanned bssid.
95911767SAnurag.Maskey@Sun.COM 		 */
96011767SAnurag.Maskey@Sun.COM 		if (strcmp(cur_wlan->nww_essid, name) != 0 &&
96111767SAnurag.Maskey@Sun.COM 		    !(cur_wlan->nww_essid[0] == '\0' && b_match))
96211767SAnurag.Maskey@Sun.COM 			continue;
96311767SAnurag.Maskey@Sun.COM 		/*
96411767SAnurag.Maskey@Sun.COM 		 * If wireless_strict_bssid is specified, need to match
96511767SAnurag.Maskey@Sun.COM 		 * BSSID too.
96611767SAnurag.Maskey@Sun.COM 		 */
96711767SAnurag.Maskey@Sun.COM 		if (wireless_strict_bssid && !b_match)
96811767SAnurag.Maskey@Sun.COM 			continue;
96911767SAnurag.Maskey@Sun.COM 		/*
97011767SAnurag.Maskey@Sun.COM 		 * Found a match. Since we walk known WLANs in
97111767SAnurag.Maskey@Sun.COM 		 * priority order, it's guaranteed to be the
97211767SAnurag.Maskey@Sun.COM 		 * most prioritized. It may not be the strongest though -
97311767SAnurag.Maskey@Sun.COM 		 * we continue the walk and record the strength along
97411767SAnurag.Maskey@Sun.COM 		 * with the ESSID and BSSID, so that if we encounter
97511767SAnurag.Maskey@Sun.COM 		 * another AP with the same ESSID but a higher signal strength,
97611767SAnurag.Maskey@Sun.COM 		 * we will choose it - but only if the currently-connected
97711767SAnurag.Maskey@Sun.COM 		 * WLAN is at or below wireless_scan_level.
97811767SAnurag.Maskey@Sun.COM 		 */
97911767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_str2strength
98011767SAnurag.Maskey@Sun.COM 		    (cur_wlan->nww_signal_strength, &curr_strength);
98111767SAnurag.Maskey@Sun.COM 
98211767SAnurag.Maskey@Sun.COM 		if (curr_strength > max_strength) {
98311767SAnurag.Maskey@Sun.COM 			(void) strlcpy(link->nwamd_link_wifi_essid,
98411767SAnurag.Maskey@Sun.COM 			    cur_wlan->nww_essid,
98511767SAnurag.Maskey@Sun.COM 			    sizeof (link->nwamd_link_wifi_essid));
98612080SAnurag.Maskey@Sun.COM 			/*
98712080SAnurag.Maskey@Sun.COM 			 * Set BSSID if wireless_strict_bssid is specified or
98812080SAnurag.Maskey@Sun.COM 			 * if this is a hidden WLAN.  Store the BSSID here and
98912080SAnurag.Maskey@Sun.COM 			 * then later determine the hidden WLAN's name in the
99012080SAnurag.Maskey@Sun.COM 			 * connect thread.
99112080SAnurag.Maskey@Sun.COM 			 */
99212080SAnurag.Maskey@Sun.COM 			if (wireless_strict_bssid ||
99312080SAnurag.Maskey@Sun.COM 			    cur_wlan->nww_essid[0] == '\0') {
99411767SAnurag.Maskey@Sun.COM 				(void) strlcpy(link->nwamd_link_wifi_bssid,
99511767SAnurag.Maskey@Sun.COM 				    cur_wlan->nww_bssid,
99611767SAnurag.Maskey@Sun.COM 				    sizeof (link->nwamd_link_wifi_bssid));
99711767SAnurag.Maskey@Sun.COM 			}
99811767SAnurag.Maskey@Sun.COM 			(void) strlcpy(link->nwamd_link_wifi_signal_strength,
99911767SAnurag.Maskey@Sun.COM 			    cur_wlan->nww_signal_strength,
100011767SAnurag.Maskey@Sun.COM 			    sizeof (link->nwamd_link_wifi_signal_strength));
100111767SAnurag.Maskey@Sun.COM 			link->nwamd_link_wifi_security_mode =
100211767SAnurag.Maskey@Sun.COM 			    cur_wlan->nww_security_mode;
100311767SAnurag.Maskey@Sun.COM 			found = B_TRUE;
100411767SAnurag.Maskey@Sun.COM 		}
100511767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_str2strength
100611767SAnurag.Maskey@Sun.COM 		    (link->nwamd_link_wifi_signal_strength, &max_strength);
100711767SAnurag.Maskey@Sun.COM 	}
100811767SAnurag.Maskey@Sun.COM 	free(name);
100911767SAnurag.Maskey@Sun.COM 	return (found ? 1 : 0);
101011767SAnurag.Maskey@Sun.COM }
101111767SAnurag.Maskey@Sun.COM 
101211767SAnurag.Maskey@Sun.COM static boolean_t
nwamd_find_known_wlan(nwamd_object_t ncu_obj)101311767SAnurag.Maskey@Sun.COM nwamd_find_known_wlan(nwamd_object_t ncu_obj)
101411767SAnurag.Maskey@Sun.COM {
101511767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu = ncu_obj->nwamd_object_data;
101611767SAnurag.Maskey@Sun.COM 	int ret;
101711767SAnurag.Maskey@Sun.COM 
101811767SAnurag.Maskey@Sun.COM 	/*
101911767SAnurag.Maskey@Sun.COM 	 * Walk known WLANs, finding lowest priority (preferred) WLAN
102011767SAnurag.Maskey@Sun.COM 	 * in our scan results.
102111767SAnurag.Maskey@Sun.COM 	 */
102211767SAnurag.Maskey@Sun.COM 	(void) nwam_walk_known_wlans(find_best_wlan_cb, ncu,
102311767SAnurag.Maskey@Sun.COM 	    NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, &ret);
102411767SAnurag.Maskey@Sun.COM 
102511767SAnurag.Maskey@Sun.COM 	return (ret == 1);
102611767SAnurag.Maskey@Sun.COM }
102711767SAnurag.Maskey@Sun.COM 
102811767SAnurag.Maskey@Sun.COM /*
102911767SAnurag.Maskey@Sun.COM  * WLAN scan code for WIFI link NCUs.
103011767SAnurag.Maskey@Sun.COM  */
103111767SAnurag.Maskey@Sun.COM 
103211767SAnurag.Maskey@Sun.COM /* Create periodic scan event for object.  Called with object lock held. */
103311767SAnurag.Maskey@Sun.COM void
nwamd_ncu_create_periodic_scan_event(nwamd_object_t ncu_obj)103411767SAnurag.Maskey@Sun.COM nwamd_ncu_create_periodic_scan_event(nwamd_object_t ncu_obj)
103511767SAnurag.Maskey@Sun.COM {
103611767SAnurag.Maskey@Sun.COM 	nwamd_event_t scan_event;
103711767SAnurag.Maskey@Sun.COM 
103811767SAnurag.Maskey@Sun.COM 	if (wireless_scan_interval == 0) {
103911767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_create_periodic_scan_event: "
104011767SAnurag.Maskey@Sun.COM 		    "wireless_scan_interval set to 0 so no periodic scanning");
104111767SAnurag.Maskey@Sun.COM 		return;
104211767SAnurag.Maskey@Sun.COM 	}
104311767SAnurag.Maskey@Sun.COM 	scan_event = nwamd_event_init(NWAM_EVENT_TYPE_PERIODIC_SCAN,
104411767SAnurag.Maskey@Sun.COM 	    NWAM_OBJECT_TYPE_NCU, 0, ncu_obj->nwamd_object_name);
104511767SAnurag.Maskey@Sun.COM 	if (scan_event != NULL) {
104611767SAnurag.Maskey@Sun.COM 		nwamd_event_enqueue_timed(scan_event,
104711767SAnurag.Maskey@Sun.COM 		    wireless_scan_interval > WIRELESS_SCAN_INTERVAL_MIN ?
104811767SAnurag.Maskey@Sun.COM 		    wireless_scan_interval : WIRELESS_SCAN_INTERVAL_MIN);
104911767SAnurag.Maskey@Sun.COM 	}
105011767SAnurag.Maskey@Sun.COM }
105111767SAnurag.Maskey@Sun.COM 
105211767SAnurag.Maskey@Sun.COM /* Handle periodic scan event (which puts link into WIFI_INIT state */
105311767SAnurag.Maskey@Sun.COM void
nwamd_ncu_handle_periodic_scan_event(nwamd_event_t event)105411767SAnurag.Maskey@Sun.COM nwamd_ncu_handle_periodic_scan_event(nwamd_event_t event)
105511767SAnurag.Maskey@Sun.COM {
105611767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
105711767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
105811767SAnurag.Maskey@Sun.COM 
105911767SAnurag.Maskey@Sun.COM 	ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
106011767SAnurag.Maskey@Sun.COM 	    event->event_object);
106111767SAnurag.Maskey@Sun.COM 	if (ncu_obj == NULL) {
106211767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncu_handle_periodic_scan_event: "
106311767SAnurag.Maskey@Sun.COM 		    "no object %s", event->event_object);
106411767SAnurag.Maskey@Sun.COM 		return;
106511767SAnurag.Maskey@Sun.COM 	}
106611767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
106711767SAnurag.Maskey@Sun.COM 
106811767SAnurag.Maskey@Sun.COM 	/* Only rescan if state is offline* or online */
106911767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncu_handle_periodic_scan_event: doing rescan..");
107011767SAnurag.Maskey@Sun.COM 
107111767SAnurag.Maskey@Sun.COM 	if (ncu_obj->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE ||
107211767SAnurag.Maskey@Sun.COM 	    ncu_obj->nwamd_object_state == NWAM_STATE_ONLINE) {
107311767SAnurag.Maskey@Sun.COM 		/* rescan, then create periodic scan event */
107411767SAnurag.Maskey@Sun.COM 		(void) nwamd_wlan_scan(ncu->ncu_name);
107511767SAnurag.Maskey@Sun.COM 		nwamd_ncu_create_periodic_scan_event(ncu_obj);
107611767SAnurag.Maskey@Sun.COM 	}
107711767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
107811767SAnurag.Maskey@Sun.COM }
107911767SAnurag.Maskey@Sun.COM 
108011767SAnurag.Maskey@Sun.COM static boolean_t
get_scan_results(void * arg,dladm_wlan_attr_t * attrp)108111767SAnurag.Maskey@Sun.COM get_scan_results(void *arg, dladm_wlan_attr_t *attrp)
108211767SAnurag.Maskey@Sun.COM {
108311767SAnurag.Maskey@Sun.COM 	nwamd_wifi_scan_t *s = arg;
108411767SAnurag.Maskey@Sun.COM 	const char *linkname = s->nwamd_wifi_scan_link;
108511767SAnurag.Maskey@Sun.COM 	char essid_name[DLADM_STRSIZE];
108611767SAnurag.Maskey@Sun.COM 	char bssid_name[DLADM_STRSIZE];
108711767SAnurag.Maskey@Sun.COM 	char strength[DLADM_STRSIZE];
108811767SAnurag.Maskey@Sun.COM 	uint_t i, index = 0;
108911767SAnurag.Maskey@Sun.COM 	boolean_t found = B_FALSE;
109011767SAnurag.Maskey@Sun.COM 
109111767SAnurag.Maskey@Sun.COM 	(void) dladm_wlan_essid2str(&attrp->wa_essid, essid_name);
109211767SAnurag.Maskey@Sun.COM 	(void) dladm_wlan_bssid2str(&attrp->wa_bssid, bssid_name);
109311767SAnurag.Maskey@Sun.COM 	(void) dladm_wlan_strength2str(&attrp->wa_strength, strength);
109411767SAnurag.Maskey@Sun.COM 
109511767SAnurag.Maskey@Sun.COM 	index = s->nwamd_wifi_scan_curr_num;
109611767SAnurag.Maskey@Sun.COM 	if (index == NWAMD_MAX_NUM_WLANS) {
109711767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "get_scan_results: truncating WLAN scan results "
109811767SAnurag.Maskey@Sun.COM 		    "for link %s: ommiting (%s, %s)", linkname, essid_name,
109911767SAnurag.Maskey@Sun.COM 		    bssid_name);
110011767SAnurag.Maskey@Sun.COM 		return (B_TRUE);
110111767SAnurag.Maskey@Sun.COM 	}
110211767SAnurag.Maskey@Sun.COM 
110311767SAnurag.Maskey@Sun.COM 	(void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_essid, essid_name,
110411767SAnurag.Maskey@Sun.COM 	    sizeof (s->nwamd_wifi_scan_curr[index].nww_essid));
110511767SAnurag.Maskey@Sun.COM 	(void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_bssid, bssid_name,
110611767SAnurag.Maskey@Sun.COM 	    sizeof (s->nwamd_wifi_scan_curr[index].nww_bssid));
110711767SAnurag.Maskey@Sun.COM 	(void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_signal_strength,
110811767SAnurag.Maskey@Sun.COM 	    strength,
110911767SAnurag.Maskey@Sun.COM 	    sizeof (s->nwamd_wifi_scan_curr[index].nww_signal_strength));
111011767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr[index].nww_security_mode = attrp->wa_secmode;
111111767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr[index].nww_speed = attrp->wa_speed;
111211767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr[index].nww_channel = attrp->wa_channel;
111311767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr[index].nww_bsstype = attrp->wa_bsstype;
111411767SAnurag.Maskey@Sun.COM 
111511767SAnurag.Maskey@Sun.COM 	/*
111611767SAnurag.Maskey@Sun.COM 	 * We fill in actual values for selected/connected/key later when we
111711767SAnurag.Maskey@Sun.COM 	 * reacquire the object lock.
111811767SAnurag.Maskey@Sun.COM 	 */
111911767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr[index].nww_selected = B_FALSE;
112011767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr[index].nww_connected = B_FALSE;
112111767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr[index].nww_have_key = B_FALSE;
112211767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr[index].nww_keyindex = 1;
112311767SAnurag.Maskey@Sun.COM 	s->nwamd_wifi_scan_curr_num++;
112411767SAnurag.Maskey@Sun.COM 
112511767SAnurag.Maskey@Sun.COM 	/* Check if this AP was in previous scan results */
112611767SAnurag.Maskey@Sun.COM 	for (i = 0; i < s->nwamd_wifi_scan_last_num; i++) {
112711767SAnurag.Maskey@Sun.COM 		found = (strcmp(s->nwamd_wifi_scan_last[i].nww_essid,
112811767SAnurag.Maskey@Sun.COM 		    essid_name) == 0 &&
112911767SAnurag.Maskey@Sun.COM 		    strcmp(s->nwamd_wifi_scan_last[i].nww_bssid,
113011767SAnurag.Maskey@Sun.COM 		    bssid_name) == 0);
113111767SAnurag.Maskey@Sun.COM 		if (found)
113211767SAnurag.Maskey@Sun.COM 			break;
113311767SAnurag.Maskey@Sun.COM 	}
113411767SAnurag.Maskey@Sun.COM 	if (!found)
113511767SAnurag.Maskey@Sun.COM 		s->nwamd_wifi_scan_changed = B_TRUE;
113611767SAnurag.Maskey@Sun.COM 
113711767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "get_scan_results(%s, %d): ESSID %s, BSSID %s",
113811767SAnurag.Maskey@Sun.COM 	    linkname, index, essid_name, bssid_name);
113911767SAnurag.Maskey@Sun.COM 
114011767SAnurag.Maskey@Sun.COM 	return (B_TRUE);
114111767SAnurag.Maskey@Sun.COM }
114211767SAnurag.Maskey@Sun.COM 
114311767SAnurag.Maskey@Sun.COM /*
114411767SAnurag.Maskey@Sun.COM  * Check if we're connected to the expected WLAN, or in the case of autoconf
114511767SAnurag.Maskey@Sun.COM  * record the WLAN we're connected to.
114611767SAnurag.Maskey@Sun.COM  */
114711767SAnurag.Maskey@Sun.COM boolean_t
nwamd_wlan_connected(nwamd_object_t ncu_obj)114811767SAnurag.Maskey@Sun.COM nwamd_wlan_connected(nwamd_object_t ncu_obj)
114911767SAnurag.Maskey@Sun.COM {
115011767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu = ncu_obj->nwamd_object_data;
115112576SAnurag.Maskey@Oracle.COM 	nwamd_link_t *link = &ncu->ncu_link;
115211767SAnurag.Maskey@Sun.COM 	dladm_wlan_linkattr_t attr;
115311767SAnurag.Maskey@Sun.COM 	char essid[DLADM_STRSIZE];
115411767SAnurag.Maskey@Sun.COM 	char bssid[DLADM_STRSIZE];
115511767SAnurag.Maskey@Sun.COM 	boolean_t connected = B_FALSE;
115611767SAnurag.Maskey@Sun.COM 	int retries = 0;
115711767SAnurag.Maskey@Sun.COM 
115811767SAnurag.Maskey@Sun.COM 	/*
115911767SAnurag.Maskey@Sun.COM 	 * This is awful, but some wireless drivers
116011767SAnurag.Maskey@Sun.COM 	 * (particularly 'ath') will erroneously report
116111767SAnurag.Maskey@Sun.COM 	 * "disconnected" if queried right after a scan.  If we
116211767SAnurag.Maskey@Sun.COM 	 * see 'down' reported here, we retry a few times to
116311767SAnurag.Maskey@Sun.COM 	 * make sure it's really down.
116411767SAnurag.Maskey@Sun.COM 	 */
116511767SAnurag.Maskey@Sun.COM 	while (retries++ < 4) {
116611767SAnurag.Maskey@Sun.COM 		if (dladm_wlan_get_linkattr(dld_handle, link->nwamd_link_id,
116711767SAnurag.Maskey@Sun.COM 		    &attr) != DLADM_STATUS_OK) {
116811767SAnurag.Maskey@Sun.COM 			attr.la_status = DLADM_WLAN_LINK_DISCONNECTED;
116911767SAnurag.Maskey@Sun.COM 		} else if (attr.la_status == DLADM_WLAN_LINK_CONNECTED) {
117011767SAnurag.Maskey@Sun.COM 			break;
117111767SAnurag.Maskey@Sun.COM 		}
117211767SAnurag.Maskey@Sun.COM 	}
117311767SAnurag.Maskey@Sun.COM 
117411767SAnurag.Maskey@Sun.COM 	if (attr.la_status == DLADM_WLAN_LINK_CONNECTED) {
117511767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_essid2str(&attr.la_wlan_attr.wa_essid, essid);
117611767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_bssid2str(&attr.la_wlan_attr.wa_bssid, bssid);
117711767SAnurag.Maskey@Sun.COM 		connected = B_TRUE;
117811767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_wlan_connected: %s connected to %s %s",
117911767SAnurag.Maskey@Sun.COM 		    ncu->ncu_name, essid, bssid);
118011767SAnurag.Maskey@Sun.COM 	} else {
118111767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
118211767SAnurag.Maskey@Sun.COM 	}
118311767SAnurag.Maskey@Sun.COM 	/*
118411767SAnurag.Maskey@Sun.COM 	 * If we're using autoconf,  we have no control over what we connect to,
118511767SAnurag.Maskey@Sun.COM 	 * so rather than verifying ESSSID, simply record ESSID/BSSID.
118611767SAnurag.Maskey@Sun.COM 	 */
118711767SAnurag.Maskey@Sun.COM 	if (link->nwamd_link_wifi_autoconf) {
118811767SAnurag.Maskey@Sun.COM 		(void) strlcpy(link->nwamd_link_wifi_essid, essid,
118911767SAnurag.Maskey@Sun.COM 		    sizeof (link->nwamd_link_wifi_essid));
119011767SAnurag.Maskey@Sun.COM 		(void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
119111767SAnurag.Maskey@Sun.COM 		    sizeof (link->nwamd_link_wifi_bssid));
119211767SAnurag.Maskey@Sun.COM 	}
119311767SAnurag.Maskey@Sun.COM 	/*
119411767SAnurag.Maskey@Sun.COM 	 * Are we connected to expected WLAN? Note:
119511767SAnurag.Maskey@Sun.COM 	 * we'd like to verify BSSID, but we cannot due to CR 6772510.
119611767SAnurag.Maskey@Sun.COM 	 */
119711767SAnurag.Maskey@Sun.COM 	if (strcmp(essid, link->nwamd_link_wifi_essid) == 0) {
119811767SAnurag.Maskey@Sun.COM 		/* Update connected signal strength */
119911767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_strength2str(&attr.la_wlan_attr.wa_strength,
120011767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_signal_strength);
120111767SAnurag.Maskey@Sun.COM 
120211767SAnurag.Maskey@Sun.COM 		/* Store current BSSID */
120311767SAnurag.Maskey@Sun.COM 		(void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
120411767SAnurag.Maskey@Sun.COM 		    sizeof (link->nwamd_link_wifi_bssid));
120511767SAnurag.Maskey@Sun.COM 
120611767SAnurag.Maskey@Sun.COM 		if (attr.la_wlan_attr.wa_strength < wireless_scan_level) {
120711767SAnurag.Maskey@Sun.COM 			/*
120811767SAnurag.Maskey@Sun.COM 			 * We're connected, but we've dropped below
120911767SAnurag.Maskey@Sun.COM 			 * scan threshold.  Initiate a scan.
121011767SAnurag.Maskey@Sun.COM 			 */
121111767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_wlan_connected: "
121211767SAnurag.Maskey@Sun.COM 			    "connected but signal under threshold...");
121311767SAnurag.Maskey@Sun.COM 			(void) nwamd_wlan_scan(ncu->ncu_name);
121411767SAnurag.Maskey@Sun.COM 		}
121511767SAnurag.Maskey@Sun.COM 		return (connected);
121611767SAnurag.Maskey@Sun.COM 	} else if (strlen(essid) == 0) {
121711767SAnurag.Maskey@Sun.COM 		/*
121811767SAnurag.Maskey@Sun.COM 		 * For hidden WLANs, no ESSID is specified, so we cannot verify
121911767SAnurag.Maskey@Sun.COM 		 * WLAN name.
122011767SAnurag.Maskey@Sun.COM 		 */
122111767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG,
122211767SAnurag.Maskey@Sun.COM 		    "nwamd_wlan_connected: connected to hidden WLAN, cannot "
122311767SAnurag.Maskey@Sun.COM 		    "verify connection details");
122411767SAnurag.Maskey@Sun.COM 		return (connected);
122511767SAnurag.Maskey@Sun.COM 	} else {
122611767SAnurag.Maskey@Sun.COM 		(void) nlog(LOG_ERR,
122711767SAnurag.Maskey@Sun.COM 		    "nwamd_wlan_connected: wrong AP on %s; expected %s %s",
122811767SAnurag.Maskey@Sun.COM 		    ncu->ncu_name, link->nwamd_link_wifi_essid,
122911767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_bssid);
123011767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_disconnect(dld_handle, link->nwamd_link_id);
123111767SAnurag.Maskey@Sun.COM 		link->nwamd_link_wifi_connected = B_FALSE;
123211767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
123311767SAnurag.Maskey@Sun.COM 	}
123411767SAnurag.Maskey@Sun.COM }
123511767SAnurag.Maskey@Sun.COM 
123611767SAnurag.Maskey@Sun.COM /*
123711767SAnurag.Maskey@Sun.COM  * WLAN scan thread. Called with the per-link WiFi mutex held.
123811767SAnurag.Maskey@Sun.COM  */
123911767SAnurag.Maskey@Sun.COM static void *
wlan_scan_thread(void * arg)124011767SAnurag.Maskey@Sun.COM wlan_scan_thread(void *arg)
124111767SAnurag.Maskey@Sun.COM {
124211767SAnurag.Maskey@Sun.COM 	char *linkname = arg;
124311767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
124411767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
124511767SAnurag.Maskey@Sun.COM 	nwamd_link_t *link;
124611767SAnurag.Maskey@Sun.COM 	dladm_status_t status;
124711767SAnurag.Maskey@Sun.COM 	char essid[DLADM_STRSIZE];
124811767SAnurag.Maskey@Sun.COM 	char bssid[DLADM_STRSIZE];
124911767SAnurag.Maskey@Sun.COM 	uint32_t now, link_id;
125011767SAnurag.Maskey@Sun.COM 	nwamd_wifi_scan_t s;
125111767SAnurag.Maskey@Sun.COM 	int i;
125211767SAnurag.Maskey@Sun.COM 
125311767SAnurag.Maskey@Sun.COM 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
125411767SAnurag.Maskey@Sun.COM 	    == NULL) {
125511767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "wlan_scan_thread: could not find object  "
125611767SAnurag.Maskey@Sun.COM 		    "for link %s", linkname);
125711767SAnurag.Maskey@Sun.COM 		free(linkname);
125811767SAnurag.Maskey@Sun.COM 		return (NULL);
125911767SAnurag.Maskey@Sun.COM 	}
126011767SAnurag.Maskey@Sun.COM 
126111767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
126212576SAnurag.Maskey@Oracle.COM 	link = &ncu->ncu_link;
126311767SAnurag.Maskey@Sun.COM 
126411767SAnurag.Maskey@Sun.COM 	/*
126511767SAnurag.Maskey@Sun.COM 	 * It is possible multiple scan threads have queued up waiting for the
126611767SAnurag.Maskey@Sun.COM 	 * object lock.  We try to prevent excessive scanning by limiting the
126711767SAnurag.Maskey@Sun.COM 	 * interval between scans to WIRELESS_SCAN_REQUESTED_INTERVAL_MIN sec.
126811767SAnurag.Maskey@Sun.COM 	 */
126911767SAnurag.Maskey@Sun.COM 	now = NSEC_TO_SEC(gethrtime());
127011767SAnurag.Maskey@Sun.COM 	if ((now - link->nwamd_link_wifi_scan.nwamd_wifi_scan_last_time) <
127111767SAnurag.Maskey@Sun.COM 	    WIRELESS_SCAN_REQUESTED_INTERVAL_MIN) {
127211767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "wlan_scan_thread: last scan for %s "
127311767SAnurag.Maskey@Sun.COM 		    "was < %d sec ago, ignoring scan request",
127411767SAnurag.Maskey@Sun.COM 		    linkname, WIRELESS_SCAN_REQUESTED_INTERVAL_MIN);
127511767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
127611767SAnurag.Maskey@Sun.COM 		free(linkname);
127711767SAnurag.Maskey@Sun.COM 		return (NULL);
127811767SAnurag.Maskey@Sun.COM 	}
127911767SAnurag.Maskey@Sun.COM 
128011767SAnurag.Maskey@Sun.COM 	/*
128111767SAnurag.Maskey@Sun.COM 	 * Prepare scan data - copy link name and copy previous "current"
128211767SAnurag.Maskey@Sun.COM 	 * scan results from the nwamd_link_t to the last scan results for
128311767SAnurag.Maskey@Sun.COM 	 * the next scan so that we can compare results to find if things
128411767SAnurag.Maskey@Sun.COM 	 * have changed since last time.
128511767SAnurag.Maskey@Sun.COM 	 */
128611767SAnurag.Maskey@Sun.COM 	(void) bzero(&s, sizeof (nwamd_wifi_scan_t));
128711767SAnurag.Maskey@Sun.COM 	(void) strlcpy(s.nwamd_wifi_scan_link, ncu->ncu_name,
128811767SAnurag.Maskey@Sun.COM 	    sizeof (s.nwamd_wifi_scan_link));
128911767SAnurag.Maskey@Sun.COM 	s.nwamd_wifi_scan_last_num =
129011767SAnurag.Maskey@Sun.COM 	    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num;
129111767SAnurag.Maskey@Sun.COM 	if (s.nwamd_wifi_scan_last_num > 0) {
129211767SAnurag.Maskey@Sun.COM 		(void) memcpy(s.nwamd_wifi_scan_last,
129311767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr,
129411767SAnurag.Maskey@Sun.COM 		    s.nwamd_wifi_scan_last_num * sizeof (nwam_wlan_t));
129511767SAnurag.Maskey@Sun.COM 	}
129611767SAnurag.Maskey@Sun.COM 	link_id = link->nwamd_link_id;
129711767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
129811767SAnurag.Maskey@Sun.COM 
129911767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "wlan_scan_thread: initiating scan on %s",
130011767SAnurag.Maskey@Sun.COM 	    s.nwamd_wifi_scan_link);
130111767SAnurag.Maskey@Sun.COM 
130211767SAnurag.Maskey@Sun.COM 	scanconnect_entry();
130311767SAnurag.Maskey@Sun.COM 	status = dladm_wlan_scan(dld_handle, link_id, &s, get_scan_results);
130411767SAnurag.Maskey@Sun.COM 	s.nwamd_wifi_scan_last_time = NSEC_TO_SEC(gethrtime());
130511767SAnurag.Maskey@Sun.COM 	if (!s.nwamd_wifi_scan_changed) {
130611767SAnurag.Maskey@Sun.COM 		/* Scan may have lost WLANs, if so this qualifies as change */
130711767SAnurag.Maskey@Sun.COM 		s.nwamd_wifi_scan_changed = (s.nwamd_wifi_scan_curr_num !=
130811767SAnurag.Maskey@Sun.COM 		    s.nwamd_wifi_scan_last_num);
130911767SAnurag.Maskey@Sun.COM 	}
131011767SAnurag.Maskey@Sun.COM 	scanconnect_exit();
131111767SAnurag.Maskey@Sun.COM 
131211767SAnurag.Maskey@Sun.COM 	if (status != DLADM_STATUS_OK) {
131311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "wlan_scan_thread: cannot scan link %s",
131411767SAnurag.Maskey@Sun.COM 		    s.nwamd_wifi_scan_link);
131511767SAnurag.Maskey@Sun.COM 		free(linkname);
131611767SAnurag.Maskey@Sun.COM 		return (NULL);
131711767SAnurag.Maskey@Sun.COM 	}
131811767SAnurag.Maskey@Sun.COM 
131911767SAnurag.Maskey@Sun.COM 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
132011767SAnurag.Maskey@Sun.COM 	    == NULL) {
132111767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "wlan_scan_thread: could not find object  "
132211767SAnurag.Maskey@Sun.COM 		    "for link %s after doing scan", linkname);
132311767SAnurag.Maskey@Sun.COM 		free(linkname);
132411767SAnurag.Maskey@Sun.COM 		return (NULL);
132511767SAnurag.Maskey@Sun.COM 	}
132611767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
132712576SAnurag.Maskey@Oracle.COM 	link = &ncu->ncu_link;
132811767SAnurag.Maskey@Sun.COM 
132911767SAnurag.Maskey@Sun.COM 	/* For new scan data, add key info from known WLANs */
133011767SAnurag.Maskey@Sun.COM 	for (i = 0; i < s.nwamd_wifi_scan_curr_num; i++) {
133111767SAnurag.Maskey@Sun.COM 		if (NEED_ENC(s.nwamd_wifi_scan_curr[i].nww_security_mode)) {
133211767SAnurag.Maskey@Sun.COM 			char keyname[NWAM_MAX_VALUE_LEN];
133311767SAnurag.Maskey@Sun.COM 			dladm_wlan_key_t *key = NULL;
133411767SAnurag.Maskey@Sun.COM 
133511767SAnurag.Maskey@Sun.COM 			if (known_wlan_get_keyname
133611767SAnurag.Maskey@Sun.COM 			    (s.nwamd_wifi_scan_curr[i].nww_essid, keyname)
133711767SAnurag.Maskey@Sun.COM 			    == NWAM_SUCCESS &&
133811767SAnurag.Maskey@Sun.COM 			    (key = nwamd_wlan_get_key_named(keyname,
133911767SAnurag.Maskey@Sun.COM 			    s.nwamd_wifi_scan_curr[i].nww_security_mode))
134011767SAnurag.Maskey@Sun.COM 			    != NULL) {
134111767SAnurag.Maskey@Sun.COM 				s.nwamd_wifi_scan_curr[i].nww_have_key =
134211767SAnurag.Maskey@Sun.COM 				    B_TRUE;
134311767SAnurag.Maskey@Sun.COM 				s.nwamd_wifi_scan_curr[i].nww_keyindex =
134411767SAnurag.Maskey@Sun.COM 				    s.nwamd_wifi_scan_curr[i].
134511767SAnurag.Maskey@Sun.COM 				    nww_security_mode ==
134611767SAnurag.Maskey@Sun.COM 				    DLADM_WLAN_SECMODE_WEP ?
134711767SAnurag.Maskey@Sun.COM 				    key->wk_idx : 1;
134811767SAnurag.Maskey@Sun.COM 				free(key);
134911767SAnurag.Maskey@Sun.COM 			}
135011767SAnurag.Maskey@Sun.COM 		}
135111767SAnurag.Maskey@Sun.COM 	}
135211767SAnurag.Maskey@Sun.COM 	/* Copy scan data into nwamd_link_t */
135311767SAnurag.Maskey@Sun.COM 	link->nwamd_link_wifi_scan = s;
135411767SAnurag.Maskey@Sun.COM 	/* Set selected, connected and send scan event if we've got new data */
135511767SAnurag.Maskey@Sun.COM 	nwamd_set_selected_connected(ncu,
135611767SAnurag.Maskey@Sun.COM 	    link->nwamd_link_wifi_essid[0] != '\0',
135711767SAnurag.Maskey@Sun.COM 	    link->nwamd_link_wifi_connected);
135811767SAnurag.Maskey@Sun.COM 
135911767SAnurag.Maskey@Sun.COM 	/*
136011767SAnurag.Maskey@Sun.COM 	 * If wireless selection is not possible because of the current
136111767SAnurag.Maskey@Sun.COM 	 * state or priority-group, then this was just a scan request.
136211767SAnurag.Maskey@Sun.COM 	 * Nothing else to do.
136311767SAnurag.Maskey@Sun.COM 	 */
136411767SAnurag.Maskey@Sun.COM 	if (!wireless_selection_possible(ncu_obj)) {
136511767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
136611767SAnurag.Maskey@Sun.COM 		free(linkname);
136711767SAnurag.Maskey@Sun.COM 		return (NULL);
136811767SAnurag.Maskey@Sun.COM 	}
136911767SAnurag.Maskey@Sun.COM 
137011767SAnurag.Maskey@Sun.COM 	/*
137111767SAnurag.Maskey@Sun.COM 	 * Check if WLAN is on our known WLAN list. If no
137211767SAnurag.Maskey@Sun.COM 	 * previously-visited WLANs are found in scan data, set
137311767SAnurag.Maskey@Sun.COM 	 * new state to NEED_SELECTION (provided we're not currently
137411767SAnurag.Maskey@Sun.COM 	 * connected, as can be the case during a periodic scan or
137511767SAnurag.Maskey@Sun.COM 	 * monitor-triggered scan where the signal strength recovers.
137611767SAnurag.Maskey@Sun.COM 	 */
137711767SAnurag.Maskey@Sun.COM 	if (!nwamd_find_known_wlan(ncu_obj)) {
137811767SAnurag.Maskey@Sun.COM 		if (!nwamd_wlan_connected(ncu_obj)) {
137911767SAnurag.Maskey@Sun.COM 			if (link->nwamd_link_wifi_connected) {
138011767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "wlan_scan_thread: "
138111767SAnurag.Maskey@Sun.COM 				    "unexpected disconnect after scan");
138211767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
138311767SAnurag.Maskey@Sun.COM 				    ncu_obj->nwamd_object_name,
138411767SAnurag.Maskey@Sun.COM 				    NWAM_STATE_ONLINE_TO_OFFLINE,
138511767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_DOWN);
138611767SAnurag.Maskey@Sun.COM 			} else {
138711767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "wlan_scan_thread: "
138811767SAnurag.Maskey@Sun.COM 				    "no known WLANs - ask user");
138911767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
139011767SAnurag.Maskey@Sun.COM 				    ncu_obj->nwamd_object_name,
139111767SAnurag.Maskey@Sun.COM 				    NWAM_STATE_OFFLINE_TO_ONLINE,
139211767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION);
139311767SAnurag.Maskey@Sun.COM 			}
139411767SAnurag.Maskey@Sun.COM 		} else {
139511767SAnurag.Maskey@Sun.COM 			/* still connected. if not online, change to online */
139611767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "wlan_scan_thread: still connected to "
139711767SAnurag.Maskey@Sun.COM 			    "%s %s", link->nwamd_link_wifi_essid,
139811767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_bssid);
139911767SAnurag.Maskey@Sun.COM 			if (ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
140011767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
140111767SAnurag.Maskey@Sun.COM 				    ncu_obj->nwamd_object_name,
140211767SAnurag.Maskey@Sun.COM 				    NWAM_STATE_OFFLINE_TO_ONLINE,
140311767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_UP);
140411767SAnurag.Maskey@Sun.COM 			}
140511767SAnurag.Maskey@Sun.COM 		}
140611767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
140711767SAnurag.Maskey@Sun.COM 
140811767SAnurag.Maskey@Sun.COM 	} else {
140911767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "wlan_scan_thread: found known WLAN %s %s",
141011767SAnurag.Maskey@Sun.COM 		    link->nwamd_link_wifi_essid, link->nwamd_link_wifi_bssid);
141111767SAnurag.Maskey@Sun.COM 
141211767SAnurag.Maskey@Sun.COM 		if (!nwamd_wlan_connected(ncu_obj)) {
141311767SAnurag.Maskey@Sun.COM 			/* Copy selected ESSID/BSSID, unlock, call select */
141411767SAnurag.Maskey@Sun.COM 			(void) strlcpy(essid, link->nwamd_link_wifi_essid,
141511767SAnurag.Maskey@Sun.COM 			    sizeof (essid));
141611767SAnurag.Maskey@Sun.COM 			(void) strlcpy(bssid, link->nwamd_link_wifi_bssid,
141711767SAnurag.Maskey@Sun.COM 			    sizeof (bssid));
141811767SAnurag.Maskey@Sun.COM 			nwamd_object_release(ncu_obj);
141911767SAnurag.Maskey@Sun.COM 			(void) nwamd_wlan_select(linkname, essid, bssid,
142011767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_security_mode, B_TRUE);
142111767SAnurag.Maskey@Sun.COM 		} else {
142211767SAnurag.Maskey@Sun.COM 			/* still connected.  if not online, change to online */
142311767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "wlan_scan_thread: still connected to "
142411767SAnurag.Maskey@Sun.COM 			    "known WLAN %s %s", link->nwamd_link_wifi_essid,
142511767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_bssid);
142611767SAnurag.Maskey@Sun.COM 			if (ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
142711767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
142811767SAnurag.Maskey@Sun.COM 				    ncu_obj->nwamd_object_name,
142911767SAnurag.Maskey@Sun.COM 				    NWAM_STATE_OFFLINE_TO_ONLINE,
143011767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_UP);
143111767SAnurag.Maskey@Sun.COM 			}
143211767SAnurag.Maskey@Sun.COM 			nwamd_object_release(ncu_obj);
143311767SAnurag.Maskey@Sun.COM 		}
143411767SAnurag.Maskey@Sun.COM 	}
143511767SAnurag.Maskey@Sun.COM 	free(linkname);
143611767SAnurag.Maskey@Sun.COM 	return (NULL);
143711767SAnurag.Maskey@Sun.COM }
143811767SAnurag.Maskey@Sun.COM 
143911767SAnurag.Maskey@Sun.COM nwam_error_t
nwamd_wlan_scan(const char * linkname)144011767SAnurag.Maskey@Sun.COM nwamd_wlan_scan(const char *linkname)
144111767SAnurag.Maskey@Sun.COM {
144211767SAnurag.Maskey@Sun.COM 	pthread_t wifi_thread;
144311767SAnurag.Maskey@Sun.COM 	char *link = strdup(linkname);
144411767SAnurag.Maskey@Sun.COM 
144511767SAnurag.Maskey@Sun.COM 	if (link == NULL) {
144611767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_scan: out of memory");
144711767SAnurag.Maskey@Sun.COM 		return (NWAM_NO_MEMORY);
144811767SAnurag.Maskey@Sun.COM 	}
144911767SAnurag.Maskey@Sun.COM 
145011767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_wlan_scan: WLAN scan for %s",
145111767SAnurag.Maskey@Sun.COM 	    link);
145211767SAnurag.Maskey@Sun.COM 
145311767SAnurag.Maskey@Sun.COM 	if (pthread_create(&wifi_thread, NULL, wlan_scan_thread,
145411767SAnurag.Maskey@Sun.COM 	    link) != 0) {
145511767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_scan: could not start scan");
145611767SAnurag.Maskey@Sun.COM 		free(link);
145711767SAnurag.Maskey@Sun.COM 		return (NWAM_ERROR_INTERNAL);
145811767SAnurag.Maskey@Sun.COM 	}
145911767SAnurag.Maskey@Sun.COM 	/* detach thread so that it doesn't become a zombie */
146011767SAnurag.Maskey@Sun.COM 	(void) pthread_detach(wifi_thread);
146111767SAnurag.Maskey@Sun.COM 	return (NWAM_SUCCESS);
146211767SAnurag.Maskey@Sun.COM }
146311767SAnurag.Maskey@Sun.COM 
146411767SAnurag.Maskey@Sun.COM /*
146511767SAnurag.Maskey@Sun.COM  * WLAN connection code.
146611767SAnurag.Maskey@Sun.COM  */
146711767SAnurag.Maskey@Sun.COM 
146811767SAnurag.Maskey@Sun.COM static dladm_status_t
do_connect(uint32_t link_id,dladm_wlan_attr_t * attrp,dladm_wlan_key_t * key,uint_t keycount,uint_t flags)146911767SAnurag.Maskey@Sun.COM do_connect(uint32_t link_id, dladm_wlan_attr_t *attrp, dladm_wlan_key_t *key,
147011767SAnurag.Maskey@Sun.COM     uint_t keycount, uint_t flags)
147111767SAnurag.Maskey@Sun.COM {
147211767SAnurag.Maskey@Sun.COM 	dladm_status_t status;
147311767SAnurag.Maskey@Sun.COM 	char errmsg[DLADM_STRSIZE];
147411767SAnurag.Maskey@Sun.COM 
147511767SAnurag.Maskey@Sun.COM 	scanconnect_entry();
147611767SAnurag.Maskey@Sun.COM 	status = dladm_wlan_connect(dld_handle, link_id, attrp,
147711767SAnurag.Maskey@Sun.COM 	    DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT, key, keycount, flags);
147811767SAnurag.Maskey@Sun.COM 	scanconnect_exit();
147911767SAnurag.Maskey@Sun.COM 
148011767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_do_connect: dladm_wlan_connect returned %s",
148111767SAnurag.Maskey@Sun.COM 	    dladm_status2str(status, errmsg));
148211767SAnurag.Maskey@Sun.COM 
148311767SAnurag.Maskey@Sun.COM 	return (status);
148411767SAnurag.Maskey@Sun.COM }
148511767SAnurag.Maskey@Sun.COM 
148611767SAnurag.Maskey@Sun.COM static void *
wlan_connect_thread(void * arg)148711767SAnurag.Maskey@Sun.COM wlan_connect_thread(void *arg)
148811767SAnurag.Maskey@Sun.COM {
148911767SAnurag.Maskey@Sun.COM 	char *linkname = arg;
149011767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
149111767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
149211767SAnurag.Maskey@Sun.COM 	nwamd_link_t *link;
149311767SAnurag.Maskey@Sun.COM 	nwam_error_t err;
149411767SAnurag.Maskey@Sun.COM 	uint_t	keycount;
149511767SAnurag.Maskey@Sun.COM 	uint32_t link_id;
149611767SAnurag.Maskey@Sun.COM 	dladm_wlan_key_t *key = NULL;
149711767SAnurag.Maskey@Sun.COM 	dladm_wlan_attr_t attr;
149811767SAnurag.Maskey@Sun.COM 	dladm_status_t status;
149911767SAnurag.Maskey@Sun.COM 	boolean_t autoconf = B_FALSE;
150011767SAnurag.Maskey@Sun.COM 
150111767SAnurag.Maskey@Sun.COM 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
150211767SAnurag.Maskey@Sun.COM 	    == NULL) {
150311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "wlan_connect_thread: could not find object  "
150411767SAnurag.Maskey@Sun.COM 		    "for link %s", linkname);
150511767SAnurag.Maskey@Sun.COM 		free(linkname);
150611767SAnurag.Maskey@Sun.COM 		return (NULL);
150711767SAnurag.Maskey@Sun.COM 	}
150811767SAnurag.Maskey@Sun.COM 
150911767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
151012576SAnurag.Maskey@Oracle.COM 	link = &ncu->ncu_link;
151111767SAnurag.Maskey@Sun.COM 
151211767SAnurag.Maskey@Sun.COM 	if (!wireless_selection_possible(ncu_obj)) {
151311767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "wlan_connect_thread: %s in invalid state or "
151411767SAnurag.Maskey@Sun.COM 		    "has lower priority", ncu->ncu_name);
151511767SAnurag.Maskey@Sun.COM 		goto done;
151611767SAnurag.Maskey@Sun.COM 	}
151711767SAnurag.Maskey@Sun.COM 
151811767SAnurag.Maskey@Sun.COM 	/* If it is already connected to the required AP, just return. */
151911767SAnurag.Maskey@Sun.COM 	if (nwamd_wlan_connected(ncu_obj)) {
152011767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
152111767SAnurag.Maskey@Sun.COM 		    ncu_obj->nwamd_object_name,
152211767SAnurag.Maskey@Sun.COM 		    ncu_obj->nwamd_object_state, NWAM_AUX_STATE_UP);
152311767SAnurag.Maskey@Sun.COM 		goto done;
152411767SAnurag.Maskey@Sun.COM 	}
152511767SAnurag.Maskey@Sun.COM 
152612145SAnurag.Maskey@Sun.COM 	(void) memset(&attr, 0, sizeof (attr));
152711767SAnurag.Maskey@Sun.COM 	if (dladm_wlan_str2essid(link->nwamd_link_wifi_essid, &attr.wa_essid)
152811767SAnurag.Maskey@Sun.COM 	    != DLADM_STATUS_OK) {
152911767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "wlan_connect_thread: invalid ESSID '%s' "
153011767SAnurag.Maskey@Sun.COM 		    "for '%s'", link->nwamd_link_wifi_essid, ncu->ncu_name);
153111767SAnurag.Maskey@Sun.COM 		goto done;
153211767SAnurag.Maskey@Sun.COM 	}
153311767SAnurag.Maskey@Sun.COM 	attr.wa_valid = DLADM_WLAN_ATTR_ESSID;
153411767SAnurag.Maskey@Sun.COM 
153511767SAnurag.Maskey@Sun.COM 	/* note: bssid logic here is non-functional */
153611767SAnurag.Maskey@Sun.COM 	if (link->nwamd_link_wifi_bssid[0] != '\0') {
153711767SAnurag.Maskey@Sun.COM 		if (dladm_wlan_str2bssid(link->nwamd_link_wifi_bssid,
153811767SAnurag.Maskey@Sun.COM 		    &attr.wa_bssid) != DLADM_STATUS_OK) {
153911767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "wlan_connect_thread: invalid BSSID '%s'",
154011767SAnurag.Maskey@Sun.COM 			    "for '%s'", link->nwamd_link_wifi_bssid,
154111767SAnurag.Maskey@Sun.COM 			    ncu->ncu_name);
154211767SAnurag.Maskey@Sun.COM 		} else {
154311767SAnurag.Maskey@Sun.COM 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
154411767SAnurag.Maskey@Sun.COM 		}
154511767SAnurag.Maskey@Sun.COM 	}
154611767SAnurag.Maskey@Sun.COM 
154711767SAnurag.Maskey@Sun.COM 	/* First check for the key */
154811767SAnurag.Maskey@Sun.COM 	if (NEED_ENC(link->nwamd_link_wifi_security_mode)) {
154911767SAnurag.Maskey@Sun.COM 		if (link->nwamd_link_wifi_key == NULL) {
155011767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "wlan_connect_thread: could not find "
155111767SAnurag.Maskey@Sun.COM 			    "key for WLAN '%s'", link->nwamd_link_wifi_essid);
155211767SAnurag.Maskey@Sun.COM 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
155311767SAnurag.Maskey@Sun.COM 			    ncu_obj->nwamd_object_name,
155411767SAnurag.Maskey@Sun.COM 			    NWAM_STATE_OFFLINE_TO_ONLINE,
155511767SAnurag.Maskey@Sun.COM 			    NWAM_AUX_STATE_LINK_WIFI_NEED_KEY);
155611767SAnurag.Maskey@Sun.COM 			goto done;
155711767SAnurag.Maskey@Sun.COM 		}
155811767SAnurag.Maskey@Sun.COM 		/* Make a copy of the key as we need to unlock the object */
155911767SAnurag.Maskey@Sun.COM 		if ((key = calloc(1, sizeof (dladm_wlan_key_t))) == NULL) {
156011767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "wlan_connect_thread: out of memory");
156111767SAnurag.Maskey@Sun.COM 			goto done;
156211767SAnurag.Maskey@Sun.COM 		}
156311767SAnurag.Maskey@Sun.COM 		(void) memcpy(key, link->nwamd_link_wifi_key,
156411767SAnurag.Maskey@Sun.COM 		    sizeof (dladm_wlan_key_t));
156511767SAnurag.Maskey@Sun.COM 
156611767SAnurag.Maskey@Sun.COM 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
156711767SAnurag.Maskey@Sun.COM 		attr.wa_secmode = link->nwamd_link_wifi_security_mode;
156811767SAnurag.Maskey@Sun.COM 		keycount = 1;
156911767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "wlan_connect_thread: retrieved key");
157011767SAnurag.Maskey@Sun.COM 	} else {
157111767SAnurag.Maskey@Sun.COM 		key = NULL;
157211767SAnurag.Maskey@Sun.COM 		keycount = 0;
157311767SAnurag.Maskey@Sun.COM 	}
157411767SAnurag.Maskey@Sun.COM 
157511767SAnurag.Maskey@Sun.COM 	/*
157611767SAnurag.Maskey@Sun.COM 	 * Connect; only scan if a bssid was not specified.  If it times out,
157711767SAnurag.Maskey@Sun.COM 	 * try a second time using autoconf.  Drop the object lock during the
157811767SAnurag.Maskey@Sun.COM 	 * connect attempt since connecting may take some time, and access to
157911767SAnurag.Maskey@Sun.COM 	 * the link object during that period would be impossible if we held the
158011767SAnurag.Maskey@Sun.COM 	 * lock.
158111767SAnurag.Maskey@Sun.COM 	 */
158211767SAnurag.Maskey@Sun.COM 
158311767SAnurag.Maskey@Sun.COM 	link->nwamd_link_wifi_autoconf = B_FALSE;
158411767SAnurag.Maskey@Sun.COM 	link_id = link->nwamd_link_id;
158511767SAnurag.Maskey@Sun.COM 
158611767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
158711767SAnurag.Maskey@Sun.COM 
158811767SAnurag.Maskey@Sun.COM 	status = do_connect(link_id, &attr, key, keycount,
158911767SAnurag.Maskey@Sun.COM 	    DLADM_WLAN_CONNECT_NOSCAN);
159011767SAnurag.Maskey@Sun.COM 	if (status != DLADM_STATUS_OK) {
159111767SAnurag.Maskey@Sun.COM 		/* Connect failed, try autoconf */
159211767SAnurag.Maskey@Sun.COM 		if (!wireless_autoconf || (status = do_connect(link_id, &attr,
159311767SAnurag.Maskey@Sun.COM 		    NULL, 0, 0)) != DLADM_STATUS_OK) {
159411767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "wlan_connect_thread: connect failed for "
159511767SAnurag.Maskey@Sun.COM 			    "%s", linkname);
159611767SAnurag.Maskey@Sun.COM 			goto done_unlocked;
159711767SAnurag.Maskey@Sun.COM 		}
159811767SAnurag.Maskey@Sun.COM 		if (status == DLADM_STATUS_OK)
159911767SAnurag.Maskey@Sun.COM 			autoconf = B_TRUE;
160011767SAnurag.Maskey@Sun.COM 	}
160111767SAnurag.Maskey@Sun.COM 
160211767SAnurag.Maskey@Sun.COM 	/* Connect succeeded, reacquire object */
160311767SAnurag.Maskey@Sun.COM 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
160411767SAnurag.Maskey@Sun.COM 	    == NULL) {
160511767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "wlan_connect_thread: could not find object  "
160611767SAnurag.Maskey@Sun.COM 		    "for link %s", linkname);
160711767SAnurag.Maskey@Sun.COM 		goto done_unlocked;
160811767SAnurag.Maskey@Sun.COM 	}
160911767SAnurag.Maskey@Sun.COM 
161011767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
161112576SAnurag.Maskey@Oracle.COM 	link = &ncu->ncu_link;
161211767SAnurag.Maskey@Sun.COM 
161311767SAnurag.Maskey@Sun.COM 	if (autoconf)
161411767SAnurag.Maskey@Sun.COM 		link->nwamd_link_wifi_autoconf = B_TRUE;
161511767SAnurag.Maskey@Sun.COM 
161611767SAnurag.Maskey@Sun.COM 	/*
161711767SAnurag.Maskey@Sun.COM 	 * If WLAN is WEP/WPA, we would like to test the connection as the key
161811767SAnurag.Maskey@Sun.COM 	 * may be wrong.  It is difficult to find a reliable test that works
161911767SAnurag.Maskey@Sun.COM 	 * across APs however.  Do nothing for now.
162011767SAnurag.Maskey@Sun.COM 	 */
162111767SAnurag.Maskey@Sun.COM 	link->nwamd_link_wifi_connected = nwamd_wlan_connected(ncu_obj);
162211767SAnurag.Maskey@Sun.COM 
162311767SAnurag.Maskey@Sun.COM 	if (link->nwamd_link_wifi_connected) {
162411767SAnurag.Maskey@Sun.COM 		if (link->nwamd_link_wifi_add_to_known_wlans) {
162511767SAnurag.Maskey@Sun.COM 			/* add to known WLANs */
162611767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "wlan_connect_thread: "
162711767SAnurag.Maskey@Sun.COM 			    "add '%s' to known WLANs",
162811767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_essid);
162911767SAnurag.Maskey@Sun.COM 			if ((err = nwam_known_wlan_add_to_known_wlans
163011767SAnurag.Maskey@Sun.COM 			    (link->nwamd_link_wifi_essid,
163111767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_bssid[0] != '\0' ?
163211767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_bssid : NULL,
163311767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_security_mode,
163411767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_security_mode ==
163511767SAnurag.Maskey@Sun.COM 			    DLADM_WLAN_SECMODE_WEP ?
163611767SAnurag.Maskey@Sun.COM 			    (uint_t)link->nwamd_link_wifi_key->wk_idx : 1,
163711767SAnurag.Maskey@Sun.COM 			    NEED_ENC(link->nwamd_link_wifi_security_mode) ?
163811767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_wifi_keyname : NULL))
163911767SAnurag.Maskey@Sun.COM 			    != NWAM_SUCCESS) {
164011767SAnurag.Maskey@Sun.COM 				nlog(LOG_ERR, "wlan_connect_thread: "
164111767SAnurag.Maskey@Sun.COM 				    "could not add to known WLANs: %s",
164211767SAnurag.Maskey@Sun.COM 				    nwam_strerror(err));
164311767SAnurag.Maskey@Sun.COM 			}
164411767SAnurag.Maskey@Sun.COM 		}
164511767SAnurag.Maskey@Sun.COM 		nwamd_set_selected_connected(ncu, B_TRUE, B_TRUE);
164611767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "wlan_connect_thread: connect "
164711767SAnurag.Maskey@Sun.COM 		    "succeeded, setting state online");
164811767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
164911767SAnurag.Maskey@Sun.COM 		    ncu_obj->nwamd_object_name, NWAM_STATE_ONLINE,
165011767SAnurag.Maskey@Sun.COM 		    NWAM_AUX_STATE_UP);
165111767SAnurag.Maskey@Sun.COM 	}
165211767SAnurag.Maskey@Sun.COM 
165311767SAnurag.Maskey@Sun.COM done:
165411767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
165511767SAnurag.Maskey@Sun.COM done_unlocked:
165611767SAnurag.Maskey@Sun.COM 	free(linkname);
165711767SAnurag.Maskey@Sun.COM 	free(key);
165811767SAnurag.Maskey@Sun.COM 
165911767SAnurag.Maskey@Sun.COM 	return (NULL);
166011767SAnurag.Maskey@Sun.COM }
166111767SAnurag.Maskey@Sun.COM 
166211767SAnurag.Maskey@Sun.COM void
nwamd_wlan_connect(const char * linkname)166311767SAnurag.Maskey@Sun.COM nwamd_wlan_connect(const char *linkname)
166411767SAnurag.Maskey@Sun.COM {
166511767SAnurag.Maskey@Sun.COM 	pthread_t wifi_thread;
166611767SAnurag.Maskey@Sun.COM 	char *link = strdup(linkname);
166711767SAnurag.Maskey@Sun.COM 
166811767SAnurag.Maskey@Sun.COM 	if (link == NULL) {
166911767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_connect: out of memory");
167011767SAnurag.Maskey@Sun.COM 		return;
167111767SAnurag.Maskey@Sun.COM 	}
167211767SAnurag.Maskey@Sun.COM 
167311767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_wlan_connect: WLAN connect for %s",
167411767SAnurag.Maskey@Sun.COM 	    link);
167511767SAnurag.Maskey@Sun.COM 
167611767SAnurag.Maskey@Sun.COM 	if (pthread_create(&wifi_thread, NULL, wlan_connect_thread, link) != 0)
167711767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_connect: could not start connect");
167811767SAnurag.Maskey@Sun.COM 
167911767SAnurag.Maskey@Sun.COM 	/* detach thread so that it doesn't become a zombie */
168011767SAnurag.Maskey@Sun.COM 	(void) pthread_detach(wifi_thread);
168111767SAnurag.Maskey@Sun.COM }
168211767SAnurag.Maskey@Sun.COM 
168311767SAnurag.Maskey@Sun.COM /*
168411767SAnurag.Maskey@Sun.COM  * Launch signal strength-monitoring thread which periodically
168511767SAnurag.Maskey@Sun.COM  * checks connection and signal strength.  If we become disconnected
168611767SAnurag.Maskey@Sun.COM  * or signal drops below threshold specified by wireless_scan_level,
168711767SAnurag.Maskey@Sun.COM  * initiate a scan.  The scan initiation is taken care of by
168811767SAnurag.Maskey@Sun.COM  * the call to nwamd_wlan_connected().
168911767SAnurag.Maskey@Sun.COM  */
169011767SAnurag.Maskey@Sun.COM static void *
wlan_monitor_signal_thread(void * arg)169111767SAnurag.Maskey@Sun.COM wlan_monitor_signal_thread(void *arg)
169211767SAnurag.Maskey@Sun.COM {
169311767SAnurag.Maskey@Sun.COM 	char *linkname = arg;
169411767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
169511767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
169611767SAnurag.Maskey@Sun.COM 	nwamd_link_t *link;
169711767SAnurag.Maskey@Sun.COM 	boolean_t first_time = B_TRUE;
169811767SAnurag.Maskey@Sun.COM 
169911767SAnurag.Maskey@Sun.COM 	for (;;) {
170011767SAnurag.Maskey@Sun.COM 		if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK,
170111767SAnurag.Maskey@Sun.COM 		    linkname)) == NULL) {
170211767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "wlan_monitor_signal_thread: could "
170311767SAnurag.Maskey@Sun.COM 			    "not find object for link %s", linkname);
170411767SAnurag.Maskey@Sun.COM 			break;
170511767SAnurag.Maskey@Sun.COM 		}
170611767SAnurag.Maskey@Sun.COM 		ncu = ncu_obj->nwamd_object_data;
170712576SAnurag.Maskey@Oracle.COM 		link = &ncu->ncu_link;
170811767SAnurag.Maskey@Sun.COM 
170911767SAnurag.Maskey@Sun.COM 		/* If the NCU is DISABLED/OFFLINE, exit the monitoring thread */
171011767SAnurag.Maskey@Sun.COM 		if (ncu_obj->nwamd_object_state == NWAM_STATE_OFFLINE ||
171111767SAnurag.Maskey@Sun.COM 		    ncu_obj->nwamd_object_state == NWAM_STATE_DISABLED) {
171211767SAnurag.Maskey@Sun.COM 			nlog(LOG_INFO, "wlan_monitor_signal_thread: "
171311767SAnurag.Maskey@Sun.COM 			    "%s is %s, stopping thread", linkname,
171411767SAnurag.Maskey@Sun.COM 			    nwam_state_to_string(ncu_obj->nwamd_object_state));
171511767SAnurag.Maskey@Sun.COM 			link->nwamd_link_wifi_monitor_thread = 0;
171611767SAnurag.Maskey@Sun.COM 			nwamd_object_release(ncu_obj);
171711767SAnurag.Maskey@Sun.COM 			break;
171811767SAnurag.Maskey@Sun.COM 		}
171911767SAnurag.Maskey@Sun.COM 
172011767SAnurag.Maskey@Sun.COM 		/*
172111767SAnurag.Maskey@Sun.COM 		 * First time thru loop, we check if there is another
172211767SAnurag.Maskey@Sun.COM 		 * link monitoring thread in operation - if so exit this
172311767SAnurag.Maskey@Sun.COM 		 * thread.
172411767SAnurag.Maskey@Sun.COM 		 */
172511767SAnurag.Maskey@Sun.COM 		if (first_time) {
172611767SAnurag.Maskey@Sun.COM 			first_time = B_FALSE;
172711767SAnurag.Maskey@Sun.COM 
172811767SAnurag.Maskey@Sun.COM 			if (link->nwamd_link_wifi_monitor_thread != 0) {
172911767SAnurag.Maskey@Sun.COM 				/* Already have a monitor thread for link? */
173011767SAnurag.Maskey@Sun.COM 				nwamd_object_release(ncu_obj);
173111767SAnurag.Maskey@Sun.COM 				break;
173211767SAnurag.Maskey@Sun.COM 			} else {
173311767SAnurag.Maskey@Sun.COM 				link->nwamd_link_wifi_monitor_thread =
173411767SAnurag.Maskey@Sun.COM 				    pthread_self();
173511767SAnurag.Maskey@Sun.COM 			}
173611767SAnurag.Maskey@Sun.COM 		}
173711767SAnurag.Maskey@Sun.COM 		if (!nwamd_wlan_connected(ncu_obj)) {
173811767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "wlan_monitor_signal_thread: "
173911767SAnurag.Maskey@Sun.COM 			    "disconnect occured for WLAN on link %s", linkname);
174011767SAnurag.Maskey@Sun.COM 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
174111767SAnurag.Maskey@Sun.COM 			    ncu_obj->nwamd_object_name,
174211767SAnurag.Maskey@Sun.COM 			    NWAM_STATE_ONLINE_TO_OFFLINE,
174311767SAnurag.Maskey@Sun.COM 			    NWAM_AUX_STATE_DOWN);
174411767SAnurag.Maskey@Sun.COM 			link->nwamd_link_wifi_monitor_thread = 0;
174511767SAnurag.Maskey@Sun.COM 			nwamd_object_release(ncu_obj);
174611767SAnurag.Maskey@Sun.COM 			break;
174711767SAnurag.Maskey@Sun.COM 		}
174811767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
174911767SAnurag.Maskey@Sun.COM 		(void) sleep(WIRELESS_MONITOR_SIGNAL_INTERVAL);
175011767SAnurag.Maskey@Sun.COM 	}
175111767SAnurag.Maskey@Sun.COM 	free(linkname);
175211767SAnurag.Maskey@Sun.COM 
175311767SAnurag.Maskey@Sun.COM 	return (NULL);
175411767SAnurag.Maskey@Sun.COM }
175511767SAnurag.Maskey@Sun.COM 
175611767SAnurag.Maskey@Sun.COM void
nwamd_wlan_monitor_signal(const char * linkname)175711767SAnurag.Maskey@Sun.COM nwamd_wlan_monitor_signal(const char *linkname)
175811767SAnurag.Maskey@Sun.COM {
175911767SAnurag.Maskey@Sun.COM 	pthread_t wifi_thread;
176011767SAnurag.Maskey@Sun.COM 	char *link = strdup(linkname);
176111767SAnurag.Maskey@Sun.COM 
176211767SAnurag.Maskey@Sun.COM 	if (link == NULL) {
176311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_monitor_signal: out of memory");
176411767SAnurag.Maskey@Sun.COM 		return;
176511767SAnurag.Maskey@Sun.COM 	}
176611767SAnurag.Maskey@Sun.COM 
176711767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_wlan_monitor_signal: WLAN monitor for %s",
176811767SAnurag.Maskey@Sun.COM 	    link);
176911767SAnurag.Maskey@Sun.COM 
177011767SAnurag.Maskey@Sun.COM 	if (pthread_create(&wifi_thread, NULL, wlan_monitor_signal_thread,
177111767SAnurag.Maskey@Sun.COM 	    link) != 0) {
177211767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_wlan_monitor_signal: could not monitor "
177311767SAnurag.Maskey@Sun.COM 		    "link %s", link);
177411767SAnurag.Maskey@Sun.COM 		free(link);
177511767SAnurag.Maskey@Sun.COM 		return;
177611767SAnurag.Maskey@Sun.COM 	}
177711767SAnurag.Maskey@Sun.COM 
177811767SAnurag.Maskey@Sun.COM 	/* detach thread so that it doesn't become a zombie */
177911767SAnurag.Maskey@Sun.COM 	(void) pthread_detach(wifi_thread);
178011767SAnurag.Maskey@Sun.COM }
178111767SAnurag.Maskey@Sun.COM 
178211767SAnurag.Maskey@Sun.COM void
nwamd_ncu_handle_link_state_event(nwamd_event_t event)178311767SAnurag.Maskey@Sun.COM nwamd_ncu_handle_link_state_event(nwamd_event_t event)
178411767SAnurag.Maskey@Sun.COM {
178511767SAnurag.Maskey@Sun.COM 	nwam_event_t evm;
178611767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
178711767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
178811767SAnurag.Maskey@Sun.COM 	nwamd_link_t *link;
178911767SAnurag.Maskey@Sun.COM 
179011767SAnurag.Maskey@Sun.COM 	ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, event->event_object);
179111767SAnurag.Maskey@Sun.COM 	if (ncu_obj == NULL) {
1792*12923SRenee.Sommerfeld@Oracle.COM 		nlog(LOG_INFO, "nwamd_ncu_handle_link_state_event: no object "
1793*12923SRenee.Sommerfeld@Oracle.COM 		    "%s", event->event_object);
179411767SAnurag.Maskey@Sun.COM 		nwamd_event_do_not_send(event);
179511767SAnurag.Maskey@Sun.COM 		return;
179611767SAnurag.Maskey@Sun.COM 	}
179711767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
179812576SAnurag.Maskey@Oracle.COM 	link = &ncu->ncu_link;
179911767SAnurag.Maskey@Sun.COM 	evm = event->event_msg;
180011767SAnurag.Maskey@Sun.COM 
180111767SAnurag.Maskey@Sun.COM 	/*
180211767SAnurag.Maskey@Sun.COM 	 * We ignore link state events for WiFi because it is very flaky.
180311767SAnurag.Maskey@Sun.COM 	 * Instead we use the monitor thread and drive WiFi state changes from
180411767SAnurag.Maskey@Sun.COM 	 * there.
180511767SAnurag.Maskey@Sun.COM 	 */
180611767SAnurag.Maskey@Sun.COM 	if (link->nwamd_link_media == DL_WIFI) {
180711767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
180811767SAnurag.Maskey@Sun.COM 		return;
180911767SAnurag.Maskey@Sun.COM 	}
181011767SAnurag.Maskey@Sun.COM 
181111767SAnurag.Maskey@Sun.COM 	/*
181211767SAnurag.Maskey@Sun.COM 	 * If it's a link up event and we're not disabled, go online.
181311767SAnurag.Maskey@Sun.COM 	 */
181411767SAnurag.Maskey@Sun.COM 	if (evm->nwe_data.nwe_link_state.nwe_link_up &&
181511767SAnurag.Maskey@Sun.COM 	    ncu_obj->nwamd_object_state != NWAM_STATE_DISABLED) {
181611767SAnurag.Maskey@Sun.COM 
181711767SAnurag.Maskey@Sun.COM 		if (link->nwamd_link_activation_mode ==
181811767SAnurag.Maskey@Sun.COM 		    NWAM_ACTIVATION_MODE_PRIORITIZED) {
181911767SAnurag.Maskey@Sun.COM 			int64_t priority_group;
182011767SAnurag.Maskey@Sun.COM 
182111767SAnurag.Maskey@Sun.COM 			(void) pthread_mutex_lock(&active_ncp_mutex);
182211767SAnurag.Maskey@Sun.COM 			priority_group = current_ncu_priority_group;
182311767SAnurag.Maskey@Sun.COM 			(void) pthread_mutex_unlock(&active_ncp_mutex);
182411767SAnurag.Maskey@Sun.COM 
182511767SAnurag.Maskey@Sun.COM 			/* compare priority groups */
182611767SAnurag.Maskey@Sun.COM 			if (link->nwamd_link_priority_group > priority_group) {
182711767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG,
182811767SAnurag.Maskey@Sun.COM 				    "nwamd_ncu_handle_link_state_event: "
182911767SAnurag.Maskey@Sun.COM 				    "got LINK UP event for priority group "
183011767SAnurag.Maskey@Sun.COM 				    "%lld, less preferred than current %lld, "
183111767SAnurag.Maskey@Sun.COM 				    "ignoring",
183211767SAnurag.Maskey@Sun.COM 				    link->nwamd_link_priority_group,
183311767SAnurag.Maskey@Sun.COM 				    priority_group);
183411767SAnurag.Maskey@Sun.COM 
183511767SAnurag.Maskey@Sun.COM 			} else if (link->nwamd_link_priority_group ==
183611767SAnurag.Maskey@Sun.COM 			    priority_group) {
183711767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG,
183811767SAnurag.Maskey@Sun.COM 				    "nwamd_ncu_handle_link_state_event: "
183911767SAnurag.Maskey@Sun.COM 				    "got LINK UP event for priority group "
184011767SAnurag.Maskey@Sun.COM 				    "%lld, same as current %lld",
184111767SAnurag.Maskey@Sun.COM 				    link->nwamd_link_priority_group,
184211767SAnurag.Maskey@Sun.COM 				    priority_group);
184311767SAnurag.Maskey@Sun.COM 				/*
184411767SAnurag.Maskey@Sun.COM 				 * Change link state to UP.  It will be
184511767SAnurag.Maskey@Sun.COM 				 * propagated to IP state machine.  Only do
184611767SAnurag.Maskey@Sun.COM 				 * the NCU check if and when the interface
184711767SAnurag.Maskey@Sun.COM 				 * NCU is online.
184811767SAnurag.Maskey@Sun.COM 				 */
184911767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
185011767SAnurag.Maskey@Sun.COM 				    event->event_object,
185111767SAnurag.Maskey@Sun.COM 				    NWAM_STATE_OFFLINE_TO_ONLINE,
185211767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_UP);
185311767SAnurag.Maskey@Sun.COM 			} else {
185411767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG,
185511767SAnurag.Maskey@Sun.COM 				    "nwamd_ncu_handle_link_state_event: "
185611767SAnurag.Maskey@Sun.COM 				    "got LINK UP event for priority group "
185711767SAnurag.Maskey@Sun.COM 				    "%lld, more preferred than current %lld",
185811767SAnurag.Maskey@Sun.COM 				    link->nwamd_link_priority_group,
185911767SAnurag.Maskey@Sun.COM 				    priority_group);
186011767SAnurag.Maskey@Sun.COM 
186111767SAnurag.Maskey@Sun.COM 				/*
186211767SAnurag.Maskey@Sun.COM 				 * We need to mark the link as up so that when
186311767SAnurag.Maskey@Sun.COM 				 * it is activated we will bring the interface
186411767SAnurag.Maskey@Sun.COM 				 * up.
186511767SAnurag.Maskey@Sun.COM 				 */
186611767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
186711767SAnurag.Maskey@Sun.COM 				    event->event_object,
186811767SAnurag.Maskey@Sun.COM 				    NWAM_STATE_OFFLINE_TO_ONLINE,
186911767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_UP);
187011767SAnurag.Maskey@Sun.COM 				nwamd_object_release(ncu_obj);
187111767SAnurag.Maskey@Sun.COM 				nwamd_ncp_deactivate_priority_group
187211767SAnurag.Maskey@Sun.COM 				    (priority_group);
187311767SAnurag.Maskey@Sun.COM 				nwamd_ncp_activate_priority_group
187411767SAnurag.Maskey@Sun.COM 				    (link->nwamd_link_priority_group);
187511767SAnurag.Maskey@Sun.COM 				return;
187611767SAnurag.Maskey@Sun.COM 			}
187711767SAnurag.Maskey@Sun.COM 
187811767SAnurag.Maskey@Sun.COM 		} else if (link->nwamd_link_activation_mode ==
187911767SAnurag.Maskey@Sun.COM 		    NWAM_ACTIVATION_MODE_MANUAL) {
188011767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_ncu_handle_link_state_event: "
188111767SAnurag.Maskey@Sun.COM 			    "got LINK UP event for manual NCU %s",
188211767SAnurag.Maskey@Sun.COM 			    ncu_obj->nwamd_object_name);
188311767SAnurag.Maskey@Sun.COM 
188411767SAnurag.Maskey@Sun.COM 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
188511767SAnurag.Maskey@Sun.COM 			    event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE,
188611767SAnurag.Maskey@Sun.COM 			    NWAM_AUX_STATE_UP);
188711767SAnurag.Maskey@Sun.COM 		}
188811767SAnurag.Maskey@Sun.COM 	}
188911767SAnurag.Maskey@Sun.COM 
189011767SAnurag.Maskey@Sun.COM 	/*
189111767SAnurag.Maskey@Sun.COM 	 * If the link is down then start or continue transition down.
189211767SAnurag.Maskey@Sun.COM 	 */
189311767SAnurag.Maskey@Sun.COM 	if (!evm->nwe_data.nwe_link_state.nwe_link_up &&
189411767SAnurag.Maskey@Sun.COM 	    (ncu_obj->nwamd_object_state == NWAM_STATE_ONLINE ||
189511767SAnurag.Maskey@Sun.COM 	    ncu_obj->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE)) {
189611767SAnurag.Maskey@Sun.COM 
189711767SAnurag.Maskey@Sun.COM 		if (link->nwamd_link_activation_mode ==
189811767SAnurag.Maskey@Sun.COM 		    NWAM_ACTIVATION_MODE_PRIORITIZED) {
189911767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG,
190011767SAnurag.Maskey@Sun.COM 			    "nwamd_ncu_handle_link_state_event: "
190111767SAnurag.Maskey@Sun.COM 			    "got LINK DOWN for priority group %lld",
190211767SAnurag.Maskey@Sun.COM 			    link->nwamd_link_priority_group);
190311767SAnurag.Maskey@Sun.COM 			/* Moving to offline checks priority group */
190411767SAnurag.Maskey@Sun.COM 		} else {
190511767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_ncu_handle_link_state_event: "
190611767SAnurag.Maskey@Sun.COM 			    "got LINK DOWN event for manual NCU %s",
190711767SAnurag.Maskey@Sun.COM 			    ncu_obj->nwamd_object_name);
190811767SAnurag.Maskey@Sun.COM 		}
190911767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
191011767SAnurag.Maskey@Sun.COM 		    event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE,
191111767SAnurag.Maskey@Sun.COM 		    NWAM_AUX_STATE_DOWN);
191211767SAnurag.Maskey@Sun.COM 	}
191311767SAnurag.Maskey@Sun.COM 
191411767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
191511767SAnurag.Maskey@Sun.COM }
1916