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