GAS: Use off-channel operations for requests
This separates off-channel Action frame TX/RX from P2P into a generic implementation that can now be used both for P2P and GAS needs.
This commit is contained in:
parent
04ea7b7947
commit
24f6497c34
8 changed files with 452 additions and 262 deletions
|
@ -202,6 +202,7 @@ OBJS += ../src/p2p/p2p_group.o
|
||||||
OBJS += ../src/ap/p2p_hostapd.o
|
OBJS += ../src/ap/p2p_hostapd.o
|
||||||
CFLAGS += -DCONFIG_P2P
|
CFLAGS += -DCONFIG_P2P
|
||||||
NEED_GAS=y
|
NEED_GAS=y
|
||||||
|
NEED_OFFCHANNEL=y
|
||||||
NEED_80211_COMMON=y
|
NEED_80211_COMMON=y
|
||||||
ifdef CONFIG_P2P_STRICT
|
ifdef CONFIG_P2P_STRICT
|
||||||
CFLAGS += -DCONFIG_P2P_STRICT
|
CFLAGS += -DCONFIG_P2P_STRICT
|
||||||
|
@ -1287,6 +1288,12 @@ ifdef NEED_GAS
|
||||||
OBJS += ../src/common/gas.o
|
OBJS += ../src/common/gas.o
|
||||||
OBJS += gas_query.o
|
OBJS += gas_query.o
|
||||||
CFLAGS += -DCONFIG_GAS
|
CFLAGS += -DCONFIG_GAS
|
||||||
|
NEED_OFFCHANNEL=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef NEED_OFFCHANNEL
|
||||||
|
OBJS += offchannel.o
|
||||||
|
CFLAGS += -DCONFIG_OFFCHANNEL
|
||||||
endif
|
endif
|
||||||
|
|
||||||
OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
|
OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "bss.h"
|
#include "bss.h"
|
||||||
#include "mlme.h"
|
#include "mlme.h"
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
|
#include "offchannel.h"
|
||||||
|
|
||||||
|
|
||||||
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
|
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
|
||||||
|
@ -1914,27 +1915,28 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
|
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
|
||||||
sme_event_assoc_timed_out(wpa_s, data);
|
sme_event_assoc_timed_out(wpa_s, data);
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_AP
|
|
||||||
case EVENT_TX_STATUS:
|
case EVENT_TX_STATUS:
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS dst=" MACSTR
|
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS dst=" MACSTR
|
||||||
" type=%d stype=%d",
|
" type=%d stype=%d",
|
||||||
MAC2STR(data->tx_status.dst),
|
MAC2STR(data->tx_status.dst),
|
||||||
data->tx_status.type, data->tx_status.stype);
|
data->tx_status.type, data->tx_status.stype);
|
||||||
|
#ifdef CONFIG_AP
|
||||||
if (wpa_s->ap_iface == NULL) {
|
if (wpa_s->ap_iface == NULL) {
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_OFFCHANNEL
|
||||||
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
|
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
|
||||||
data->tx_status.stype == WLAN_FC_STYPE_ACTION)
|
data->tx_status.stype == WLAN_FC_STYPE_ACTION)
|
||||||
wpas_send_action_tx_status(
|
offchannel_send_action_tx_status(
|
||||||
wpa_s, data->tx_status.dst,
|
wpa_s, data->tx_status.dst,
|
||||||
data->tx_status.data,
|
data->tx_status.data,
|
||||||
data->tx_status.data_len,
|
data->tx_status.data_len,
|
||||||
data->tx_status.ack ?
|
data->tx_status.ack ?
|
||||||
P2P_SEND_ACTION_SUCCESS :
|
OFFCHANNEL_SEND_ACTION_SUCCESS :
|
||||||
P2P_SEND_ACTION_NO_ACK);
|
OFFCHANNEL_SEND_ACTION_NO_ACK);
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_OFFCHANNEL */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_P2P
|
#endif /* CONFIG_AP */
|
||||||
|
#ifdef CONFIG_OFFCHANNEL
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
|
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
|
||||||
MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
|
MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
|
||||||
/*
|
/*
|
||||||
|
@ -1945,16 +1947,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
|
data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
|
||||||
os_memcmp(wpa_s->parent->pending_action_dst,
|
os_memcmp(wpa_s->parent->pending_action_dst,
|
||||||
data->tx_status.dst, ETH_ALEN) == 0) {
|
data->tx_status.dst, ETH_ALEN) == 0) {
|
||||||
wpas_send_action_tx_status(
|
offchannel_send_action_tx_status(
|
||||||
wpa_s->parent, data->tx_status.dst,
|
wpa_s->parent, data->tx_status.dst,
|
||||||
data->tx_status.data,
|
data->tx_status.data,
|
||||||
data->tx_status.data_len,
|
data->tx_status.data_len,
|
||||||
data->tx_status.ack ?
|
data->tx_status.ack ?
|
||||||
P2P_SEND_ACTION_SUCCESS :
|
OFFCHANNEL_SEND_ACTION_SUCCESS :
|
||||||
P2P_SEND_ACTION_NO_ACK);
|
OFFCHANNEL_SEND_ACTION_NO_ACK);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_OFFCHANNEL */
|
||||||
|
#ifdef CONFIG_AP
|
||||||
switch (data->tx_status.type) {
|
switch (data->tx_status.type) {
|
||||||
case WLAN_FC_TYPE_MGMT:
|
case WLAN_FC_TYPE_MGMT:
|
||||||
ap_mgmt_tx_cb(wpa_s, data->tx_status.data,
|
ap_mgmt_tx_cb(wpa_s, data->tx_status.data,
|
||||||
|
@ -1969,7 +1972,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
data->tx_status.ack);
|
data->tx_status.ack);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
break;
|
break;
|
||||||
|
#ifdef CONFIG_AP
|
||||||
case EVENT_RX_FROM_UNKNOWN:
|
case EVENT_RX_FROM_UNKNOWN:
|
||||||
if (wpa_s->ap_iface == NULL)
|
if (wpa_s->ap_iface == NULL)
|
||||||
break;
|
break;
|
||||||
|
@ -2067,16 +2072,29 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
data->rx_probe_req.ie_len);
|
data->rx_probe_req.ie_len);
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_P2P
|
|
||||||
case EVENT_REMAIN_ON_CHANNEL:
|
case EVENT_REMAIN_ON_CHANNEL:
|
||||||
|
#ifdef CONFIG_OFFCHANNEL
|
||||||
|
offchannel_remain_on_channel_cb(
|
||||||
|
wpa_s, data->remain_on_channel.freq,
|
||||||
|
data->remain_on_channel.duration);
|
||||||
|
#endif /* CONFIG_OFFCHANNEL */
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
wpas_p2p_remain_on_channel_cb(
|
wpas_p2p_remain_on_channel_cb(
|
||||||
wpa_s, data->remain_on_channel.freq,
|
wpa_s, data->remain_on_channel.freq,
|
||||||
data->remain_on_channel.duration);
|
data->remain_on_channel.duration);
|
||||||
|
#endif /* CONFIG_P2P */
|
||||||
break;
|
break;
|
||||||
case EVENT_CANCEL_REMAIN_ON_CHANNEL:
|
case EVENT_CANCEL_REMAIN_ON_CHANNEL:
|
||||||
|
#ifdef CONFIG_OFFCHANNEL
|
||||||
|
offchannel_cancel_remain_on_channel_cb(
|
||||||
|
wpa_s, data->remain_on_channel.freq);
|
||||||
|
#endif /* CONFIG_OFFCHANNEL */
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
wpas_p2p_cancel_remain_on_channel_cb(
|
wpas_p2p_cancel_remain_on_channel_cb(
|
||||||
wpa_s, data->remain_on_channel.freq);
|
wpa_s, data->remain_on_channel.freq);
|
||||||
|
#endif /* CONFIG_P2P */
|
||||||
break;
|
break;
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
case EVENT_P2P_DEV_FOUND: {
|
case EVENT_P2P_DEV_FOUND: {
|
||||||
struct p2p_peer_info peer_info;
|
struct p2p_peer_info peer_info;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "common/gas.h"
|
#include "common/gas.h"
|
||||||
#include "wpa_supplicant_i.h"
|
#include "wpa_supplicant_i.h"
|
||||||
#include "driver_i.h"
|
#include "driver_i.h"
|
||||||
|
#include "offchannel.h"
|
||||||
#include "gas_query.h"
|
#include "gas_query.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +33,8 @@ struct gas_query_pending {
|
||||||
u8 addr[ETH_ALEN];
|
u8 addr[ETH_ALEN];
|
||||||
u8 dialog_token;
|
u8 dialog_token;
|
||||||
u8 next_frag_id;
|
u8 next_frag_id;
|
||||||
int wait_comeback;
|
int wait_comeback:1;
|
||||||
|
int offchannel_tx_started:1;
|
||||||
int freq;
|
int freq;
|
||||||
u16 status_code;
|
u16 status_code;
|
||||||
struct wpabuf *adv_proto;
|
struct wpabuf *adv_proto;
|
||||||
|
@ -73,6 +75,8 @@ static void gas_query_done(struct gas_query *gas,
|
||||||
struct gas_query_pending *query,
|
struct gas_query_pending *query,
|
||||||
enum gas_query_result result)
|
enum gas_query_result result)
|
||||||
{
|
{
|
||||||
|
if (query->offchannel_tx_started)
|
||||||
|
offchannel_send_action_done(gas->wpa_s);
|
||||||
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
||||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||||
dl_list_del(&query->list);
|
dl_list_del(&query->list);
|
||||||
|
@ -127,12 +131,17 @@ static int gas_query_append(struct gas_query_pending *query, const u8 *data,
|
||||||
static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
|
static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
|
||||||
struct wpabuf *req)
|
struct wpabuf *req)
|
||||||
{
|
{
|
||||||
|
int res;
|
||||||
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
|
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
|
||||||
"freq=%d", MAC2STR(query->addr),
|
"freq=%d", MAC2STR(query->addr),
|
||||||
(unsigned int) wpabuf_len(req), query->freq);
|
(unsigned int) wpabuf_len(req), query->freq);
|
||||||
return wpa_drv_send_action(gas->wpa_s, query->freq, 0, query->addr,
|
res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
|
||||||
gas->wpa_s->own_addr, query->addr,
|
gas->wpa_s->own_addr, query->addr,
|
||||||
wpabuf_head(req), wpabuf_len(req));
|
wpabuf_head(req), wpabuf_len(req), 1000,
|
||||||
|
NULL);
|
||||||
|
if (res == 0)
|
||||||
|
query->offchannel_tx_started = 1;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
310
wpa_supplicant/offchannel.c
Normal file
310
wpa_supplicant/offchannel.c
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
/*
|
||||||
|
* wpa_supplicant - Off-channel Action frame TX/RX
|
||||||
|
* Copyright (c) 2009-2010, Atheros Communications
|
||||||
|
* Copyright (c) 2011, Qualcomm Atheros
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "utils/eloop.h"
|
||||||
|
#include "wpa_supplicant_i.h"
|
||||||
|
#include "driver_i.h"
|
||||||
|
#include "offchannel.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static struct wpa_supplicant *
|
||||||
|
wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
|
||||||
|
{
|
||||||
|
struct wpa_supplicant *iface;
|
||||||
|
|
||||||
|
if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
|
||||||
|
return wpa_s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to find a group interface that matches with the source address.
|
||||||
|
*/
|
||||||
|
iface = wpa_s->global->ifaces;
|
||||||
|
while (iface) {
|
||||||
|
if (os_memcmp(wpa_s->pending_action_src,
|
||||||
|
iface->own_addr, ETH_ALEN) == 0)
|
||||||
|
break;
|
||||||
|
iface = iface->next;
|
||||||
|
}
|
||||||
|
if (iface) {
|
||||||
|
wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
|
||||||
|
"instead of interface %s for Action TX",
|
||||||
|
iface->ifname, wpa_s->ifname);
|
||||||
|
return iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wpa_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct wpa_supplicant *wpa_s = eloop_ctx;
|
||||||
|
struct wpa_supplicant *iface;
|
||||||
|
int res;
|
||||||
|
int without_roc;
|
||||||
|
|
||||||
|
without_roc = wpa_s->pending_action_without_roc;
|
||||||
|
wpa_s->pending_action_without_roc = 0;
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback "
|
||||||
|
"(without_roc=%d pending_action_tx=%p)",
|
||||||
|
without_roc, wpa_s->pending_action_tx);
|
||||||
|
|
||||||
|
if (wpa_s->pending_action_tx == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This call is likely going to be on the P2P device instance if the
|
||||||
|
* driver uses a separate interface for that purpose. However, some
|
||||||
|
* Action frames are actually sent within a P2P Group and when that is
|
||||||
|
* the case, we need to follow power saving (e.g., GO buffering the
|
||||||
|
* frame for a client in PS mode or a client following the advertised
|
||||||
|
* NoA from its GO). To make that easier for the driver, select the
|
||||||
|
* correct group interface here.
|
||||||
|
*/
|
||||||
|
iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
|
||||||
|
|
||||||
|
if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
|
||||||
|
wpa_s->pending_action_freq != 0 &&
|
||||||
|
wpa_s->pending_action_freq != iface->assoc_freq) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX "
|
||||||
|
"waiting for another freq=%u (off_channel_freq=%u "
|
||||||
|
"assoc_freq=%u)",
|
||||||
|
wpa_s->pending_action_freq,
|
||||||
|
wpa_s->off_channel_freq,
|
||||||
|
iface->assoc_freq);
|
||||||
|
if (without_roc && wpa_s->off_channel_freq == 0) {
|
||||||
|
/*
|
||||||
|
* We may get here if wpas_send_action() found us to be
|
||||||
|
* on the correct channel, but remain-on-channel cancel
|
||||||
|
* event was received before getting here.
|
||||||
|
*/
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
|
||||||
|
"remain-on-channel to send Action frame");
|
||||||
|
if (wpa_drv_remain_on_channel(
|
||||||
|
wpa_s, wpa_s->pending_action_freq, 200) <
|
||||||
|
0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
|
||||||
|
"request driver to remain on "
|
||||||
|
"channel (%u MHz) for Action Frame "
|
||||||
|
"TX", wpa_s->pending_action_freq);
|
||||||
|
} else {
|
||||||
|
wpa_s->off_channel_freq = 0;
|
||||||
|
wpa_s->roc_waiting_drv_freq =
|
||||||
|
wpa_s->pending_action_freq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
|
||||||
|
MACSTR " using interface %s",
|
||||||
|
MAC2STR(wpa_s->pending_action_dst), iface->ifname);
|
||||||
|
res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
|
||||||
|
wpa_s->pending_action_dst,
|
||||||
|
wpa_s->pending_action_src,
|
||||||
|
wpa_s->pending_action_bssid,
|
||||||
|
wpabuf_head(wpa_s->pending_action_tx),
|
||||||
|
wpabuf_len(wpa_s->pending_action_tx));
|
||||||
|
if (res) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the "
|
||||||
|
"pending Action frame");
|
||||||
|
/*
|
||||||
|
* Use fake TX status event to allow state machines to
|
||||||
|
* continue.
|
||||||
|
*/
|
||||||
|
offchannel_send_action_tx_status(
|
||||||
|
wpa_s, wpa_s->pending_action_dst,
|
||||||
|
wpabuf_head(wpa_s->pending_action_tx),
|
||||||
|
wpabuf_len(wpa_s->pending_action_tx),
|
||||||
|
OFFCHANNEL_SEND_ACTION_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void offchannel_send_action_tx_status(
|
||||||
|
struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
|
||||||
|
size_t data_len, enum offchannel_send_action_result result)
|
||||||
|
{
|
||||||
|
if (wpa_s->pending_action_tx == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
|
||||||
|
"no pending operation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
|
||||||
|
"unknown destination address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpabuf_free(wpa_s->pending_action_tx);
|
||||||
|
wpa_s->pending_action_tx = NULL;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p",
|
||||||
|
result, wpa_s->pending_action_tx_status_cb);
|
||||||
|
|
||||||
|
if (wpa_s->pending_action_tx_status_cb) {
|
||||||
|
wpa_s->pending_action_tx_status_cb(
|
||||||
|
wpa_s, wpa_s->pending_action_freq,
|
||||||
|
wpa_s->pending_action_dst, wpa_s->pending_action_src,
|
||||||
|
wpa_s->pending_action_bssid,
|
||||||
|
data, data_len, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
|
||||||
|
const u8 *dst, const u8 *src, const u8 *bssid,
|
||||||
|
const u8 *buf, size_t len, unsigned int wait_time,
|
||||||
|
void (*tx_cb)(struct wpa_supplicant *wpa_s,
|
||||||
|
unsigned int freq, const u8 *dst,
|
||||||
|
const u8 *src, const u8 *bssid,
|
||||||
|
const u8 *data, size_t data_len,
|
||||||
|
enum offchannel_send_action_result
|
||||||
|
result))
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst="
|
||||||
|
MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d",
|
||||||
|
freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
|
||||||
|
(int) len);
|
||||||
|
|
||||||
|
wpa_s->pending_action_tx_status_cb = tx_cb;
|
||||||
|
|
||||||
|
if (wpa_s->pending_action_tx) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
|
||||||
|
"frame TX to " MACSTR,
|
||||||
|
MAC2STR(wpa_s->pending_action_dst));
|
||||||
|
wpabuf_free(wpa_s->pending_action_tx);
|
||||||
|
}
|
||||||
|
wpa_s->pending_action_tx = wpabuf_alloc(len);
|
||||||
|
if (wpa_s->pending_action_tx == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
|
||||||
|
"frame TX buffer (len=%llu)",
|
||||||
|
(unsigned long long) len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
|
||||||
|
os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
|
||||||
|
os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
|
||||||
|
os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
|
||||||
|
wpa_s->pending_action_freq = freq;
|
||||||
|
|
||||||
|
if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
|
||||||
|
struct wpa_supplicant *iface;
|
||||||
|
|
||||||
|
iface = wpas_get_tx_interface(wpa_s,
|
||||||
|
wpa_s->pending_action_src);
|
||||||
|
wpa_s->action_tx_wait_time = wait_time;
|
||||||
|
|
||||||
|
return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
|
||||||
|
wait_time, wpa_s->pending_action_dst,
|
||||||
|
wpa_s->pending_action_src,
|
||||||
|
wpa_s->pending_action_bssid,
|
||||||
|
wpabuf_head(wpa_s->pending_action_tx),
|
||||||
|
wpabuf_len(wpa_s->pending_action_tx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freq) {
|
||||||
|
struct wpa_supplicant *tx_iface;
|
||||||
|
tx_iface = wpas_get_tx_interface(wpa_s, src);
|
||||||
|
if (tx_iface->assoc_freq == freq) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Already on "
|
||||||
|
"requested channel (TX interface operating "
|
||||||
|
"channel)");
|
||||||
|
freq = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wpa_s->off_channel_freq == freq || freq == 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Already on requested "
|
||||||
|
"channel; send Action frame immediately");
|
||||||
|
/* TODO: Would there ever be need to extend the current
|
||||||
|
* duration on the channel? */
|
||||||
|
wpa_s->pending_action_without_roc = 1;
|
||||||
|
eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
|
||||||
|
eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
wpa_s->pending_action_without_roc = 0;
|
||||||
|
|
||||||
|
if (wpa_s->roc_waiting_drv_freq == freq) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for "
|
||||||
|
"driver to get to frequency %u MHz; continue "
|
||||||
|
"waiting to send the Action frame", freq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be "
|
||||||
|
"transmitted once the driver gets to the requested "
|
||||||
|
"channel");
|
||||||
|
if (wait_time > wpa_s->max_remain_on_chan)
|
||||||
|
wait_time = wpa_s->max_remain_on_chan;
|
||||||
|
if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
|
||||||
|
"to remain on channel (%u MHz) for Action "
|
||||||
|
"Frame TX", freq);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_s->off_channel_freq = 0;
|
||||||
|
wpa_s->roc_waiting_drv_freq = freq;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
|
||||||
|
"notification");
|
||||||
|
wpabuf_free(wpa_s->pending_action_tx);
|
||||||
|
wpa_s->pending_action_tx = NULL;
|
||||||
|
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
|
||||||
|
wpa_s->action_tx_wait_time)
|
||||||
|
wpa_drv_send_action_cancel_wait(wpa_s);
|
||||||
|
|
||||||
|
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
|
||||||
|
wpa_drv_cancel_remain_on_channel(wpa_s);
|
||||||
|
wpa_s->off_channel_freq = 0;
|
||||||
|
wpa_s->roc_waiting_drv_freq = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
|
||||||
|
unsigned int freq, unsigned int duration)
|
||||||
|
{
|
||||||
|
wpa_s->roc_waiting_drv_freq = 0;
|
||||||
|
wpa_s->off_channel_freq = freq;
|
||||||
|
wpas_send_action_cb(wpa_s, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
|
||||||
|
unsigned int freq)
|
||||||
|
{
|
||||||
|
wpa_s->off_channel_freq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void offchannel_deinit(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
wpabuf_free(wpa_s->pending_action_tx);
|
||||||
|
wpa_s->pending_action_tx = NULL;
|
||||||
|
eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
|
||||||
|
}
|
38
wpa_supplicant/offchannel.h
Normal file
38
wpa_supplicant/offchannel.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* wpa_supplicant - Off-channel Action frame TX/RX
|
||||||
|
* Copyright (c) 2009-2010, Atheros Communications
|
||||||
|
* Copyright (c) 2011, Qualcomm Atheros
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OFFCHANNEL_H
|
||||||
|
#define OFFCHANNEL_H
|
||||||
|
|
||||||
|
int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
|
||||||
|
const u8 *dst, const u8 *src, const u8 *bssid,
|
||||||
|
const u8 *buf, size_t len, unsigned int wait_time,
|
||||||
|
void (*tx_cb)(struct wpa_supplicant *wpa_s,
|
||||||
|
unsigned int freq, const u8 *dst,
|
||||||
|
const u8 *src, const u8 *bssid,
|
||||||
|
const u8 *data, size_t data_len,
|
||||||
|
enum offchannel_send_action_result
|
||||||
|
result));
|
||||||
|
void offchannel_send_action_done(struct wpa_supplicant *wpa_s);
|
||||||
|
void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
|
||||||
|
unsigned int freq, unsigned int duration);
|
||||||
|
void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
|
||||||
|
unsigned int freq);
|
||||||
|
void offchannel_deinit(struct wpa_supplicant *wpa_s);
|
||||||
|
void offchannel_send_action_tx_status(
|
||||||
|
struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
|
||||||
|
size_t data_len, enum offchannel_send_action_result result);
|
||||||
|
|
||||||
|
#endif /* OFFCHANNEL_H */
|
|
@ -34,6 +34,7 @@
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
#include "bss.h"
|
#include "bss.h"
|
||||||
|
#include "offchannel.h"
|
||||||
#include "wps_supplicant.h"
|
#include "wps_supplicant.h"
|
||||||
#include "p2p_supplicant.h"
|
#include "p2p_supplicant.h"
|
||||||
|
|
||||||
|
@ -570,155 +571,38 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct wpa_supplicant *
|
static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
|
||||||
wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
|
unsigned int freq,
|
||||||
|
const u8 *dst, const u8 *src,
|
||||||
|
const u8 *bssid,
|
||||||
|
const u8 *data, size_t data_len,
|
||||||
|
enum offchannel_send_action_result
|
||||||
|
result)
|
||||||
{
|
{
|
||||||
struct wpa_supplicant *iface;
|
enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
|
||||||
|
|
||||||
if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
|
|
||||||
return wpa_s;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to find a group interface that matches with the source address.
|
|
||||||
*/
|
|
||||||
iface = wpa_s->global->ifaces;
|
|
||||||
while (iface) {
|
|
||||||
if (os_memcmp(wpa_s->pending_action_src,
|
|
||||||
iface->own_addr, ETH_ALEN) == 0)
|
|
||||||
break;
|
|
||||||
iface = iface->next;
|
|
||||||
}
|
|
||||||
if (iface) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
|
|
||||||
"instead of interface %s for Action TX",
|
|
||||||
iface->ifname, wpa_s->ifname);
|
|
||||||
return iface;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wpa_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
|
|
||||||
{
|
|
||||||
struct wpa_supplicant *wpa_s = eloop_ctx;
|
|
||||||
struct wpa_supplicant *iface;
|
|
||||||
int res;
|
|
||||||
int without_roc;
|
|
||||||
|
|
||||||
without_roc = wpa_s->pending_action_without_roc;
|
|
||||||
wpa_s->pending_action_without_roc = 0;
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Send Action callback (without_roc=%d "
|
|
||||||
"pending_action_tx=%p)",
|
|
||||||
without_roc, wpa_s->pending_action_tx);
|
|
||||||
|
|
||||||
if (wpa_s->pending_action_tx == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This call is likely going to be on the P2P device instance if the
|
|
||||||
* driver uses a separate interface for that purpose. However, some
|
|
||||||
* Action frames are actually sent within a P2P Group and when that is
|
|
||||||
* the case, we need to follow power saving (e.g., GO buffering the
|
|
||||||
* frame for a client in PS mode or a client following the advertised
|
|
||||||
* NoA from its GO). To make that easier for the driver, select the
|
|
||||||
* correct group interface here.
|
|
||||||
*/
|
|
||||||
iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
|
|
||||||
|
|
||||||
if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
|
|
||||||
wpa_s->pending_action_freq != 0 &&
|
|
||||||
wpa_s->pending_action_freq != iface->assoc_freq) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX "
|
|
||||||
"waiting for another freq=%u (off_channel_freq=%u "
|
|
||||||
"assoc_freq=%u)",
|
|
||||||
wpa_s->pending_action_freq,
|
|
||||||
wpa_s->off_channel_freq,
|
|
||||||
iface->assoc_freq);
|
|
||||||
if (without_roc && wpa_s->off_channel_freq == 0) {
|
|
||||||
/*
|
|
||||||
* We may get here if wpas_send_action() found us to be
|
|
||||||
* on the correct channel, but remain-on-channel cancel
|
|
||||||
* event was received before getting here.
|
|
||||||
*/
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Schedule "
|
|
||||||
"remain-on-channel to send Action frame");
|
|
||||||
if (wpa_drv_remain_on_channel(
|
|
||||||
wpa_s, wpa_s->pending_action_freq, 200) <
|
|
||||||
0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Failed to request "
|
|
||||||
"driver to remain on channel (%u "
|
|
||||||
"MHz) for Action Frame TX",
|
|
||||||
wpa_s->pending_action_freq);
|
|
||||||
} else {
|
|
||||||
wpa_s->off_channel_freq = 0;
|
|
||||||
wpa_s->roc_waiting_drv_freq =
|
|
||||||
wpa_s->pending_action_freq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
|
|
||||||
MACSTR " using interface %s",
|
|
||||||
MAC2STR(wpa_s->pending_action_dst), iface->ifname);
|
|
||||||
res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
|
|
||||||
wpa_s->pending_action_dst,
|
|
||||||
wpa_s->pending_action_src,
|
|
||||||
wpa_s->pending_action_bssid,
|
|
||||||
wpabuf_head(wpa_s->pending_action_tx),
|
|
||||||
wpabuf_len(wpa_s->pending_action_tx));
|
|
||||||
if (res) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Failed to send the pending "
|
|
||||||
"Action frame");
|
|
||||||
/*
|
|
||||||
* Use fake TX status event to allow P2P state machine to
|
|
||||||
* continue.
|
|
||||||
*/
|
|
||||||
wpas_send_action_tx_status(
|
|
||||||
wpa_s, wpa_s->pending_action_dst,
|
|
||||||
wpabuf_head(wpa_s->pending_action_tx),
|
|
||||||
wpabuf_len(wpa_s->pending_action_tx),
|
|
||||||
P2P_SEND_ACTION_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
|
|
||||||
const u8 *data, size_t data_len,
|
|
||||||
enum p2p_send_action_result result)
|
|
||||||
{
|
|
||||||
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
|
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
|
||||||
return;
|
return;
|
||||||
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
|
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (wpa_s->pending_action_tx == NULL) {
|
switch (result) {
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - no "
|
case OFFCHANNEL_SEND_ACTION_SUCCESS:
|
||||||
"pending operation");
|
res = P2P_SEND_ACTION_SUCCESS;
|
||||||
return;
|
break;
|
||||||
|
case OFFCHANNEL_SEND_ACTION_NO_ACK:
|
||||||
|
res = P2P_SEND_ACTION_NO_ACK;
|
||||||
|
break;
|
||||||
|
case OFFCHANNEL_SEND_ACTION_FAILED:
|
||||||
|
res = P2P_SEND_ACTION_FAILED;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
|
p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - unknown "
|
|
||||||
"destination address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpabuf_free(wpa_s->pending_action_tx);
|
|
||||||
wpa_s->pending_action_tx = NULL;
|
|
||||||
|
|
||||||
p2p_send_action_cb(wpa_s->global->p2p, wpa_s->pending_action_freq,
|
|
||||||
wpa_s->pending_action_dst,
|
|
||||||
wpa_s->pending_action_src,
|
|
||||||
wpa_s->pending_action_bssid,
|
|
||||||
result);
|
|
||||||
|
|
||||||
if (wpa_s->pending_pd_before_join &&
|
if (wpa_s->pending_pd_before_join &&
|
||||||
(os_memcmp(wpa_s->pending_action_dst, wpa_s->pending_join_dev_addr,
|
(os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
|
||||||
ETH_ALEN) == 0 ||
|
os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
|
||||||
os_memcmp(wpa_s->pending_action_dst,
|
|
||||||
wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
|
|
||||||
wpa_s->pending_pd_before_join = 0;
|
wpa_s->pending_pd_before_join = 0;
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
|
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
|
||||||
"join-existing-group operation");
|
"join-existing-group operation");
|
||||||
|
@ -732,104 +616,16 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
|
||||||
size_t len, unsigned int wait_time)
|
size_t len, unsigned int wait_time)
|
||||||
{
|
{
|
||||||
struct wpa_supplicant *wpa_s = ctx;
|
struct wpa_supplicant *wpa_s = ctx;
|
||||||
|
return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Send action frame: freq=%d dst=" MACSTR
|
wait_time,
|
||||||
" src=" MACSTR " bssid=" MACSTR " len=%d",
|
wpas_p2p_send_action_tx_status);
|
||||||
freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
|
|
||||||
(int) len);
|
|
||||||
|
|
||||||
if (wpa_s->pending_action_tx) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
|
|
||||||
"to " MACSTR, MAC2STR(wpa_s->pending_action_dst));
|
|
||||||
wpabuf_free(wpa_s->pending_action_tx);
|
|
||||||
}
|
|
||||||
wpa_s->pending_action_tx = wpabuf_alloc(len);
|
|
||||||
if (wpa_s->pending_action_tx == NULL) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Failed to allocate Action frame "
|
|
||||||
"TX buffer (len=%llu)", (unsigned long long) len);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
|
|
||||||
os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
|
|
||||||
os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
|
|
||||||
os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
|
|
||||||
wpa_s->pending_action_freq = freq;
|
|
||||||
|
|
||||||
if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
|
|
||||||
struct wpa_supplicant *iface;
|
|
||||||
|
|
||||||
iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
|
|
||||||
wpa_s->action_tx_wait_time = wait_time;
|
|
||||||
|
|
||||||
return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
|
|
||||||
wait_time, wpa_s->pending_action_dst,
|
|
||||||
wpa_s->pending_action_src,
|
|
||||||
wpa_s->pending_action_bssid,
|
|
||||||
wpabuf_head(wpa_s->pending_action_tx),
|
|
||||||
wpabuf_len(wpa_s->pending_action_tx));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (freq) {
|
|
||||||
struct wpa_supplicant *tx_iface;
|
|
||||||
tx_iface = wpas_get_tx_interface(wpa_s, src);
|
|
||||||
if (tx_iface->assoc_freq == freq) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Already on requested "
|
|
||||||
"channel (TX interface operating channel)");
|
|
||||||
freq = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wpa_s->off_channel_freq == freq || freq == 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Already on requested channel; "
|
|
||||||
"send Action frame immediately");
|
|
||||||
/* TODO: Would there ever be need to extend the current
|
|
||||||
* duration on the channel? */
|
|
||||||
wpa_s->pending_action_without_roc = 1;
|
|
||||||
eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
|
|
||||||
eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
wpa_s->pending_action_without_roc = 0;
|
|
||||||
|
|
||||||
if (wpa_s->roc_waiting_drv_freq == freq) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Already waiting for driver to get "
|
|
||||||
"to frequency %u MHz; continue waiting to send the "
|
|
||||||
"Action frame", freq);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted "
|
|
||||||
"once the driver gets to the requested channel");
|
|
||||||
if (wait_time > wpa_s->max_remain_on_chan)
|
|
||||||
wait_time = wpa_s->max_remain_on_chan;
|
|
||||||
if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Failed to request driver "
|
|
||||||
"to remain on channel (%u MHz) for Action "
|
|
||||||
"Frame TX", freq);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
wpa_s->off_channel_freq = 0;
|
|
||||||
wpa_s->roc_waiting_drv_freq = freq;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void wpas_send_action_done(void *ctx)
|
static void wpas_send_action_done(void *ctx)
|
||||||
{
|
{
|
||||||
struct wpa_supplicant *wpa_s = ctx;
|
struct wpa_supplicant *wpa_s = ctx;
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Action frame sequence done notification");
|
offchannel_send_action_done(wpa_s);
|
||||||
wpabuf_free(wpa_s->pending_action_tx);
|
|
||||||
wpa_s->pending_action_tx = NULL;
|
|
||||||
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
|
|
||||||
wpa_s->action_tx_wait_time)
|
|
||||||
wpa_drv_send_action_cancel_wait(wpa_s);
|
|
||||||
|
|
||||||
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
|
|
||||||
wpa_drv_cancel_remain_on_channel(wpa_s);
|
|
||||||
wpa_s->off_channel_freq = 0;
|
|
||||||
wpa_s->roc_waiting_drv_freq = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2529,9 +2325,6 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
|
||||||
wpa_drv_probe_req_report(wpa_s, 0);
|
wpa_drv_probe_req_report(wpa_s, 0);
|
||||||
os_free(wpa_s->go_params);
|
os_free(wpa_s->go_params);
|
||||||
wpa_s->go_params = NULL;
|
wpa_s->go_params = NULL;
|
||||||
wpabuf_free(wpa_s->pending_action_tx);
|
|
||||||
wpa_s->pending_action_tx = NULL;
|
|
||||||
eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
|
|
||||||
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
|
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
|
||||||
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
|
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
|
||||||
wpa_s->p2p_long_listen = 0;
|
wpa_s->p2p_long_listen = 0;
|
||||||
|
@ -3056,9 +2849,6 @@ void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
|
||||||
{
|
{
|
||||||
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
|
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
|
||||||
return;
|
return;
|
||||||
wpa_s->roc_waiting_drv_freq = 0;
|
|
||||||
wpa_s->off_channel_freq = freq;
|
|
||||||
wpas_send_action_cb(wpa_s, NULL);
|
|
||||||
if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
|
if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
|
||||||
p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
|
p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
|
||||||
wpa_s->pending_listen_duration);
|
wpa_s->pending_listen_duration);
|
||||||
|
@ -3096,7 +2886,6 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
|
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
|
||||||
"(p2p_long_listen=%d ms pending_action_tx=%p)",
|
"(p2p_long_listen=%d ms pending_action_tx=%p)",
|
||||||
wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
|
wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
|
||||||
wpa_s->off_channel_freq = 0;
|
|
||||||
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
|
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
|
||||||
return;
|
return;
|
||||||
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
|
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "bgscan.h"
|
#include "bgscan.h"
|
||||||
#include "bss.h"
|
#include "bss.h"
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
|
#include "offchannel.h"
|
||||||
|
|
||||||
const char *wpa_supplicant_version =
|
const char *wpa_supplicant_version =
|
||||||
"wpa_supplicant v" VERSION_STR "\n"
|
"wpa_supplicant v" VERSION_STR "\n"
|
||||||
|
@ -440,6 +441,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
|
||||||
wpas_p2p_deinit(wpa_s);
|
wpas_p2p_deinit(wpa_s);
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
|
#ifdef CONFIG_OFFCHANNEL
|
||||||
|
offchannel_deinit(wpa_s);
|
||||||
|
#endif /* CONFIG_OFFCHANNEL */
|
||||||
|
|
||||||
os_free(wpa_s->next_scan_freqs);
|
os_free(wpa_s->next_scan_freqs);
|
||||||
wpa_s->next_scan_freqs = NULL;
|
wpa_s->next_scan_freqs = NULL;
|
||||||
|
|
||||||
|
|
|
@ -322,6 +322,13 @@ struct wpa_client_mlme {
|
||||||
#endif /* CONFIG_CLIENT_MLME */
|
#endif /* CONFIG_CLIENT_MLME */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum offchannel_send_action_result {
|
||||||
|
OFFCHANNEL_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
|
||||||
|
OFFCHANNEL_SEND_ACTION_NO_ACK /* Frame was sent, but not acknowledged
|
||||||
|
*/,
|
||||||
|
OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct wpa_supplicant - Internal data for wpa_supplicant interface
|
* struct wpa_supplicant - Internal data for wpa_supplicant interface
|
||||||
*
|
*
|
||||||
|
@ -478,13 +485,6 @@ struct wpa_supplicant {
|
||||||
void *ap_configured_cb_data;
|
void *ap_configured_cb_data;
|
||||||
#endif /* CONFIG_AP */
|
#endif /* CONFIG_AP */
|
||||||
|
|
||||||
#ifdef CONFIG_P2P
|
|
||||||
struct p2p_go_neg_results *go_params;
|
|
||||||
int create_p2p_iface;
|
|
||||||
u8 pending_interface_addr[ETH_ALEN];
|
|
||||||
char pending_interface_name[100];
|
|
||||||
int pending_interface_type;
|
|
||||||
int p2p_group_idx;
|
|
||||||
unsigned int off_channel_freq;
|
unsigned int off_channel_freq;
|
||||||
struct wpabuf *pending_action_tx;
|
struct wpabuf *pending_action_tx;
|
||||||
u8 pending_action_src[ETH_ALEN];
|
u8 pending_action_src[ETH_ALEN];
|
||||||
|
@ -492,6 +492,22 @@ struct wpa_supplicant {
|
||||||
u8 pending_action_bssid[ETH_ALEN];
|
u8 pending_action_bssid[ETH_ALEN];
|
||||||
unsigned int pending_action_freq;
|
unsigned int pending_action_freq;
|
||||||
int pending_action_without_roc;
|
int pending_action_without_roc;
|
||||||
|
void (*pending_action_tx_status_cb)(struct wpa_supplicant *wpa_s,
|
||||||
|
unsigned int freq, const u8 *dst,
|
||||||
|
const u8 *src, const u8 *bssid,
|
||||||
|
const u8 *data, size_t data_len,
|
||||||
|
enum offchannel_send_action_result
|
||||||
|
result);
|
||||||
|
unsigned int roc_waiting_drv_freq;
|
||||||
|
int action_tx_wait_time;
|
||||||
|
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
|
struct p2p_go_neg_results *go_params;
|
||||||
|
int create_p2p_iface;
|
||||||
|
u8 pending_interface_addr[ETH_ALEN];
|
||||||
|
char pending_interface_name[100];
|
||||||
|
int pending_interface_type;
|
||||||
|
int p2p_group_idx;
|
||||||
unsigned int pending_listen_freq;
|
unsigned int pending_listen_freq;
|
||||||
unsigned int pending_listen_duration;
|
unsigned int pending_listen_duration;
|
||||||
enum {
|
enum {
|
||||||
|
@ -515,8 +531,6 @@ struct wpa_supplicant {
|
||||||
u8 pending_join_dev_addr[ETH_ALEN];
|
u8 pending_join_dev_addr[ETH_ALEN];
|
||||||
int pending_join_wps_method;
|
int pending_join_wps_method;
|
||||||
int p2p_join_scan_count;
|
int p2p_join_scan_count;
|
||||||
unsigned int roc_waiting_drv_freq;
|
|
||||||
int action_tx_wait_time;
|
|
||||||
int force_long_sd;
|
int force_long_sd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue