/*
- * WPA Supplicant - driver interaction with generic Linux Wireless Extensions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* This file implements a driver interface for the Linux Wireless Extensions.
* When used with WE-18 or newer, this interface can be used as-is with number
#include "includes.h"
#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <net/if_arp.h>
-#include "wireless_copy.h"
+#include "linux_wext.h"
#include "common.h"
#include "eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_common.h"
#include "priv_netlink.h"
#include "netlink.h"
+#include "linux_ioctl.h"
+#include "rfkill.h"
#include "driver.h"
#include "driver_wext.h"
-
static int wpa_driver_wext_flush_pmkid(void *priv);
static int wpa_driver_wext_get_range(void *priv);
static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
bytes /= 2;
req_ies = os_malloc(bytes);
- if (req_ies == NULL)
- return;
- hexstr2bin(spos, req_ies, bytes);
+ if (req_ies == NULL ||
+ hexstr2bin(spos, req_ies, bytes) < 0)
+ goto done;
data.assoc_info.req_ies = req_ies;
data.assoc_info.req_ies_len = bytes;
bytes /= 2;
resp_ies = os_malloc(bytes);
- if (resp_ies == NULL)
+ if (resp_ies == NULL ||
+ hexstr2bin(spos, resp_ies, bytes) < 0)
goto done;
- hexstr2bin(spos, resp_ies, bytes);
data.assoc_info.resp_ies = resp_ies;
data.assoc_info.resp_ies_len = bytes;
}
"IWEVCUSTOM length");
return;
}
- buf = os_malloc(iwe->u.data.length + 1);
+ buf = dup_binstr(custom, iwe->u.data.length);
if (buf == NULL)
return;
- os_memcpy(buf, custom, iwe->u.data.length);
- buf[iwe->u.data.length] = '\0';
wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
os_free(buf);
break;
del ? "removed" : "added");
if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
- if (del)
+ if (del) {
+ if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+ "already set - ignore event");
+ return;
+ }
drv->if_removed = 1;
- else
+ } else {
+ if (if_nametoindex(drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Interface %s "
+ "does not exist - ignore "
+ "RTM_NEWLINK",
+ drv->ifname);
+ return;
+ }
+ if (!drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+ "already cleared - ignore event");
+ return;
+ }
drv->if_removed = 0;
+ }
}
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
struct wpa_driver_wext_data *drv = ctx;
int attrlen, rta_len;
struct rtattr *attr;
+ char namebuf[IFNAMSIZ];
if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
(ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
(ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+ wpa_printf(MSG_DEBUG, "WEXT: Interface down");
+ drv->if_disabled = 1;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
+ }
+
+ if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+ if (if_indextoname(ifi->ifi_index, namebuf) &&
+ linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s is down",
+ namebuf);
+ } else if (if_nametoindex(drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s does not exist",
+ drv->ifname);
+ } else if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s is marked "
+ "removed", drv->ifname);
+ } else {
+ wpa_printf(MSG_DEBUG, "WEXT: Interface up");
+ drv->if_disabled = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ }
+
/*
* Some drivers send the association event before the operup event--in
* this case, lifting operstate in wpa_driver_wext_set_operstate()
}
-static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv,
- const char *ifname, int *flags)
+static void wpa_driver_wext_rfkill_blocked(void *ctx)
{
- struct ifreq ifr;
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
- return -1;
- }
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked");
+ /*
+ * This may be for any interface; use ifdown event to disable
+ * interface.
+ */
}
-/**
- * wpa_driver_wext_get_ifflags - Get interface flags (SIOCGIFFLAGS)
- * @drv: driver_wext private data
- * @flags: Pointer to returned flags value
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags)
+static void wpa_driver_wext_rfkill_unblocked(void *ctx)
{
- return wpa_driver_wext_get_ifflags_ifname(drv, drv->ifname, flags);
+ struct wpa_driver_wext_data *drv = ctx;
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked");
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) {
+ wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP "
+ "after rfkill unblock");
+ return;
+ }
+ /* rtnetlink ifup handler will report interface as enabled */
}
-static int wpa_driver_wext_set_ifflags_ifname(struct wpa_driver_wext_data *drv,
- const char *ifname, int flags)
+static void wext_get_phy_name(struct wpa_driver_wext_data *drv)
{
- struct ifreq ifr;
+ /* Find phy (radio) to which this interface belongs */
+ char buf[90], *pos;
+ int f, rv;
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("SIOCSIFFLAGS");
- return -1;
+ drv->phyname[0] = '\0';
+ snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
+ drv->ifname);
+ f = open(buf, O_RDONLY);
+ if (f < 0) {
+ wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+ buf, strerror(errno));
+ return;
}
- return 0;
-}
+ rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
+ close(f);
+ if (rv < 0) {
+ wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+ buf, strerror(errno));
+ return;
+ }
-/**
- * wpa_driver_wext_set_ifflags - Set interface flags (SIOCSIFFLAGS)
- * @drv: driver_wext private data
- * @flags: New value for flags
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags)
-{
- return wpa_driver_wext_set_ifflags_ifname(drv, drv->ifname, flags);
+ drv->phyname[rv] = '\0';
+ pos = os_strchr(drv->phyname, '\n');
+ if (pos)
+ *pos = '\0';
+ wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s",
+ drv->ifname, drv->phyname);
}
{
struct wpa_driver_wext_data *drv;
struct netlink_config *cfg;
+ struct rfkill_config *rcfg;
+ char path[128];
+ struct stat buf;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
drv->ctx = ctx;
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
+ if (stat(path, &buf) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
+ drv->cfg80211 = 1;
+ wext_get_phy_name(drv);
+ }
+
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
perror("socket(PF_INET,SOCK_DGRAM)");
goto err2;
}
+ rcfg = os_zalloc(sizeof(*rcfg));
+ if (rcfg == NULL)
+ goto err3;
+ rcfg->ctx = drv;
+ os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
+ rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked;
+ rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked;
+ drv->rfkill = rfkill_init(rcfg);
+ if (drv->rfkill == NULL) {
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available");
+ os_free(rcfg);
+ }
+
drv->mlme_sock = -1;
if (wpa_driver_wext_finish_drv_init(drv) < 0)
return drv;
err3:
+ rfkill_deinit(drv->rfkill);
netlink_deinit(drv->netlink);
err2:
close(drv->ioctl_sock);
}
-static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
{
- int flags;
+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+}
- if (wpa_driver_wext_get_ifflags(drv, &flags) != 0) {
- wpa_printf(MSG_ERROR, "Could not get interface '%s' flags",
- drv->ifname);
- return -1;
- }
- if (!(flags & IFF_UP)) {
- if (wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) {
- wpa_printf(MSG_ERROR, "Could not set interface '%s' "
- "UP", drv->ifname);
- return -1;
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+{
+ int send_rfkill_event = 0;
+
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) {
+ if (rfkill_is_blocked(drv->rfkill)) {
+ wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable "
+ "interface '%s' due to rfkill",
+ drv->ifname);
+ drv->if_disabled = 1;
+ send_rfkill_event = 1;
} else {
- /*
- * Wait some time to allow driver to initialize before
- * starting configuring the driver. This seems to be
- * needed at least some drivers that load firmware etc.
- * when the interface is set up.
- */
- wpa_printf(MSG_DEBUG, "Interface %s set UP - waiting "
- "a second for the driver to complete "
- "initialization", drv->ifname);
- sleep(1);
+ wpa_printf(MSG_ERROR, "WEXT: Could not set "
+ "interface '%s' UP", drv->ifname);
+ return -1;
}
}
netlink_send_oper_ifla(drv->netlink, drv->ifindex,
1, IF_OPER_DORMANT);
+ if (send_rfkill_event) {
+ eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill,
+ drv, drv->ctx);
+ }
+
return 0;
}
void wpa_driver_wext_deinit(void *priv)
{
struct wpa_driver_wext_data *drv = priv;
- int flags;
wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0);
netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
netlink_deinit(drv->netlink);
+ rfkill_deinit(drv->rfkill);
if (drv->mlme_sock >= 0)
eloop_unregister_read_sock(drv->mlme_sock);
- if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
- (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
close(drv->ioctl_sock);
if (drv->mlme_sock >= 0)
/* Not all drivers generate "scan completed" wireless event, so try to
* read results after a timeout. */
- timeout = 5;
+ timeout = 10;
if (drv->scan_complete_events) {
/*
* The driver seems to deliver SIOCGIWSCAN events to notify
}
-static void wext_get_scan_qual(struct iw_event *iwe,
+static void wext_get_scan_qual(struct wpa_driver_wext_data *drv,
+ struct iw_event *iwe,
struct wext_scan_data *res)
{
res->res.qual = iwe->u.qual.qual;
res->res.flags |= WPA_SCAN_NOISE_INVALID;
if (iwe->u.qual.updated & IW_QUAL_DBM)
res->res.flags |= WPA_SCAN_LEVEL_DBM;
+ if ((iwe->u.qual.updated & IW_QUAL_DBM) ||
+ ((iwe->u.qual.level != 0) &&
+ (iwe->u.qual.level > drv->max_level))) {
+ if (iwe->u.qual.level >= 64)
+ res->res.level -= 0x100;
+ if (iwe->u.qual.noise >= 64)
+ res->res.noise -= 0x100;
+ }
}
tmp = os_realloc(res->ie, res->ie_len + bytes);
if (tmp == NULL)
return;
- hexstr2bin(spos, tmp + res->ie_len, bytes);
res->ie = tmp;
+ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
+ return;
res->ie_len += bytes;
} else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
char *spos;
tmp = os_realloc(res->ie, res->ie_len + bytes);
if (tmp == NULL)
return;
- hexstr2bin(spos, tmp + res->ie_len, bytes);
res->ie = tmp;
+ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
+ return;
res->ie_len += bytes;
} else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
char *spos;
return;
}
bytes /= 2;
- hexstr2bin(spos, bin, bytes);
+ if (hexstr2bin(spos, bin, bytes) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value");
+ return;
+ }
res->res.tsf += WPA_GET_BE64(bin);
}
}
if (data->ie)
os_memcpy(pos, data->ie, data->ie_len);
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(r);
return;
tmp[res->num++] = r;
res->res = tmp;
}
-
+
/**
* wpa_driver_wext_get_scan_results - Fetch the latest scan results
struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
{
struct wpa_driver_wext_data *drv = priv;
- size_t ap_num = 0, len;
+ size_t len;
int first;
u8 *res_buf;
struct iw_event iwe_buf, *iwe = &iwe_buf;
if (res_buf == NULL)
return NULL;
- ap_num = 0;
first = 1;
res = os_zalloc(sizeof(*res));
wext_get_scan_freq(iwe, &data);
break;
case IWEVQUAL:
- wext_get_scan_qual(iwe, &data);
+ wext_get_scan_qual(drv, iwe, &data);
break;
case SIOCGIWENCODE:
wext_get_scan_encode(iwe, &data);
}
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
WPA_DRIVER_CAPA_ENC_WEP104;
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128;
if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
drv->capa.max_scan_ssids = 1;
wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
- "flags 0x%x",
- drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+ "flags 0x%llx",
+ drv->capa.key_mgmt, drv->capa.enc,
+ (unsigned long long) drv->capa.flags);
} else {
wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
"assuming WPA is not supported");
}
+ drv->max_level = range->max_qual.level;
+
os_free(range);
return 0;
}
iwr.u.encoding.pointer = (caddr_t) ext;
iwr.u.encoding.length = sizeof(*ext) + key_len;
- if (addr == NULL ||
- os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
+ if (addr == NULL || is_broadcast_ether_addr(addr))
ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
if (set_tx)
ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
}
if (iwr.u.mode == IW_MODE_INFRA) {
+ /* Clear the BSSID selection */
+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID "
+ "selection on disconnect");
+ }
+
+ if (drv->cfg80211) {
+ /*
+ * cfg80211 supports SIOCSIWMLME commands, so there is
+ * no need for the random SSID hack, but clear the
+ * SSID.
+ */
+ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
+ "SSID on disconnect");
+ }
+ return;
+ }
+
/*
- * Clear the BSSID selection and set a random SSID to make sure
- * the driver will not be trying to associate with something
- * even if it does not understand SIOCSIWMLME commands (or
- * tries to associate automatically after deauth/disassoc).
+ * Set a random SSID to make sure the driver will not be trying
+ * to associate with something even if it does not understand
+ * SIOCSIWMLME commands (or tries to associate automatically
+ * after deauth/disassoc).
*/
- wpa_driver_wext_set_bssid(drv, null_bssid);
-
for (i = 0; i < 32; i++)
ssid[i] = rand() & 0xFF;
- wpa_driver_wext_set_ssid(drv, ssid, 32);
+ if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
+ "SSID to disconnect");
+ }
}
}
}
-static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_wext_data *drv = priv;
- int ret;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
- wpa_driver_wext_disconnect(drv);
- return ret;
-}
-
-
static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
size_t ie_len)
{
int wpa_driver_wext_cipher2wext(int cipher)
{
switch (cipher) {
- case CIPHER_NONE:
+ case WPA_CIPHER_NONE:
return IW_AUTH_CIPHER_NONE;
- case CIPHER_WEP40:
+ case WPA_CIPHER_WEP40:
return IW_AUTH_CIPHER_WEP40;
- case CIPHER_TKIP:
+ case WPA_CIPHER_TKIP:
return IW_AUTH_CIPHER_TKIP;
- case CIPHER_CCMP:
+ case WPA_CIPHER_CCMP:
return IW_AUTH_CIPHER_CCMP;
- case CIPHER_WEP104:
+ case WPA_CIPHER_WEP104:
return IW_AUTH_CIPHER_WEP104;
default:
return 0;
int wpa_driver_wext_keymgmt2wext(int keymgmt)
{
switch (keymgmt) {
- case KEY_MGMT_802_1X:
- case KEY_MGMT_802_1X_NO_WPA:
+ case WPA_KEY_MGMT_IEEE8021X:
+ case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
return IW_AUTH_KEY_MGMT_802_1X;
- case KEY_MGMT_PSK:
+ case WPA_KEY_MGMT_PSK:
return IW_AUTH_KEY_MGMT_PSK;
default:
return 0;
if (!drv->use_crypt) {
iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
} else {
- if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ if (params->auth_alg & WPA_AUTH_ALG_OPEN)
iwr.u.encoding.flags |= IW_ENCODE_OPEN;
- if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ if (params->auth_alg & WPA_AUTH_ALG_SHARED)
iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
}
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ if (drv->cfg80211) {
+ /*
+ * Stop cfg80211 from trying to associate before we are done
+ * with all parameters.
+ */
+ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WEXT: Failed to clear SSID to stop pending cfg80211 association attempts (if any)");
+ /* continue anyway */
+ }
+ }
+
if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
< 0)
ret = -1;
if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
< 0)
ret = -1;
- if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
- value = IW_AUTH_WPA_VERSION_DISABLED;
- else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ if (params->wpa_proto & WPA_PROTO_RSN)
value = IW_AUTH_WPA_VERSION_WPA2;
- else
+ else if (params->wpa_proto & WPA_PROTO_WPA)
value = IW_AUTH_WPA_VERSION_WPA;
+ else
+ value = IW_AUTH_WPA_VERSION_DISABLED;
if (wpa_driver_wext_set_auth_param(drv,
IW_AUTH_WPA_VERSION, value) < 0)
ret = -1;
if (wpa_driver_wext_set_auth_param(drv,
IW_AUTH_KEY_MGMT, value) < 0)
ret = -1;
- value = params->key_mgmt_suite != KEY_MGMT_NONE ||
- params->pairwise_suite != CIPHER_NONE ||
- params->group_suite != CIPHER_NONE ||
- params->wpa_ie_len;
+ value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE ||
+ params->pairwise_suite != WPA_CIPHER_NONE ||
+ params->group_suite != WPA_CIPHER_NONE ||
+ (params->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_WPA));
if (wpa_driver_wext_set_auth_param(drv,
IW_AUTH_PRIVACY_INVOKED, value) < 0)
ret = -1;
/* Allow unencrypted EAPOL messages even if pairwise keys are set when
* not using WPA. IEEE 802.1X specifies that these frames are not
* encrypted, but WPA encrypts them when pairwise keys are in use. */
- if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
- params->key_mgmt_suite == KEY_MGMT_PSK)
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK)
allow_unencrypted_eapol = 0;
else
allow_unencrypted_eapol = 1;
if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
ret = -1;
#endif /* CONFIG_IEEE80211W */
- if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
+ if (params->freq.freq &&
+ wpa_driver_wext_set_freq(drv, params->freq.freq) < 0)
ret = -1;
- if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ if (!drv->cfg80211 &&
+ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
ret = -1;
if (params->bssid &&
wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
ret = -1;
+ if (drv->cfg80211 &&
+ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
return ret;
}
struct wpa_driver_wext_data *drv = priv;
int algs = 0, res;
- if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ if (auth_alg & WPA_AUTH_ALG_OPEN)
algs |= IW_AUTH_ALG_OPEN_SYSTEM;
- if (auth_alg & AUTH_ALG_SHARED_KEY)
+ if (auth_alg & WPA_AUTH_ALG_SHARED)
algs |= IW_AUTH_ALG_SHARED_KEY;
- if (auth_alg & AUTH_ALG_LEAP)
+ if (auth_alg & WPA_AUTH_ALG_LEAP)
algs |= IW_AUTH_ALG_LEAP;
if (algs == 0) {
/* at least one algorithm should be set */
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
- int ret = -1, flags;
+ int ret = -1;
unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
os_memset(&iwr, 0, sizeof(iwr));
goto done;
}
- if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
- (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
-
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
/* Try to set the mode again while the interface is down */
iwr.u.mode = new_mode;
if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
else
ret = 0;
- /* Ignore return value of get_ifflags to ensure that the device
- * is always up like it was before this function was called.
- */
- (void) wpa_driver_wext_get_ifflags(drv, &flags);
- (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
}
done:
}
+static const char * wext_get_radio_name(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return drv->phyname;
+}
+
+
+static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iw_statistics stats;
+ struct iwreq iwr;
+
+ os_memset(si, 0, sizeof(*si));
+ si->current_signal = -9999;
+ si->current_noise = 9999;
+ si->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) &stats;
+ iwr.u.data.length = sizeof(stats);
+ iwr.u.data.flags = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "WEXT: SIOCGIWSTATS: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ si->current_signal = stats.qual.level -
+ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0);
+ si->current_noise = stats.qual.noise -
+ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0);
+ return 0;
+}
+
+
+static int wpa_driver_wext_status(void *priv, char *buf, size_t buflen)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int res;
+ char *pos, *end;
+ unsigned char addr[ETH_ALEN];
+
+ pos = buf;
+ end = buf + buflen;
+
+ if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr))
+ return -1;
+
+ res = os_snprintf(pos, end - pos,
+ "ifindex=%d\n"
+ "ifname=%s\n"
+ "addr=" MACSTR "\n",
+ drv->ifindex,
+ drv->ifname,
+ MAC2STR(addr));
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
+
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
.scan2 = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
- .disassociate = wpa_driver_wext_disassociate,
.associate = wpa_driver_wext_associate,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
.flush_pmkid = wpa_driver_wext_flush_pmkid,
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
+ .get_radio_name = wext_get_radio_name,
+ .signal_poll = wpa_driver_wext_signal_poll,
+ .status = wpa_driver_wext_status,
};