* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
- * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2009-2010, Atheros Communications
*
* 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
#endif
struct i802_bss {
+ struct wpa_driver_nl80211_data *drv;
struct i802_bss *next;
int ifindex;
+ char ifname[IFNAMSIZ + 1];
unsigned int beacon_set:1;
};
void *ctx;
struct netlink_data *netlink;
int ioctl_sock; /* socket for ioctl() use */
- char ifname[IFNAMSIZ + 1];
char brname[IFNAMSIZ];
int ifindex;
int if_removed;
int probe_req_report;
int disable_11b_rates;
- unsigned int beacon_set:1;
unsigned int pending_remain_on_chan:1;
+ unsigned int pending_send_action:1;
unsigned int added_bridge:1;
unsigned int added_if_into_bridge:1;
u64 remain_on_chan_cookie;
+ u64 send_action_cookie;
+
+ struct wpa_driver_scan_filter *filter_ssids;
+ size_t num_filter_ssids;
+
+ struct i802_bss first_bss;
#ifdef HOSTAPD
int eapol_sock; /* socket for EAPOL frames */
int *if_indices;
int num_if_indices;
- struct i802_bss bss;
-
int last_freq;
int last_freq_ht;
#endif /* HOSTAPD */
#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 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,
}
-static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
- struct nl_msg *msg,
- int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
+static int send_and_recv(struct wpa_driver_nl80211_data *drv,
+ struct nl_handle *nl_handle, struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
{
struct nl_cb *cb;
int err = -ENOMEM;
if (!cb)
goto out;
- err = nl_send_auto_complete(drv->nl_handle, msg);
+ err = nl_send_auto_complete(nl_handle, msg);
if (err < 0)
goto out;
valid_handler, valid_data);
while (err > 0)
- nl_recvmsgs(drv->nl_handle, cb);
+ nl_recvmsgs(nl_handle, cb);
out:
nl_cb_put(cb);
nlmsg_free(msg);
}
+static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
+{
+ return send_and_recv(drv, drv->nl_handle, msg, valid_handler,
+ valid_data);
+}
+
+
struct family_data {
const char *group;
int id;
static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
if (!drv->associated)
return -1;
os_memcpy(bssid, drv->bssid, ETH_ALEN);
static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
if (!drv->associated)
return -1;
os_memcpy(ssid, drv->ssid, drv->ssid_len);
event.interface_status.ifname,
del ? "removed" : "added");
- if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
+ if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
if (del)
drv->if_removed = 1;
else
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_IFNAME) {
- if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
+ if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
== 0)
return 1;
else
return 1;
if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
- drv->ifindex = if_nametoindex(drv->ifname);
+ drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
wpa_driver_nl80211_finish_drv_init(drv);
}
+static void mlme_event_action(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *freq, const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 fc, stype;
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
+ return;
+ }
+
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_action.da = mgmt->da;
+ event.rx_action.sa = mgmt->sa;
+ event.rx_action.bssid = mgmt->bssid;
+ event.rx_action.category = mgmt->u.action.category;
+ event.rx_action.data = &mgmt->u.action.category + 1;
+ event.rx_action.len = frame + len - event.rx_action.data;
+ if (freq)
+ event.rx_action.freq = nla_get_u32(freq);
+ wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
+}
+
+
+static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *cookie, const u8 *frame,
+ size_t len, struct nlattr *ack)
+{
+ union wpa_event_data event;
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+ u64 cookie_val;
+
+ if (!cookie)
+ return;
+
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s",
+ (long long unsigned int) cookie_val,
+ cookie_val == drv->send_action_cookie ?
+ " (match)" : " (unknown)");
+ if (cookie_val != drv->send_action_cookie)
+ return;
+
+ hdr = (const struct ieee80211_hdr *) frame;
+ fc = le_to_host16(hdr->frame_control);
+
+ 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 = frame;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ack != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
+}
+
+
static void mlme_event(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, struct nlattr *frame,
- struct nlattr *addr, struct nlattr *timed_out)
+ struct nlattr *addr, struct nlattr *timed_out,
+ struct nlattr *freq, struct nlattr *ack,
+ struct nlattr *cookie)
{
if (timed_out && addr) {
mlme_timeout_event(drv, cmd, addr);
drv->associated = 0;
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
break;
+ case NL80211_CMD_ACTION:
+ mlme_event_action(drv, freq, nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_ACTION_TX_STATUS:
+ mlme_event_action_tx_status(drv, cookie, nla_data(frame),
+ nla_len(frame), ack);
+ break;
default:
break;
}
if (drv->ap_scan_as_station &&
(gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
- wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP);
+ wpa_driver_nl80211_set_mode(&drv->first_bss,
+ IEEE80211_MODE_AP);
drv->ap_scan_as_station = 0;
}
case NL80211_CMD_ASSOCIATE:
case NL80211_CMD_DEAUTHENTICATE:
case NL80211_CMD_DISASSOCIATE:
+ case NL80211_CMD_ACTION:
+ case NL80211_CMD_ACTION_TX_STATUS:
mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
- tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT]);
+ tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE]);
break;
case NL80211_CMD_CONNECT:
case NL80211_CMD_ROAM:
*/
static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
char alpha2[3];
struct nl_msg *msg;
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
0, NL80211_CMD_GET_WIPHY, 0);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
return 0;
{
struct wpa_driver_nl80211_data *drv;
struct netlink_config *cfg;
+ struct i802_bss *bss;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
drv->ctx = ctx;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ bss = &drv->first_bss;
+ bss->drv = drv;
+ os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
drv->monitor_ifidx = -1;
drv->monitor_sock = -1;
drv->ioctl_sock = -1;
if (wpa_driver_nl80211_finish_drv_init(drv))
goto failed;
- return drv;
+ return bss;
failed:
netlink_deinit(drv->netlink);
nl_cache_free(drv->nl_cache);
nl_handle_destroy(drv->nl_handle);
nl_cb_put(drv->nl_cb);
+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
os_free(drv);
return NULL;
}
+static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
+ const u8 *match, size_t match_len)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_REGISTER_ACTION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
+
+ ret = send_and_recv(drv, drv->nl_handle_event, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Register Action command "
+ "failed: ret=%d (%s)", ret, strerror(-ret));
+ wpa_hexdump(MSG_DEBUG, "nl80211: Register Action match",
+ match, match_len);
+ goto nla_put_failure;
+ }
+ ret = 0;
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
+{
+ if (0) {
+ /* Public Action frames */
+ return nl80211_register_action_frame(drv, (u8 *) "\x04", 1);
+ }
+ return 0;
+}
+
+
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
{
- drv->ifindex = if_nametoindex(drv->ifname);
+ struct i802_bss *bss = &drv->first_bss;
+
+ drv->ifindex = if_nametoindex(bss->ifname);
+ drv->first_bss.ifindex = drv->ifindex;
#ifndef HOSTAPD
- if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA) < 0) {
+ if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
"use managed mode");
}
- if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) {
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
wpa_printf(MSG_ERROR, "Could not set interface '%s' UP",
- drv->ifname);
+ bss->ifname);
return -1;
}
1, IF_OPER_DORMANT);
#endif /* HOSTAPD */
- return 0;
-}
-
+ if (nl80211_register_action_frames(drv) < 0)
+ return -1;
-#ifdef HOSTAPD
-static void wpa_driver_nl80211_free_bss(struct wpa_driver_nl80211_data *drv)
-{
- struct i802_bss *bss, *prev;
- bss = drv->bss.next;
- while (bss) {
- prev = bss;
- bss = bss->next;
- os_free(bss);
- }
+ return 0;
}
-#endif /* HOSTAPD */
static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
*/
static void wpa_driver_nl80211_deinit(void *priv)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
if (drv->added_if_into_bridge) {
- if (linux_br_del_if(drv->ioctl_sock, drv->brname, drv->ifname)
+ if (linux_br_del_if(drv->ioctl_sock, drv->brname, bss->ifname)
< 0)
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"interface %s from bridge %s: %s",
- drv->ifname, drv->brname, strerror(errno));
+ bss->ifname, drv->brname, strerror(errno));
}
if (drv->added_bridge) {
if (linux_br_del(drv->ioctl_sock, drv->brname) < 0)
if (drv->if_indices != drv->default_if_indices)
os_free(drv->if_indices);
-
- wpa_driver_nl80211_free_bss(drv);
#endif /* HOSTAPD */
if (drv->disable_11b_rates)
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
- (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
- wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA);
+ (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
+ wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
eloop_cancel_timeout(wpa_driver_nl80211_probe_req_report_timeout,
drv, NULL);
+ os_free(drv->filter_ssids);
+
os_free(drv);
}
{
struct wpa_driver_nl80211_data *drv = eloop_ctx;
if (drv->ap_scan_as_station) {
- wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP);
+ wpa_driver_nl80211_set_mode(&drv->first_bss,
+ IEEE80211_MODE_AP);
drv->ap_scan_as_station = 0;
}
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
static int wpa_driver_nl80211_scan(void *priv,
struct wpa_driver_scan_params *params)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = 0, timeout;
struct nl_msg *msg, *ssids, *freqs;
size_t i;
return -1;
}
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
NL80211_CMD_TRIGGER_SCAN, 0);
* mac80211 does not allow scan requests in AP mode, so
* try to do this in station mode.
*/
- if (wpa_driver_nl80211_set_mode(drv,
+ if (wpa_driver_nl80211_set_mode(bss,
IEEE80211_MODE_INFRA))
goto nla_put_failure;
if (wpa_driver_nl80211_scan(drv, params)) {
- wpa_driver_nl80211_set_mode(drv,
+ wpa_driver_nl80211_set_mode(bss,
IEEE80211_MODE_AP);
goto nla_put_failure;
}
}
+static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+{
+ const u8 *end, *pos;
+
+ if (ies == NULL)
+ return NULL;
+
+ pos = ies;
+ end = ies + ies_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == ie)
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
+static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
+ const u8 *ie, size_t ie_len)
+{
+ const u8 *ssid;
+ size_t i;
+
+ if (drv->filter_ssids == NULL)
+ return 0;
+
+ ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+ if (ssid == NULL)
+ return 1;
+
+ for (i = 0; i < drv->num_filter_ssids; i++) {
+ if (ssid[1] == drv->filter_ssids[i].ssid_len &&
+ os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
+ 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct nl80211_bss_info_arg {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_scan_results *res;
+};
+
static int bss_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
};
- struct wpa_scan_results *res = arg;
+ struct nl80211_bss_info_arg *_arg = arg;
+ struct wpa_scan_results *res = _arg->res;
struct wpa_scan_res **tmp;
struct wpa_scan_res *r;
const u8 *ie, *beacon_ie;
beacon_ie_len = 0;
}
+ if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+ ie ? ie_len : beacon_ie_len))
+ return NL_SKIP;
+
r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
if (r == NULL)
return NL_SKIP;
struct nl_msg *msg;
struct wpa_scan_results *res;
int ret;
+ struct nl80211_bss_info_arg arg;
res = os_zalloc(sizeof(*res));
if (res == NULL)
NL80211_CMD_GET_SCAN, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, res);
+ arg.drv = drv;
+ arg.res = res;
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
msg = NULL;
if (ret == 0) {
wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
static struct wpa_scan_results *
wpa_driver_nl80211_get_scan_results(void *priv)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct wpa_scan_results *res;
res = nl80211_get_scan_results(drv);
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
struct nl_msg *msg;
int ret;
static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
int reason_code)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
wpa_printf(MSG_DEBUG, "%s", __func__);
static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
int reason_code)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
wpa_printf(MSG_DEBUG, "%s", __func__);
static int wpa_driver_nl80211_authenticate(
void *priv, struct wpa_driver_auth_params *params)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1, i;
struct nl_msg *msg;
enum nl80211_auth_type type;
if (drv->nlmode != NL80211_IFTYPE_STATION)
wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
- if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA) < 0)
+ if (wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
return -1;
retry:
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
continue;
- wpa_driver_nl80211_set_key(drv->ifname, drv, WPA_ALG_WEP, NULL,
+ wpa_driver_nl80211_set_key(bss->ifname, drv, WPA_ALG_WEP, NULL,
i,
i == params->wep_tx_keyidx, NULL, 0,
params->wep_key[i],
static struct hostapd_hw_modes *
wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct phy_info_arg result = {
.num_modes = num_modes,
static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
size_t data_len)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt *mgmt;
int encrypt = 1;
u16 fc;
}
-static int wpa_driver_nl80211_set_beacon(const char *ifname, void *priv,
+static int wpa_driver_nl80211_set_beacon(void *priv,
const u8 *head, size_t head_len,
const u8 *tail, size_t tail_len,
int dtim_period, int beacon_int)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
u8 cmd = NL80211_CMD_NEW_BEACON;
int ret;
int beacon_set;
- int ifindex = if_nametoindex(ifname);
-#ifdef HOSTAPD
- struct i802_bss *bss;
+ int ifindex = if_nametoindex(bss->ifname);
- bss = get_bss(drv, ifindex);
- if (bss == NULL)
- return -ENOENT;
beacon_set = bss->beacon_set;
-#else /* HOSTAPD */
- beacon_set = drv->beacon_set;
-#endif /* HOSTAPD */
msg = nlmsg_alloc();
if (!msg)
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
ret, strerror(-ret));
} else {
-#ifdef HOSTAPD
bss->beacon_set = 1;
-#else /* HOSTAPD */
- drv->beacon_set = 1;
-#endif /* HOSTAPD */
}
return ret;
nla_put_failure:
}
-static int wpa_driver_nl80211_sta_add(const char *ifname, void *priv,
+static int wpa_driver_nl80211_sta_add(void *priv,
struct hostapd_sta_add_params *params)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret = -ENOBUFS;
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
0, NL80211_CMD_NEW_STATION, 0);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
0, NL80211_CMD_DEL_STATION, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(drv->ifname));
+ if_nametoindex(bss->ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
return;
nla_put_failure:
- wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d).\n",
- ifidx);
+ wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
}
int optval;
socklen_t optlen;
- snprintf(buf, IFNAMSIZ, "mon.%s", drv->ifname);
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
buf[IFNAMSIZ - 1] = '\0';
drv->monitor_ifidx =
void *priv, const u8 *addr, const u8 *data,
size_t data_len, int encrypt, const u8 *own_addr)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_hdr *hdr;
size_t len;
u8 *pos;
}
-static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
- int total_flags, int flags_or,
- int flags_and)
+static int wpa_driver_nl80211_sta_set_flags(const char *ifname, void *priv,
+ const u8 *addr, int total_flags,
+ int flags_or, int flags_and)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg, *flags = NULL;
struct nl80211_sta_flag_update upd;
0, NL80211_CMD_SET_STATION, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(drv->ifname));
+ if_nametoindex(ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
/*
static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
- if (wpa_driver_nl80211_set_mode(drv, params->mode) ||
+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
nl80211_remove_monitor_interface(drv);
return -1;
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
- if (wpa_driver_nl80211_set_mode(drv, params->mode)) {
+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"IBSS mode");
return -1;
static int wpa_driver_nl80211_associate(
void *priv, struct wpa_driver_associate_params *params)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
struct nl_msg *msg;
return wpa_driver_nl80211_ibss(drv, params);
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
- if (wpa_driver_nl80211_set_mode(drv, params->mode) < 0)
+ if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0)
return -1;
return wpa_driver_nl80211_connect(drv, params);
}
static int wpa_driver_nl80211_set_mode(void *priv, int mode)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
int nlmode;
* take the device down, try to set the mode again, and bring the
* device back up.
*/
- if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == 0) {
/* Try to set the mode again while the interface is down */
ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
- if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1))
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
ret = -1;
}
} else if (!ret && nlmode != NL80211_IFTYPE_AP) {
/* Remove additional AP mode functionality */
nl80211_remove_monitor_interface(drv);
-#ifndef HOSTAPD
- drv->beacon_set = 0;
-#endif /* HOSTAPD */
+ bss->beacon_set = 0;
}
if (ret)
static int wpa_driver_nl80211_get_capa(void *priv,
struct wpa_driver_capa *capa)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
if (!drv->has_capability)
return -1;
os_memcpy(capa, &drv->capa, sizeof(*capa));
static int wpa_driver_nl80211_set_operstate(void *priv, int state)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
__func__, drv->operstate, state, state ? "UP" : "DORMANT");
static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nl80211_sta_flag_update upd;
0, NL80211_CMD_SET_STATION, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(drv->ifname));
+ if_nametoindex(bss->ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
os_memset(&upd, 0, sizeof(upd));
#ifdef HOSTAPD
-static struct i802_bss * get_bss(struct wpa_driver_nl80211_data *drv,
- int ifindex)
-{
- struct i802_bss *bss = &drv->bss;
- while (bss) {
- if (ifindex == bss->ifindex)
- return bss;
- bss = bss->next;
- }
- wpa_printf(MSG_DEBUG, "nl80211: get_bss(%d) failed", ifindex);
- return NULL;
-}
-
-
static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
{
int i;
static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
int idx, u8 *seq)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
msg = nlmsg_alloc();
static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
int mode)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
u8 rates[NL80211_MAX_SUPP_RATES];
u8 rates_len = 0;
NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
- /* TODO: multi-BSS support */
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
/* Set kernel driver on given frequency (MHz) */
static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
freq->sec_channel_offset);
}
static int i802_set_rts(void *priv, int rts)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret = -ENOBUFS;
u32 val;
static int i802_set_frag(void *priv, int frag)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret = -ENOBUFS;
u32 val;
static int i802_flush(void *priv)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
msg = nlmsg_alloc();
* XXX: FIX! this needs to flush all VLANs too
*/
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(drv->ifname));
+ if_nametoindex(bss->ifname));
return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
const u8 *addr)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
os_memset(data, 0, sizeof(*data));
0, NL80211_CMD_GET_STATION, 0);
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
return send_and_recv_msgs(drv, msg, get_sta_handler, data);
nla_put_failure:
static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *txq, *params;
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
0, NL80211_CMD_SET_WIPHY, 0);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
if (!txq)
static int i802_set_bss(void *priv, int cts, int preamble, int slot)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
msg = nlmsg_alloc();
if (slot >= 0)
NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
- /* TODO: multi-BSS support */
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
static int i802_set_sta_vlan(void *priv, const u8 *addr,
const char *ifname, int vlan_id)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
msg = nlmsg_alloc();
0, NL80211_CMD_SET_STATION, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(drv->ifname));
+ if_nametoindex(bss->ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
if_nametoindex(ifname));
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];
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ char name[IFNAMSIZ + 1];
- os_snprintf(name, sizeof(name), "%s.sta%d", drv->ifname, aid);
+ os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+ wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+ " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
if (val) {
- if (nl80211_create_iface(priv, name, NL80211_IFTYPE_AP_VLAN,
+ if (nl80211_create_iface(drv, name, NL80211_IFTYPE_AP_VLAN,
NULL, 1) < 0)
return -1;
linux_set_iface_flags(drv->ioctl_sock, name, 1);
return i802_set_sta_vlan(priv, addr, name, 0);
} else {
- i802_set_sta_vlan(priv, addr, drv->ifname, 0);
+ i802_set_sta_vlan(priv, addr, bss->ifname, 0);
return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
name);
}
static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
int reason)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
struct ieee80211_mgmt mgmt;
memset(&mgmt, 0, sizeof(mgmt));
memcpy(mgmt.sa, own_addr, ETH_ALEN);
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
- return wpa_driver_nl80211_send_mlme(drv, (u8 *) &mgmt,
+ return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth));
}
static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
int reason)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
struct ieee80211_mgmt mgmt;
memset(&mgmt, 0, sizeof(mgmt));
memcpy(mgmt.sa, own_addr, ETH_ALEN);
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
- return wpa_driver_nl80211_send_mlme(drv, (u8 *) &mgmt,
+ return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.disassoc));
}
struct wpa_init_params *params)
{
struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *bss;
size_t i;
char brname[IFNAMSIZ];
int ifindex, br_ifindex;
int br_added = 0;
- drv = wpa_driver_nl80211_init(hapd, params->ifname);
- if (drv == NULL)
+ bss = wpa_driver_nl80211_init(hapd, params->ifname);
+ if (bss == NULL)
return NULL;
- drv->bss.ifindex = drv->ifindex;
-
+ drv = bss->drv;
if (linux_br_get(brname, params->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
params->ifname, brname);
/* start listening for EAPOL on the default AP interface */
add_ifidx(drv, drv->ifindex);
- if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0))
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
goto failed;
if (params->bssid) {
- if (linux_set_ifhwaddr(drv->ioctl_sock, drv->ifname,
+ if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
params->bssid))
goto failed;
}
- if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP)) {
+ if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
- "into AP mode", drv->ifname);
+ "into AP mode", bss->ifname);
goto failed;
}
i802_check_bridge(drv, params->bridge[0], params->ifname) < 0)
goto failed;
- if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1))
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
goto failed;
drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
goto failed;
}
- if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, params->own_addr))
+ if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
goto failed;
- return drv;
+ return bss;
failed:
nl80211_remove_monitor_interface(drv);
}
-static int wpa_driver_nl80211_if_add(const char *iface, void *priv,
- enum wpa_driver_if_type type,
+static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr,
- void *bss_ctx)
+ void *bss_ctx, void **drv_priv)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
int ifidx;
#ifdef HOSTAPD
- struct i802_bss *bss = NULL;
+ struct i802_bss *new_bss = NULL;
if (type == WPA_IF_AP_BSS) {
- bss = os_zalloc(sizeof(*bss));
- if (bss == NULL)
+ new_bss = os_zalloc(sizeof(*new_bss));
+ if (new_bss == NULL)
return -1;
}
#endif /* HOSTAPD */
0);
if (ifidx < 0) {
#ifdef HOSTAPD
- os_free(bss);
+ os_free(new_bss);
#endif /* HOSTAPD */
return -1;
}
if (type == WPA_IF_AP_BSS) {
if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
nl80211_remove_iface(drv, ifidx);
- os_free(bss);
+ os_free(new_bss);
return -1;
}
- bss->ifindex = ifidx;
- bss->next = drv->bss.next;
- drv->bss.next = bss;
+ os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+ new_bss->ifindex = ifidx;
+ new_bss->drv = drv;
+ new_bss->next = drv->first_bss.next;
+ drv->first_bss.next = new_bss;
+ if (drv_priv)
+ *drv_priv = new_bss;
}
#endif /* HOSTAPD */
enum wpa_driver_if_type type,
const char *ifname)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
+ wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
+ __func__, type, ifname, ifindex);
+ if (ifindex <= 0)
+ return -1;
nl80211_remove_iface(drv, ifindex);
#ifdef HOSTAPD
- if (type == WPA_IF_AP_BSS) {
- struct i802_bss *bss, *prev;
- prev = &drv->bss;
- bss = drv->bss.next;
- while (bss) {
- if (ifindex == bss->ifindex) {
- prev->next = bss->next;
- os_free(bss);
- break;
- }
- prev = bss;
- bss = bss->next;
+ if (type != WPA_IF_AP_BSS)
+ return 0;
+
+ if (bss != &drv->first_bss) {
+ struct i802_bss *tbss = &drv->first_bss;
+
+ while (tbss) {
+ if (tbss->next != bss)
+ continue;
+
+ tbss->next = bss->next;
+ os_free(bss);
+ break;
}
}
#endif /* HOSTAPD */
}
+static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ struct nl_msg *msg;
+ u8 *buf;
+ struct ieee80211_hdr *hdr;
+ u64 cookie;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d)",
+ drv->ifindex);
+
+ buf = os_zalloc(24 + data_len);
+ if (buf == NULL)
+ return ret;
+ os_memcpy(buf + 24, data, data_len);
+ hdr = (struct ieee80211_hdr *) buf;
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
+ os_memcpy(hdr->addr1, dst, ETH_ALEN);
+ os_memcpy(hdr->addr2, src, ETH_ALEN);
+ os_memcpy(hdr->addr3, bssid, ETH_ALEN);
+
+ if (drv->nlmode == NL80211_IFTYPE_AP) {
+ ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
+ os_free(buf);
+ return ret;
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_ACTION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+ NLA_PUT(msg, NL80211_ATTR_FRAME, 24 + data_len, buf);
+ os_free(buf);
+
+ cookie = 0;
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Action command failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX command accepted; "
+ "cookie 0x%llx", (long long unsigned int) cookie);
+ drv->send_action_cookie = cookie;
+ drv->pending_send_action = 1;
+ ret = 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
unsigned int duration)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
u64 cookie;
static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
if (drv->nlmode != NL80211_IFTYPE_STATION) {
wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
}
-static int wpa_driver_nl80211_alloc_interface_addr(void *priv, u8 *addr)
+static int wpa_driver_nl80211_alloc_interface_addr(void *priv, u8 *addr,
+ char *ifname)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
- if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr) < 0)
+ if (ifname)
+ ifname[0] = '\0';
+
+ if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, addr) < 0)
return -1;
if (addr[0] & 0x02) {
static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
drv->disable_11b_rates = disabled;
return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
}
static int wpa_driver_nl80211_deinit_ap(void *priv)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
if (drv->nlmode != NL80211_IFTYPE_AP)
return -1;
wpa_driver_nl80211_del_beacon(drv);
- return wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA);
+ return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
+}
+
+
+static void wpa_driver_nl80211_resume(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
+ "resume event");
+ }
}
.set_sta_vlan = i802_set_sta_vlan,
.set_wds_sta = i802_set_wds_sta,
#endif /* HOSTAPD */
+ .send_action = wpa_driver_nl80211_send_action,
.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
.cancel_remain_on_channel =
wpa_driver_nl80211_cancel_remain_on_channel,
.release_interface_addr = wpa_driver_nl80211_release_interface_addr,
.disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
.deinit_ap = wpa_driver_nl80211_deinit_ap,
+ .resume = wpa_driver_nl80211_resume,
};