/*
* Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
#include "nl80211_copy.h"
#include "common.h"
-#include "driver.h"
#include "eloop.h"
#include "common/ieee802_11_defs.h"
-
-#if defined(CONFIG_AP) || defined(HOSTAPD)
-#include <netpacket/packet.h>
-#include <linux/filter.h>
+#include "netlink.h"
#include "radiotap.h"
#include "radiotap_iter.h"
-#endif /* CONFIG_AP || HOSTAPD */
+#include "driver.h"
#ifdef CONFIG_LIBNL20
/* libnl 2.0 compatibility code */
struct wpa_driver_nl80211_data {
void *ctx;
- int link_event_sock;
+ struct netlink_data *netlink;
int ioctl_sock; /* socket for ioctl() use */
char ifname[IFNAMSIZ + 1];
int ifindex;
size_t ssid_len;
int nlmode;
int ap_scan_as_station;
+ unsigned int assoc_freq;
int monitor_sock;
int monitor_ifidx;
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code);
-
-#if defined(CONFIG_AP) || defined(HOSTAPD)
static void nl80211_remove_monitor_interface(
struct wpa_driver_nl80211_data *drv);
-#endif /* CONFIG_AP || HOSTAPD */
-
-#ifdef CONFIG_AP
-static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
- int ifidx);
-#endif /* CONFIG_AP */
#ifdef HOSTAPD
static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
static struct i802_bss * get_bss(struct wpa_driver_nl80211_data *drv,
int ifindex);
-static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
- int ifidx);
static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static int wpa_driver_nl80211_if_remove(void *priv,
+ enum wpa_driver_if_type type,
+ const char *ifname);
#endif /* HOSTAPD */
#endif /* HOSTAPD */
-static int wpa_driver_nl80211_send_oper_ifla(
- struct wpa_driver_nl80211_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 = aliasing_hide_typecast(
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
- struct rtattr);
- 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 = aliasing_hide_typecast(
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
- struct rtattr);
- 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, "nl80211: Operstate: linkmode=%d, operstate=%d",
- linkmode, operstate);
-
- ret = send(drv->link_event_sock, &req, req.hdr.nlmsg_len, 0);
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Sending operstate IFLA failed:"
- " %s (assume operstate is not supported)",
- strerror(errno));
- }
-
- return ret < 0 ? -1 : 0;
-}
-
-
static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
{
struct wpa_driver_nl80211_data *drv = priv;
}
-#ifndef HOSTAPD
-
static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_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_nl80211_own_ifname(struct wpa_driver_nl80211_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_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
- int ifindex, struct nlmsghdr *h)
+ int ifindex, u8 *buf, size_t len)
{
if (drv->ifindex == ifindex)
return 1;
- if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, h)) {
+ if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
drv->ifindex = if_nametoindex(drv->ifname);
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
}
-static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
- void *ctx, struct nlmsghdr *h,
- size_t len)
+static void wpa_driver_nl80211_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_nl80211_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
- if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, h)) {
+ if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len)) {
wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
ifi->ifi_index);
return;
if (drv->operstate == 1 &&
(ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
!(ifi->ifi_flags & IFF_RUNNING))
- wpa_driver_nl80211_send_oper_ifla(drv, -1, IF_OPER_UP);
-
- _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - _nlmsg_len;
- if (attrlen < 0)
- return;
-
- attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ -1, IF_OPER_UP);
+ 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_nl80211_event_link(
- drv, ctx,
+ drv,
((char *) attr) + rta_len,
attr->rta_len - rta_len, 0);
}
}
-static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv,
- void *ctx, struct nlmsghdr *h,
- size_t len)
+static void wpa_driver_nl80211_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_nl80211_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_nl80211_event_link(
- drv, ctx,
+ drv,
((char *) attr) + rta_len,
attr->rta_len - rta_len, 1);
}
}
-static void wpa_driver_nl80211_event_receive_link(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_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx,
- h, plen);
- break;
- case RTM_DELLINK:
- wpa_driver_nl80211_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;
- }
-}
-
-#endif /* HOSTAPD */
-
-
static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
const u8 *frame, size_t len)
{
len - 24 - sizeof(mgmt->u.assoc_resp);
}
+ event.assoc_info.freq = drv->assoc_freq;
+
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
}
+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+ struct nlattr *tb[])
+{
+ union wpa_event_data event;
+ struct nlattr *nl;
+ int rem;
+ struct scan_info *info;
+#define MAX_REPORT_FREQS 50
+ int freqs[MAX_REPORT_FREQS];
+ int num_freqs = 0;
+
+ os_memset(&event, 0, sizeof(event));
+ info = &event.scan_info;
+ info->aborted = aborted;
+
+ if (tb[NL80211_ATTR_SCAN_SSIDS]) {
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
+ struct wpa_driver_scan_ssid *s =
+ &info->ssids[info->num_ssids];
+ s->ssid = nla_data(nl);
+ s->ssid_len = nla_len(nl);
+ info->num_ssids++;
+ if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+ break;
+ }
+ }
+ if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
+ {
+ freqs[num_freqs] = nla_get_u32(nl);
+ num_freqs++;
+ if (num_freqs == MAX_REPORT_FREQS - 1)
+ break;
+ }
+ info->freqs = freqs;
+ info->num_freqs = num_freqs;
+ }
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+}
+
+
static int process_event(struct nl_msg *msg, void *arg)
{
struct wpa_driver_nl80211_data *drv = arg;
drv->scan_complete_events = 1;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx);
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ send_scan_event(drv, 0, tb);
break;
case NL80211_CMD_SCAN_ABORTED:
wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
*/
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx);
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ send_scan_event(drv, 1, tb);
break;
case NL80211_CMD_AUTHENTICATE:
case NL80211_CMD_ASSOCIATE:
WPA_DRIVER_CAPA_ENC_WEP104 |
WPA_DRIVER_CAPA_ENC_TKIP |
WPA_DRIVER_CAPA_ENC_CCMP;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
drv->capa.max_scan_ssids = info.max_scan_ssids;
if (info.ap_supported)
}
-static int wpa_driver_nl80211_init_link_events(
- struct wpa_driver_nl80211_data *drv)
-{
-#ifdef HOSTAPD
- return 0;
-#else /* HOSTAPD */
- int s;
- struct sockaddr_nl local;
-
- s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (s < 0) {
- perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
- return -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);
- return -1;
- }
-
- eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_link, drv,
- drv->ctx);
- drv->link_event_sock = s;
-
- return 0;
-#endif /* HOSTAPD */
-}
-
-
/**
* wpa_driver_nl80211_init - Initialize nl80211 driver interface
* @ctx: context to be used when calling wpa_supplicant functions,
static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
{
struct wpa_driver_nl80211_data *drv;
+ struct netlink_config *cfg;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
drv->monitor_ifidx = -1;
drv->monitor_sock = -1;
- drv->link_event_sock = -1;
drv->ioctl_sock = -1;
if (wpa_driver_nl80211_init_nl(drv, ctx)) {
goto failed;
}
- if (wpa_driver_nl80211_init_link_events(drv) ||
- wpa_driver_nl80211_finish_drv_init(drv))
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ goto failed;
+ cfg->ctx = drv;
+ cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+ cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+ drv->netlink = netlink_init(cfg);
+ if (drv->netlink == NULL) {
+ os_free(cfg);
+ goto failed;
+ }
+ if (wpa_driver_nl80211_finish_drv_init(drv))
goto failed;
return drv;
failed:
- if (drv->link_event_sock >= 0) {
- eloop_unregister_read_sock(drv->link_event_sock);
- close(drv->link_event_sock);
- }
+ netlink_deinit(drv->netlink);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
if (wpa_driver_nl80211_capa(drv))
return -1;
- wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ 1, IF_OPER_DORMANT);
#endif /* HOSTAPD */
return 0;
#endif /* HOSTAPD */
-#if defined(CONFIG_AP) || defined(HOSTAPD)
static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
{
struct nl_msg *msg;
nla_put_failure:
return -ENOBUFS;
}
-#endif /* CONFIG_AP || HOSTAPD */
/**
{
struct wpa_driver_nl80211_data *drv = priv;
-#if defined(CONFIG_AP) || defined(HOSTAPD)
nl80211_remove_monitor_interface(drv);
if (drv->monitor_sock >= 0) {
eloop_unregister_read_sock(drv->monitor_sock);
if (drv->nlmode == NL80211_IFTYPE_AP)
wpa_driver_nl80211_del_beacon(drv);
-#endif /* CONFIG_AP || HOSTAPD */
#ifdef HOSTAPD
if (drv->last_freq_ht) {
os_free(drv->if_indices);
wpa_driver_nl80211_free_bss(drv);
-#else /* HOSTAPD */
-
- wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
-
- if (drv->link_event_sock >= 0) {
- eloop_unregister_read_sock(drv->link_event_sock);
- close(drv->link_event_sock);
- }
#endif /* HOSTAPD */
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
+ netlink_deinit(drv->netlink);
+
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
(void) hostapd_set_iface_flags(drv, drv->ifname, 0);
static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
- wpa_alg alg, const u8 *addr, int key_idx,
- int set_tx,
+ 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)
{
}
-static int nl_add_key(struct nl_msg *msg, wpa_alg alg,
+static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
int key_idx, int defkey,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
}
-#if defined(CONFIG_AP) || defined(HOSTAPD)
-
struct phy_info_arg {
u16 *num_modes;
struct hostapd_hw_modes *modes;
return NL_SKIP;
nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
- mode = realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
+ mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
if (!mode)
return NL_SKIP;
phy_info->modes = mode;
mode->num_channels++;
}
- mode->channels = calloc(mode->num_channels, sizeof(struct hostapd_channel_data));
+ mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
if (!mode->channels)
return NL_SKIP;
mode->num_rates++;
}
- mode->rates = calloc(mode->num_rates, sizeof(int));
+ mode->rates = os_zalloc(mode->num_rates * sizeof(int));
if (!mode->rates)
return NL_SKIP;
return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
}
-#endif /* CONFIG_AP || HOSTAPD */
-
static int wpa_driver_nl80211_set_beacon(const char *ifname, void *priv,
const u8 *head, size_t head_len,
}
-#if defined(CONFIG_AP) || defined(HOSTAPD)
-
static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
int freq, int ht_enabled,
int sec_channel_offset)
return -ENOBUFS;
}
-#endif /* CONFIG_AP || HOSTAPD */
-
static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
int ifidx)
{
struct nl_msg *msg;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
+
#ifdef HOSTAPD
/* stop listening for EAPOL on this interface */
del_ifidx(drv, ifidx);
static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
const char *ifname,
enum nl80211_iftype iftype,
- const u8 *addr)
+ const u8 *addr, int wds)
{
struct nl_msg *msg, *flags = NULL;
int ifidx;
if (err)
goto nla_put_failure;
+ } else if (wds) {
+ NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
}
ifidx = if_nametoindex(ifname);
+ wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
+ ifname, ifidx);
if (ifidx <= 0)
return -1;
static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
const char *ifname, enum nl80211_iftype iftype,
- const u8 *addr)
+ const u8 *addr, int wds)
{
int ret;
- ret = nl80211_create_iface_once(drv, ifname, iftype, addr);
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
/* if error occured and interface exists already */
if (ret == -ENFILE && if_nametoindex(ifname)) {
nl80211_remove_iface(drv, if_nametoindex(ifname));
/* Try to create the interface again */
- ret = nl80211_create_iface_once(drv, ifname, iftype, addr);
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
+ wds);
}
return ret;
}
-#ifdef CONFIG_AP
-
-void ap_tx_status(void *ctx, const u8 *addr,
- const u8 *buf, size_t len, int ack);
-void ap_rx_from_unknown_sta(void *ctx, struct ieee80211_hdr *hdr, size_t len);
-void ap_mgmt_rx(void *ctx, u8 *buf, size_t len, u16 stype,
- struct hostapd_frame_info *fi);
-void ap_mgmt_tx_cb(void *ctx, u8 *buf, size_t len, u16 stype, int ok);
-
-#endif /* CONFIG_AP */
-
-#if defined(CONFIG_AP) || defined(HOSTAPD)
-
static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
{
struct ieee80211_hdr *hdr;
- u16 fc, type, stype;
+ u16 fc;
+ union wpa_event_data event;
hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control);
- type = WLAN_FC_GET_TYPE(fc);
- stype = WLAN_FC_GET_STYPE(fc);
-
- switch (type) {
- case WLAN_FC_TYPE_MGMT:
- wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s",
- ok ? "ACK" : "fail");
-#ifdef HOSTAPD
- hostapd_mgmt_tx_cb(ctx, buf, len, stype, ok);
-#else /* HOSTAPD */
- ap_mgmt_tx_cb(ctx, buf, len, stype, ok);
-#endif /* HOSTAPD */
- break;
- case WLAN_FC_TYPE_CTRL:
- wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s",
- ok ? "ACK" : "fail");
- break;
- case WLAN_FC_TYPE_DATA:
-#ifdef HOSTAPD
- hostapd_tx_status(ctx, hdr->addr1, buf, len, ok);
-#else /* HOSTAPD */
- ap_tx_status(ctx, hdr->addr1, buf, len, ok);
-#endif /* HOSTAPD */
- break;
- default:
- wpa_printf(MSG_DEBUG, "unknown TX callback frame type %d",
- type);
- break;
- }
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = buf;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ok;
+ wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
}
static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
- struct ieee80211_hdr *hdr, size_t len)
+ u8 *buf, size_t len)
{
-#ifdef HOSTAPD
- hostapd_rx_from_unknown_sta(drv->ctx, hdr, len);
-#else /* HOSTAPD */
- ap_rx_from_unknown_sta(drv->ctx, hdr, len);
-#endif /* HOSTAPD */
+ union wpa_event_data event;
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.frame = buf;
+ event.rx_from_unknown.len = len;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
}
static void handle_frame(struct wpa_driver_nl80211_data *drv,
- u8 *buf, size_t len,
- struct hostapd_frame_info *hfi)
+ u8 *buf, size_t len, int datarate, int ssi_signal)
{
struct ieee80211_hdr *hdr;
- u16 fc, stype;
+ u16 fc;
+ union wpa_event_data event;
hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control);
- stype = WLAN_FC_GET_STYPE(fc);
switch (WLAN_FC_GET_TYPE(fc)) {
case WLAN_FC_TYPE_MGMT:
- if (stype != WLAN_FC_STYPE_BEACON &&
- stype != WLAN_FC_STYPE_PROBE_REQ)
- wpa_printf(MSG_MSGDUMP, "MGMT");
-#ifdef HOSTAPD
- hostapd_mgmt_rx(drv->ctx, buf, len, stype, hfi);
-#else /* HOSTAPD */
- ap_mgmt_rx(drv->ctx, buf, len, stype, hfi);
-#endif /* HOSTAPD */
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.datarate = datarate;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
break;
case WLAN_FC_TYPE_CTRL:
/* can only get here with PS-Poll frames */
wpa_printf(MSG_DEBUG, "CTRL");
- from_unknown_sta(drv, hdr, len);
+ from_unknown_sta(drv, buf, len);
break;
case WLAN_FC_TYPE_DATA:
- from_unknown_sta(drv, hdr, len);
+ from_unknown_sta(drv, buf, len);
break;
}
}
unsigned char buf[3000];
struct ieee80211_radiotap_iterator iter;
int ret;
- struct hostapd_frame_info hfi;
+ int datarate = 0, ssi_signal = 0;
int injected = 0, failed = 0, rxflags = 0;
len = recv(sock, buf, sizeof(buf), 0);
return;
}
- memset(&hfi, 0, sizeof(hfi));
-
while (1) {
ret = ieee80211_radiotap_iterator_next(&iter);
if (ret == -ENOENT)
case IEEE80211_RADIOTAP_DATA_RETRIES:
break;
case IEEE80211_RADIOTAP_CHANNEL:
- /* TODO convert from freq/flags to channel number
- hfi.channel = XXX;
- */
+ /* TODO: convert from freq/flags to channel number */
break;
case IEEE80211_RADIOTAP_RATE:
- hfi.datarate = *iter.this_arg * 5;
+ datarate = *iter.this_arg * 5;
break;
case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
- hfi.ssi_signal = *iter.this_arg;
+ ssi_signal = *iter.this_arg;
break;
}
}
if (!injected)
handle_frame(drv, buf + iter.max_length,
- len - iter.max_length, &hfi);
+ len - iter.max_length, datarate, ssi_signal);
else
handle_tx_callback(drv->ctx, buf + iter.max_length,
len - iter.max_length, !failed);
#if 0
/*
- * drop non-data frames, WDS frames
+ * drop non-data frames
*/
/* load the lower byte of the frame control field */
BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
/* drop non-data frames */
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
+#endif
/* load the upper byte of the frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
/* mask off toDS/fromDS */
BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
- /* drop WDS frames */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, FAIL, 0),
-#endif
+ /* accept WDS frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
/*
* add header length to index
buf[IFNAMSIZ - 1] = '\0';
drv->monitor_ifidx =
- nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL);
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
+ 0);
if (drv->monitor_ifidx < 0)
return -1;
"failed: %d (%s)",
(unsigned long) len, errno, strerror(errno));
}
- free(hdr);
+ os_free(hdr);
return res;
}
return -ENOBUFS;
}
-#endif /* CONFIG_AP || HOSTAPD */
-
-#ifdef CONFIG_AP
static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
return 0;
}
-#endif /* CONFIG_AP */
static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
int ret = -1;
struct nl_msg *msg;
-#ifdef CONFIG_AP
if (params->mode == IEEE80211_MODE_AP)
return wpa_driver_nl80211_ap(drv, params);
-#endif /* CONFIG_AP */
if (params->mode == IEEE80211_MODE_IBSS)
return wpa_driver_nl80211_ibss(drv, params);
if (params->freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
- }
+ drv->assoc_freq = params->freq;
+ } else
+ drv->assoc_freq = 0;
if (params->ssid) {
wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
params->ssid, params->ssid_len);
}
if (nlmode == drv->nlmode) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
+ "requested mode - ignore error");
ret = 0;
goto done; /* Already in the requested mode */
}
ret = -1;
}
- if (!ret)
+ if (!ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
+ "interface is down");
drv->nlmode = nlmode;
+ }
done:
-#if defined(CONFIG_AP) || defined(HOSTAPD)
if (!ret && nlmode == NL80211_IFTYPE_AP) {
/* Setup additional AP mode functionality if needed */
if (drv->monitor_ifidx < 0 &&
/* Remove additional AP mode functionality */
nl80211_remove_monitor_interface(drv);
}
-#endif /* CONFIG_AP || HOSTAPD */
+
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
+ "from %d failed", nlmode, drv->nlmode);
return ret;
}
wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
__func__, drv->operstate, state, state ? "UP" : "DORMANT");
drv->operstate = state;
- return wpa_driver_nl80211_send_oper_ifla(
- drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
+ return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+ state ? IF_OPER_UP : IF_OPER_DORMANT);
}
else
old = NULL;
- drv->if_indices = realloc(old,
- sizeof(int) * (drv->num_if_indices + 1));
+ drv->if_indices = os_realloc(old,
+ sizeof(int) * (drv->num_if_indices + 1));
if (!drv->if_indices) {
if (!old)
drv->if_indices = drv->default_if_indices;
}
+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ char name[16];
+
+ os_snprintf(name, sizeof(name), "%s.sta%d", drv->ifname, aid);
+ if (val) {
+ if (nl80211_create_iface(priv, name, NL80211_IFTYPE_AP_VLAN,
+ NULL, 1) < 0)
+ return -1;
+ hostapd_set_iface_flags(drv, name, 1);
+ return i802_set_sta_vlan(priv, addr, name, 0);
+ } else {
+ i802_set_sta_vlan(priv, addr, drv->ifname, 0);
+ return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
+ name);
+ }
+}
+
+
static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
{
struct wpa_driver_nl80211_data *drv = eloop_ctx;
#endif /* HOSTAPD */
ifidx = nl80211_create_iface(drv, ifname,
- wpa_driver_nl80211_if_type(type), addr);
+ wpa_driver_nl80211_if_type(type), addr,
+ 0);
if (ifidx < 0) {
#ifdef HOSTAPD
os_free(bss);
.set_beacon = wpa_driver_nl80211_set_beacon,
.if_add = wpa_driver_nl80211_if_add,
.if_remove = wpa_driver_nl80211_if_remove,
-#if defined(CONFIG_AP) || defined(HOSTAPD)
.send_mlme = wpa_driver_nl80211_send_mlme,
.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
.sta_remove = wpa_driver_nl80211_sta_remove,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
-#endif /* CONFIG_AP || HOSTAPD */
#ifdef HOSTAPD
.hapd_init = i802_init,
.hapd_deinit = i802_deinit,
.set_short_slot_time = i802_set_short_slot_time,
.set_tx_queue_params = i802_set_tx_queue_params,
.set_sta_vlan = i802_set_sta_vlan,
+ .set_wds_sta = i802_set_wds_sta,
#endif /* HOSTAPD */
};