/*
- * 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
#include "includes.h"
#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <net/if_arp.h>
#include "wireless_copy.h"
#include "common.h"
-#include "driver.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"
-#include "ieee802_11_defs.h"
-#include "wpa_common.h"
-
-#ifdef CONFIG_CLIENT_MLME
-#include <netpacket/packet.h>
-/* old definitions from net/mac80211 */
-
-typedef u32 __bitwise __be32;
-typedef u64 __bitwise __be64;
-
-#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
-#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
-#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3)
-
-#define PRISM2_PARAM_USER_SPACE_MLME 1045
-#define PRISM2_PARAM_MGMT_IF 1046
-#define PRISM2_HOSTAPD_ADD_STA 2
-#define PRISM2_HOSTAPD_REMOVE_STA 3
-#define PRISM2_HOSTAPD_GET_HW_FEATURES 1002
-#define PRISM2_HOSTAPD_MAX_BUF_SIZE 2048
-
-#ifndef ALIGNED
-#define ALIGNED __attribute__ ((aligned))
-#endif
-
-struct prism2_hostapd_param {
- u32 cmd;
- u8 sta_addr[ETH_ALEN];
- u8 pad[2];
- union {
- struct {
- u16 aid;
- u16 capability;
- u8 supp_rates[32];
- u8 wds_flags;
-#define IEEE80211_STA_DYNAMIC_ENC BIT(0)
- u8 enc_flags;
- u16 listen_interval;
- } add_sta;
- struct {
- u16 num_modes;
- u16 flags;
- u8 data[0] ALIGNED; /* num_modes * feature data */
- } hw_features;
- struct {
- u16 mode; /* MODE_* */
- u16 num_supported_rates;
- u16 num_basic_rates;
- u8 data[0] ALIGNED; /* num_supported_rates * u16 +
- * num_basic_rates * u16 */
- } set_rate_sets;
- struct {
- u16 mode; /* MODE_* */
- u16 chan;
- u32 flag;
- u8 power_level; /* regulatory limit in dBm */
- u8 antenna_max;
- } set_channel_flag;
- struct {
- u32 rd;
- } set_regulatory_domain;
- struct {
- u32 queue;
- s32 aifs;
- u32 cw_min;
- u32 cw_max;
- u32 burst_time; /* maximum burst time in 0.1 ms, i.e.,
- * 10 = 1 ms */
- } tx_queue_params;
- } u;
-};
-
-struct hostapd_ioctl_hw_modes_hdr {
- int mode;
- int num_channels;
- int num_rates;
-};
-
-/*
- * frame format for the management interface that is slated
- * to be replaced by "cooked monitor" with radiotap
- */
-#define IEEE80211_FI_VERSION 0x80211001
-struct ieee80211_frame_info {
- __be32 version;
- __be32 length;
- __be64 mactime;
- __be64 hosttime;
- __be32 phytype;
- __be32 channel;
- __be32 datarate;
- __be32 antenna;
- __be32 priority;
- __be32 ssi_type;
- __be32 ssi_signal;
- __be32 ssi_noise;
- __be32 preamble;
- __be32 encoding;
-
- /* Note: this structure is otherwise identical to capture format used
- * in linux-wlan-ng, but this additional field is used to provide meta
- * data about the frame to hostapd. This was the easiest method for
- * providing this information, but this might change in the future. */
- __be32 msg_type;
-} __attribute__ ((packed));
-
-/* old mode definitions */
-enum {
- MODE_IEEE80211A = 0 /* IEEE 802.11a */,
- MODE_IEEE80211B = 1 /* IEEE 802.11b only */,
- MODE_ATHEROS_TURBO = 2 /* Atheros Turbo mode (2x.11a at 5 GHz) */,
- MODE_IEEE80211G = 3 /* IEEE 802.11g (and 802.11b compatibility) */,
- MODE_ATHEROS_TURBOG = 4 /* Atheros Turbo mode (2x.11g at 2.4 GHz) */,
- NUM_IEEE80211_MODES = 5
-};
-
-#ifndef ETH_P_ALL
-#define ETH_P_ALL 0x0003
-#endif
-#endif /* CONFIG_CLIENT_MLME */
-
-
static int wpa_driver_wext_flush_pmkid(void *priv);
static int wpa_driver_wext_get_range(void *priv);
-static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
-
-
-static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
- int linkmode, int operstate)
-{
- struct {
- struct nlmsghdr hdr;
- struct ifinfomsg ifinfo;
- char opts[16];
- } req;
- struct rtattr *rta;
- static int nl_seq;
- ssize_t ret;
-
- os_memset(&req, 0, sizeof(req));
-
- req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- req.hdr.nlmsg_type = RTM_SETLINK;
- req.hdr.nlmsg_flags = NLM_F_REQUEST;
- req.hdr.nlmsg_seq = ++nl_seq;
- req.hdr.nlmsg_pid = 0;
-
- req.ifinfo.ifi_family = AF_UNSPEC;
- req.ifinfo.ifi_type = 0;
- req.ifinfo.ifi_index = drv->ifindex;
- req.ifinfo.ifi_flags = 0;
- req.ifinfo.ifi_change = 0;
-
- if (linkmode != -1) {
- rta = (struct rtattr *)
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
- rta->rta_type = IFLA_LINKMODE;
- rta->rta_len = RTA_LENGTH(sizeof(char));
- *((char *) RTA_DATA(rta)) = linkmode;
- req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
- RTA_LENGTH(sizeof(char));
- }
- if (operstate != -1) {
- rta = (struct rtattr *)
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
- rta->rta_type = IFLA_OPERSTATE;
- rta->rta_len = RTA_LENGTH(sizeof(char));
- *((char *) RTA_DATA(rta)) = operstate;
- req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
- RTA_LENGTH(sizeof(char));
- }
-
- wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
- linkmode, operstate);
-
- ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
- "%s (assume operstate is not supported)",
- strerror(errno));
- }
-
- return ret < 0 ? -1 : 0;
-}
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
} else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
char *spos;
int bytes;
+ u8 *req_ies = NULL, *resp_ies = NULL;
spos = custom + 17;
return;
bytes /= 2;
- data.assoc_info.req_ies = os_malloc(bytes);
- if (data.assoc_info.req_ies == NULL)
- return;
-
+ req_ies = os_malloc(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;
- hexstr2bin(spos, data.assoc_info.req_ies, bytes);
spos += bytes * 2;
goto done;
bytes /= 2;
- data.assoc_info.resp_ies = os_malloc(bytes);
- if (data.assoc_info.resp_ies == NULL)
+ resp_ies = os_malloc(bytes);
+ if (resp_ies == NULL ||
+ hexstr2bin(spos, resp_ies, bytes) < 0)
goto done;
-
+ data.assoc_info.resp_ies = resp_ies;
data.assoc_info.resp_ies_len = bytes;
- hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
}
wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
done:
- os_free(data.assoc_info.resp_ies);
- os_free(data.assoc_info.req_ies);
+ os_free(resp_ies);
+ os_free(req_ies);
#ifdef CONFIG_PEERKEY
} else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
os_memset(&data, 0, sizeof(data));
if (drv->assoc_req_ies) {
data.assoc_info.req_ies = drv->assoc_req_ies;
- drv->assoc_req_ies = NULL;
data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
}
if (drv->assoc_resp_ies) {
data.assoc_info.resp_ies = drv->assoc_resp_ies;
- drv->assoc_resp_ies = NULL;
data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
}
wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
- os_free(data.assoc_info.req_ies);
- os_free(data.assoc_info.resp_ies);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
}
static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
- void *ctx, char *data, int len)
+ char *data, int len)
{
struct iw_event iwe_buf, *iwe = &iwe_buf;
char *pos, *end, *custom, *buf;
drv->assoc_req_ies = NULL;
os_free(drv->assoc_resp_ies);
drv->assoc_resp_ies = NULL;
- wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
NULL);
} else {
wpa_driver_wext_event_assoc_ies(drv);
- wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
+ NULL);
}
break;
case IWEVMICHAELMICFAILURE:
return;
}
wpa_driver_wext_event_wireless_michaelmicfailure(
- ctx, custom, iwe->u.data.length);
+ drv->ctx, custom, iwe->u.data.length);
break;
case IWEVCUSTOM:
if (custom + iwe->u.data.length > end) {
return;
os_memcpy(buf, custom, iwe->u.data.length);
buf[iwe->u.data.length] = '\0';
- wpa_driver_wext_event_wireless_custom(ctx, buf);
+ wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
os_free(buf);
break;
case SIOCGIWSCAN:
drv->scan_complete_events = 1;
eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
- drv, ctx);
- wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+ drv, drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+ NULL);
break;
case IWEVASSOCREQIE:
if (custom + iwe->u.data.length > end) {
static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
- void *ctx, char *buf, size_t len,
- int del)
+ char *buf, size_t len, int del)
{
union wpa_event_data event;
drv->if_removed = 0;
}
- wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
}
static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
- struct nlmsghdr *h)
+ u8 *buf, size_t len)
{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
+ int attrlen, rta_len;
struct rtattr *attr;
- ifi = NLMSG_DATA(h);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return 0;
-
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ attrlen = len;
+ attr = (struct rtattr *) buf;
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
- int ifindex, struct nlmsghdr *h)
+ int ifindex, u8 *buf, size_t len)
{
if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
return 1;
- if (drv->if_removed && wpa_driver_wext_own_ifname(drv, h)) {
+ if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) {
drv->ifindex = if_nametoindex(drv->ifname);
wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
"interface");
}
-static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
- void *ctx, struct nlmsghdr *h,
- size_t len)
+static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr * attr;
-
- if (len < sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
+ struct wpa_driver_wext_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
- if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, h)) {
+ if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
ifi->ifi_index);
return;
(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)) {
+ 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()
if (drv->operstate == 1 &&
(ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
!(ifi->ifi_flags & IFF_RUNNING))
- wpa_driver_wext_send_oper_ifla(drv, -1, IF_OPER_UP);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ -1, IF_OPER_UP);
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return;
-
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ attrlen = len;
+ attr = (struct rtattr *) buf;
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_WIRELESS) {
wpa_driver_wext_event_wireless(
- drv, ctx, ((char *) attr) + rta_len,
+ drv, ((char *) attr) + rta_len,
attr->rta_len - rta_len);
} else if (attr->rta_type == IFLA_IFNAME) {
- wpa_driver_wext_event_link(drv, ctx,
+ wpa_driver_wext_event_link(drv,
((char *) attr) + rta_len,
attr->rta_len - rta_len, 0);
}
}
-static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv,
- void *ctx, struct nlmsghdr *h,
- size_t len)
+static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr * attr;
-
- if (len < sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return;
+ struct wpa_driver_wext_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ attrlen = len;
+ attr = (struct rtattr *) buf;
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_IFNAME) {
- wpa_driver_wext_event_link(drv, ctx,
+ wpa_driver_wext_event_link(drv,
((char *) attr) + rta_len,
attr->rta_len - rta_len, 1);
}
}
-static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx,
- void *sock_ctx)
-{
- char buf[8192];
- int left;
- struct sockaddr_nl from;
- socklen_t fromlen;
- struct nlmsghdr *h;
- int max_events = 10;
-
-try_again:
- fromlen = sizeof(from);
- left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *) &from, &fromlen);
- if (left < 0) {
- if (errno != EINTR && errno != EAGAIN)
- perror("recvfrom(netlink)");
- return;
- }
-
- h = (struct nlmsghdr *) buf;
- while (left >= (int) sizeof(*h)) {
- int len, plen;
-
- len = h->nlmsg_len;
- plen = len - sizeof(*h);
- if (len > left || plen < 0) {
- wpa_printf(MSG_DEBUG, "Malformed netlink message: "
- "len=%d left=%d plen=%d",
- len, left, plen);
- break;
- }
-
- switch (h->nlmsg_type) {
- case RTM_NEWLINK:
- wpa_driver_wext_event_rtm_newlink(eloop_ctx, sock_ctx,
- h, plen);
- break;
- case RTM_DELLINK:
- wpa_driver_wext_event_rtm_dellink(eloop_ctx, sock_ctx,
- h, plen);
- break;
- }
-
- len = NLMSG_ALIGN(len);
- left -= len;
- h = (struct nlmsghdr *) ((char *) h + len);
- }
-
- if (left > 0) {
- wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
- "message", left);
- }
-
- if (--max_events > 0) {
- /*
- * Try to receive all events in one eloop call in order to
- * limit race condition on cases where AssocInfo event, Assoc
- * event, and EAPOL frames are received more or less at the
- * same time. We want to process the event messages first
- * before starting EAPOL processing.
- */
- goto try_again;
- }
-}
-
-
-static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv,
- const char *ifname, int *flags)
-{
- 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_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_blocked(void *ctx)
{
- return wpa_driver_wext_get_ifflags_ifname(drv, drv->ifname, flags);
-}
-
-
-static int wpa_driver_wext_set_ifflags_ifname(struct wpa_driver_wext_data *drv,
- const char *ifname, int flags)
-{
- struct ifreq ifr;
-
- 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;
- }
- return 0;
-}
-
-
-#ifdef CONFIG_CLIENT_MLME
-
-static int wpa_driver_prism2_param_set(struct wpa_driver_wext_data *drv,
- int param, int value)
-{
- struct iwreq iwr;
- int *i;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- i = (int *) iwr.u.name;
- *i++ = param;
- *i++ = value;
-
- return ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr);
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked");
+ /*
+ * This may be for any interface; use ifdown event to disable
+ * interface.
+ */
}
-static int wpa_driver_prism2_param_get(struct wpa_driver_wext_data *drv,
- int param)
+static void wpa_driver_wext_rfkill_unblocked(void *ctx)
{
- struct iwreq iwr;
- int *i;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- i = (int *) iwr.u.name;
- *i = param;
-
- if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_GET_PRISM2_PARAM, &iwr) < 0) {
- perror("ioctl[PRISM2_IOCTL_GET_PRISM2_PARAM]");
- return -1;
+ 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;
}
-
- return *i;
-}
-
-#endif /* CONFIG_CLIENT_MLME */
-
-
-/**
- * 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);
+ /* rtnetlink ifup handler will report interface as enabled */
}
*/
void * wpa_driver_wext_init(void *ctx, const char *ifname)
{
- int s;
- struct sockaddr_nl local;
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;
+ }
+
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
perror("socket(PF_INET,SOCK_DGRAM)");
- os_free(drv);
- return NULL;
+ goto err1;
+ }
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ goto err1;
+ cfg->ctx = drv;
+ cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;
+ cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;
+ drv->netlink = netlink_init(cfg);
+ if (drv->netlink == NULL) {
+ os_free(cfg);
+ 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);
}
- s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (s < 0) {
- perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
+ drv->mlme_sock = -1;
- os_memset(&local, 0, sizeof(local));
- local.nl_family = AF_NETLINK;
- local.nl_groups = RTMGRP_LINK;
- if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
- perror("bind(netlink)");
- close(s);
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
+ if (wpa_driver_wext_finish_drv_init(drv) < 0)
+ goto err3;
- eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx);
- drv->event_sock = s;
+ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
- drv->mlme_sock = -1;
+ return drv;
+
+err3:
+ rfkill_deinit(drv->rfkill);
+ netlink_deinit(drv->netlink);
+err2:
+ close(drv->ioctl_sock);
+err1:
+ os_free(drv);
+ return NULL;
+}
- wpa_driver_wext_finish_drv_init(drv);
- return drv;
+static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
}
-static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
{
- int flags;
-
- if (wpa_driver_wext_get_ifflags(drv, &flags) != 0)
- printf("Could not get interface '%s' flags\n", drv->ifname);
- else if (!(flags & IFF_UP)) {
- if (wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) {
- printf("Could not set interface '%s' UP\n",
- drv->ifname);
+ 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;
}
}
wpa_driver_wext_flush_pmkid(drv);
if (wpa_driver_wext_set_mode(drv, 0) < 0) {
- printf("Could not configure driver to use managed mode\n");
+ wpa_printf(MSG_DEBUG, "Could not configure driver to use "
+ "managed mode");
+ /* Try to use it anyway */
}
wpa_driver_wext_get_range(drv);
+ /*
+ * Unlock the driver's BSSID and force to a random SSID to clear any
+ * previous association the driver might have when the supplicant
+ * starts up.
+ */
+ wpa_driver_wext_disconnect(drv);
+
drv->ifindex = if_nametoindex(drv->ifname);
if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
wpa_driver_wext_alternative_ifindex(drv, ifname2);
}
- wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+ 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);
eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
* Clear possibly configured driver parameters in order to make it
* easier to use the driver after wpa_supplicant has been terminated.
*/
- (void) wpa_driver_wext_set_bssid(drv,
- (u8 *) "\x00\x00\x00\x00\x00\x00");
+ wpa_driver_wext_disconnect(drv);
- wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP);
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
+ netlink_deinit(drv->netlink);
+ rfkill_deinit(drv->rfkill);
- eloop_unregister_read_sock(drv->event_sock);
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);
-
-#ifdef CONFIG_CLIENT_MLME
- if (drv->mlmedev[0]) {
- if (wpa_driver_wext_get_ifflags_ifname(drv, drv->mlmedev,
- &flags) == 0)
- (void) wpa_driver_wext_set_ifflags_ifname(
- drv, drv->mlmedev, flags & ~IFF_UP);
- wpa_driver_prism2_param_set(drv, PRISM2_PARAM_MGMT_IF, 0);
- wpa_driver_prism2_param_set(drv, PRISM2_PARAM_USER_SPACE_MLME,
- 0);
- }
-#endif /* CONFIG_CLIENT_MLME */
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
- close(drv->event_sock);
close(drv->ioctl_sock);
if (drv->mlme_sock >= 0)
close(drv->mlme_sock);
/**
* wpa_driver_wext_scan - Request the driver to initiate scan
* @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
- * all SSIDs (either active scan with broadcast SSID or passive
- * scan
- * @ssid_len: Length of the SSID
+ * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.)
* Returns: 0 on success, -1 on failure
*/
-int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len)
+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
int ret = 0, timeout;
struct iw_scan_req req;
+ const u8 *ssid = params->ssids[0].ssid;
+ size_t ssid_len = params->ssids[0].ssid_len;
if (ssid_len > IW_ESSID_MAX_SIZE) {
wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
break;
- if (errno == E2BIG && res_buf_len < 100000) {
+ if (errno == E2BIG && res_buf_len < 65535) {
os_free(res_buf);
res_buf = NULL;
res_buf_len *= 2;
+ if (res_buf_len > 65535)
+ res_buf_len = 65535; /* 16-bit length field */
wpa_printf(MSG_DEBUG, "Scan results did not fit - "
"trying larger buffer (%lu bytes)",
(unsigned long) res_buf_len);
}
-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.noise = iwe->u.qual.noise;
res->res.level = iwe->u.qual.level;
+ if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID)
+ res->res.flags |= WPA_SCAN_QUAL_INVALID;
+ if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID)
+ res->res.flags |= WPA_SCAN_LEVEL_INVALID;
+ if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID)
+ 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);
}
}
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_CCMP;
if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ drv->capa.max_scan_ssids = 1;
wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
"flags 0x%x",
"assuming WPA is not supported");
}
+ drv->max_level = range->max_qual.level;
+
os_free(range);
return 0;
}
-static int wpa_driver_wext_set_wpa(void *priv, int enabled)
-{
- struct wpa_driver_wext_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- return wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
- enabled);
-}
-
-
static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
const u8 *psk)
{
}
-static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg,
+static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
const u8 *addr, int key_idx,
int set_tx, const u8 *seq,
size_t seq_len,
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
if (alg == WPA_ALG_NONE)
iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
iwr.u.encoding.pointer = (caddr_t) ext;
case WPA_ALG_PMK:
ext->alg = IW_ENCODE_ALG_PMK;
break;
-#ifdef WEXT_MFP_PENDING
#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
ext->alg = IW_ENCODE_ALG_AES_CMAC;
break;
#endif /* CONFIG_IEEE80211W */
-#endif /* WEXT_MFP_PENDING */
default:
wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
__FUNCTION__, alg);
* This function uses SIOCSIWENCODEEXT by default, but tries to use
* SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
*/
-int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
+int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
const u8 *addr, int key_idx,
int set_tx, const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
if (alg == WPA_ALG_NONE)
iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
iwr.u.encoding.pointer = (caddr_t) key;
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
iwr.u.encoding.pointer = (caddr_t) NULL;
iwr.u.encoding.length = 0;
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
}
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
+{
+ struct iwreq iwr;
+ const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ u8 ssid[32];
+ int i;
+
+ /*
+ * Only force-disconnect when the card is in infrastructure mode,
+ * otherwise the driver might interpret the cleared BSSID and random
+ * SSID as an attempt to create a new ad-hoc network.
+ */
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWMODE]");
+ iwr.u.mode = IW_MODE_INFRA;
+ }
+
+ if (iwr.u.mode == IW_MODE_INFRA) {
+ if (drv->cfg80211) {
+ /*
+ * cfg80211 supports SIOCSIWMLME commands, so there is
+ * no need for the random SSID hack, but clear the
+ * BSSID and SSID.
+ */
+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
+ wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
+ "to 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).
+ */
+ for (i = 0; i < 32; i++)
+ ssid[i] = rand() & 0xFF;
+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
+ wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
+ "BSSID/SSID to disconnect");
+ }
+ }
+}
+
+
static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
int reason_code)
{
struct wpa_driver_wext_data *drv = priv;
+ int ret;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ return ret;
}
int reason_code)
{
struct wpa_driver_wext_data *drv = priv;
+ int ret;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC,
- reason_code);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ return ret;
}
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.
+ */
+ wpa_driver_wext_set_ssid(drv, (u8 *) "", 0);
+ }
+
+ if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
+ < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
+ ret = -1;
+
/*
* If the driver did not support SIOCSIWAUTH, fallback to
* SIOCSIWENCODE here.
IW_AUTH_RX_UNENCRYPTED_EAPOL,
allow_unencrypted_eapol) < 0)
ret = -1;
-#ifdef WEXT_MFP_PENDING
#ifdef CONFIG_IEEE80211W
switch (params->mgmt_frame_protection) {
case NO_MGMT_FRAME_PROTECTION:
if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
ret = -1;
#endif /* CONFIG_IEEE80211W */
-#endif /* WEXT_MFP_PENDING */
if (params->freq && wpa_driver_wext_set_freq(drv, params->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:
wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
__func__, drv->operstate, state, state ? "UP" : "DORMANT");
drv->operstate = state;
- return wpa_driver_wext_send_oper_ifla(
- drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
-}
-
-
-#ifdef CONFIG_CLIENT_MLME
-static int hostapd_ioctl(struct wpa_driver_wext_data *drv,
- struct prism2_hostapd_param *param, int len)
-{
- struct iwreq iwr;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (caddr_t) param;
- iwr.u.data.length = len;
-
- if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
- perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
- return -1;
- }
-
- return 0;
-}
-
-
-static struct wpa_hw_modes *
-wpa_driver_wext_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
- struct wpa_driver_wext_data *drv = priv;
- struct prism2_hostapd_param *param;
- u8 *pos, *end;
- struct wpa_hw_modes *modes = NULL;
- int i;
-
- param = os_zalloc(PRISM2_HOSTAPD_MAX_BUF_SIZE);
- if (param == NULL)
- return NULL;
- param->cmd = PRISM2_HOSTAPD_GET_HW_FEATURES;
-
- if (hostapd_ioctl(drv, param, PRISM2_HOSTAPD_MAX_BUF_SIZE) < 0) {
- perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
- goto out;
- }
-
- *num_modes = param->u.hw_features.num_modes;
- *flags = param->u.hw_features.flags;
-
- pos = param->u.hw_features.data;
- end = pos + PRISM2_HOSTAPD_MAX_BUF_SIZE -
- (param->u.hw_features.data - (u8 *) param);
-
- modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes));
- if (modes == NULL)
- goto out;
-
- for (i = 0; i < *num_modes; i++) {
- struct hostapd_ioctl_hw_modes_hdr *hdr;
- struct wpa_hw_modes *feature;
- int clen, rlen;
-
- hdr = (struct hostapd_ioctl_hw_modes_hdr *) pos;
- pos = (u8 *) (hdr + 1);
- clen = hdr->num_channels * sizeof(struct wpa_channel_data);
- rlen = hdr->num_rates * sizeof(struct wpa_rate_data);
-
- feature = &modes[i];
- switch (hdr->mode) {
- case MODE_IEEE80211A:
- feature->mode = WPA_MODE_IEEE80211A;
- break;
- case MODE_IEEE80211B:
- feature->mode = WPA_MODE_IEEE80211B;
- break;
- case MODE_IEEE80211G:
- feature->mode = WPA_MODE_IEEE80211G;
- break;
- case MODE_ATHEROS_TURBO:
- case MODE_ATHEROS_TURBOG:
- wpa_printf(MSG_ERROR, "Skip unsupported hw_mode=%d in "
- "get_hw_features data", hdr->mode);
- pos += clen + rlen;
- continue;
- default:
- wpa_printf(MSG_ERROR, "Unknown hw_mode=%d in "
- "get_hw_features data", hdr->mode);
- wpa_supplicant_sta_free_hw_features(modes, *num_modes);
- modes = NULL;
- break;
- }
- feature->num_channels = hdr->num_channels;
- feature->num_rates = hdr->num_rates;
-
- feature->channels = os_malloc(clen);
- feature->rates = os_malloc(rlen);
- if (!feature->channels || !feature->rates ||
- pos + clen + rlen > end) {
- wpa_supplicant_sta_free_hw_features(modes, *num_modes);
- modes = NULL;
- break;
- }
-
- os_memcpy(feature->channels, pos, clen);
- pos += clen;
- os_memcpy(feature->rates, pos, rlen);
- pos += rlen;
- }
-
-out:
- os_free(param);
- return modes;
-}
-
-
-int wpa_driver_wext_set_channel(void *priv, wpa_hw_mode phymode, int chan,
- int freq)
-{
- return wpa_driver_wext_set_freq(priv, freq);
-}
-
-
-static void wpa_driver_wext_mlme_read(int sock, void *eloop_ctx,
- void *sock_ctx)
-{
- struct wpa_driver_wext_data *drv = eloop_ctx;
- int len;
- unsigned char buf[3000];
- struct ieee80211_frame_info *fi;
- struct ieee80211_rx_status rx_status;
-
- len = recv(sock, buf, sizeof(buf), 0);
- if (len < 0) {
- perror("recv[MLME]");
- return;
- }
-
- if (len < (int) sizeof(struct ieee80211_frame_info)) {
- wpa_printf(MSG_DEBUG, "WEXT: Too short MLME frame (len=%d)",
- len);
- return;
- }
-
- fi = (struct ieee80211_frame_info *) buf;
- if (ntohl(fi->version) != IEEE80211_FI_VERSION) {
- wpa_printf(MSG_DEBUG, "WEXT: Invalid MLME frame info version "
- "0x%x", ntohl(fi->version));
- return;
- }
-
- os_memset(&rx_status, 0, sizeof(rx_status));
- rx_status.ssi = ntohl(fi->ssi_signal);
- rx_status.channel = ntohl(fi->channel);
-
- wpa_supplicant_sta_rx(drv->ctx,
- buf + sizeof(struct ieee80211_frame_info),
- len - sizeof(struct ieee80211_frame_info),
- &rx_status);
-}
-
-
-static int wpa_driver_wext_open_mlme(struct wpa_driver_wext_data *drv)
-{
- int flags, ifindex, s;
- struct sockaddr_ll addr;
- struct ifreq ifr;
-
- if (wpa_driver_prism2_param_set(drv, PRISM2_PARAM_USER_SPACE_MLME, 1) <
- 0) {
- wpa_printf(MSG_ERROR, "WEXT: Failed to configure driver to "
- "use user space MLME");
- return -1;
- }
-
- if (wpa_driver_prism2_param_set(drv, PRISM2_PARAM_MGMT_IF, 1) < 0) {
- wpa_printf(MSG_ERROR, "WEXT: Failed to add management "
- "interface for user space MLME");
- return -1;
- }
-
- ifindex = wpa_driver_prism2_param_get(drv, PRISM2_PARAM_MGMT_IF);
- if (ifindex <= 0) {
- wpa_printf(MSG_ERROR, "WEXT: MLME management device not "
- "found");
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = ifindex;
- if (ioctl(drv->ioctl_sock, SIOCGIFNAME, &ifr) != 0) {
- perror("ioctl(SIOCGIFNAME)");
- return -1;
- }
- os_strlcpy(drv->mlmedev, ifr.ifr_name, sizeof(drv->mlmedev));
- wpa_printf(MSG_DEBUG, "WEXT: MLME management device '%s'",
- drv->mlmedev);
-
- if (wpa_driver_wext_get_ifflags_ifname(drv, drv->mlmedev, &flags) != 0
- || wpa_driver_wext_set_ifflags_ifname(drv, drv->mlmedev,
- flags | IFF_UP) != 0) {
- wpa_printf(MSG_ERROR, "WEXT: Could not set interface "
- "'%s' UP", drv->mlmedev);
- return -1;
- }
-
- s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (s < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
- return -1;
- }
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sll_family = AF_PACKET;
- addr.sll_ifindex = ifindex;
-
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(MLME)");
- return -1;
- }
-
- if (eloop_register_read_sock(s, wpa_driver_wext_mlme_read, drv, NULL))
- {
- wpa_printf(MSG_ERROR, "WEXT: Could not register MLME read "
- "socket");
- close(s);
- return -1;
- }
-
- return s;
-}
-
-
-static int wpa_driver_wext_send_mlme(void *priv, const u8 *data,
- size_t data_len)
-{
- struct wpa_driver_wext_data *drv = priv;
- int ret;
-
- ret = send(drv->mlme_sock, data, data_len, 0);
- if (ret < 0) {
- perror("send[MLME]");
- return -1;
- }
-
- return 0;
-}
-
-
-static int wpa_driver_wext_mlme_add_sta(void *priv, const u8 *addr,
- const u8 *supp_rates,
- size_t supp_rates_len)
-{
- struct wpa_driver_wext_data *drv = priv;
- struct prism2_hostapd_param param;
- size_t len;
-
- os_memset(¶m, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_ADD_STA;
- os_memcpy(param.sta_addr, addr, ETH_ALEN);
- len = supp_rates_len;
- if (len > sizeof(param.u.add_sta.supp_rates))
- len = sizeof(param.u.add_sta.supp_rates);
- os_memcpy(param.u.add_sta.supp_rates, supp_rates, len);
- return hostapd_ioctl(drv, ¶m, sizeof(param));
-}
-
-
-static int wpa_driver_wext_mlme_remove_sta(void *priv, const u8 *addr)
-{
- struct wpa_driver_wext_data *drv = priv;
- struct prism2_hostapd_param param;
-
- os_memset(¶m, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
- os_memcpy(param.sta_addr, addr, ETH_ALEN);
- return hostapd_ioctl(drv, ¶m, sizeof(param));
-}
-
-#endif /* CONFIG_CLIENT_MLME */
-
-
-static int wpa_driver_wext_set_param(void *priv, const char *param)
-{
-#ifdef CONFIG_CLIENT_MLME
- struct wpa_driver_wext_data *drv = priv;
-
- if (param == NULL)
- return 0;
-
- wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
-
- if (os_strstr(param, "use_mlme=1")) {
- wpa_printf(MSG_DEBUG, "WEXT: Using user space MLME");
- drv->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
-
- drv->mlme_sock = wpa_driver_wext_open_mlme(drv);
- if (drv->mlme_sock < 0)
- return -1;
- }
-#endif /* CONFIG_CLIENT_MLME */
-
- return 0;
+ return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+ state ? IF_OPER_UP : IF_OPER_DORMANT);
}
.desc = "Linux wireless extensions (generic)",
.get_bssid = wpa_driver_wext_get_bssid,
.get_ssid = wpa_driver_wext_get_ssid,
- .set_wpa = wpa_driver_wext_set_wpa,
.set_key = wpa_driver_wext_set_key,
.set_countermeasures = wpa_driver_wext_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
- .scan = wpa_driver_wext_scan,
+ .scan2 = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
.disassociate = wpa_driver_wext_disassociate,
- .set_mode = wpa_driver_wext_set_mode,
.associate = wpa_driver_wext_associate,
- .set_auth_alg = wpa_driver_wext_set_auth_alg,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
- .set_param = wpa_driver_wext_set_param,
.add_pmkid = wpa_driver_wext_add_pmkid,
.remove_pmkid = wpa_driver_wext_remove_pmkid,
.flush_pmkid = wpa_driver_wext_flush_pmkid,
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
-#ifdef CONFIG_CLIENT_MLME
- .get_hw_feature_data = wpa_driver_wext_get_hw_feature_data,
- .set_channel = wpa_driver_wext_set_channel,
- .set_ssid = wpa_driver_wext_set_ssid,
- .set_bssid = wpa_driver_wext_set_bssid,
- .send_mlme = wpa_driver_wext_send_mlme,
- .mlme_add_sta = wpa_driver_wext_mlme_add_sta,
- .mlme_remove_sta = wpa_driver_wext_mlme_remove_sta,
-#endif /* CONFIG_CLIENT_MLME */
};