nl80211: Work around misdelivered control port TX status
The kernel commit "mac80211: support control port TX status reporting" seems to be delivering the TX status events for EAPOL frames over control port using NL80211_CMD_FRAME_TX_STATUS due to incorrect check on whether the frame is a Management or Data frame. Use the pending cookie value from EAPOL TX operation to detect this incorrect behavior and redirect the event internally to allow it to be used to get full TX control port functionality available for AP mode. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
87065881b1
commit
569497bf4f
3 changed files with 36 additions and 17 deletions
|
@ -5363,14 +5363,18 @@ static int nl80211_tx_control_port(void *priv, const u8 *dest,
|
|||
ext_arg.ext_data = &cookie;
|
||||
ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL,
|
||||
ack_handler_cookie, &ext_arg);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: tx_control_port failed: ret=%d (%s)",
|
||||
ret, strerror(-ret));
|
||||
else
|
||||
} else {
|
||||
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: tx_control_port cookie=0x%llx",
|
||||
(long long unsigned int) cookie);
|
||||
drv->eapol_tx_cookie = cookie;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -181,6 +181,7 @@ struct wpa_driver_nl80211_data {
|
|||
#define MAX_SEND_FRAME_COOKIES 20
|
||||
u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES];
|
||||
unsigned int num_send_frame_cookies;
|
||||
u64 eapol_tx_cookie;
|
||||
|
||||
unsigned int last_mgmt_freq;
|
||||
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
#include "driver_nl80211.h"
|
||||
|
||||
|
||||
static void
|
||||
nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
|
||||
const u8 *frame, size_t len,
|
||||
struct nlattr *ack, struct nlattr *cookie);
|
||||
|
||||
|
||||
static const char * nl80211_command_to_string(enum nl80211_commands cmd)
|
||||
{
|
||||
#define C2S(x) case x: return #x;
|
||||
|
@ -700,6 +706,16 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
|
|||
WLAN_FC_GET_STYPE(fc), (long long unsigned int) cookie_val,
|
||||
cookie ? "" : "(N/A)", ack != NULL);
|
||||
|
||||
if (cookie_val && cookie_val == drv->eapol_tx_cookie &&
|
||||
len >= ETH_HLEN &&
|
||||
WPA_GET_BE16(frame + 2 * ETH_ALEN) == ETH_P_PAE) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Work around misdelivered control port TX status for EAPOL");
|
||||
nl80211_control_port_frame_tx_status(drv, frame, len, ack,
|
||||
cookie);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
|
||||
return;
|
||||
|
||||
|
@ -2561,31 +2577,23 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv,
|
|||
|
||||
static void
|
||||
nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
|
||||
struct nlattr **tb)
|
||||
const u8 *frame, size_t len,
|
||||
struct nlattr *ack, struct nlattr *cookie)
|
||||
{
|
||||
bool acked = tb[NL80211_ATTR_ACK];
|
||||
union wpa_event_data event;
|
||||
const u8 *frame;
|
||||
size_t frame_len;
|
||||
|
||||
if (!tb[NL80211_ATTR_FRAME] || !tb[NL80211_ATTR_COOKIE])
|
||||
return;
|
||||
|
||||
frame = nla_data(tb[NL80211_ATTR_FRAME]);
|
||||
frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
|
||||
if (frame_len < ETH_HLEN)
|
||||
if (!cookie || len < ETH_HLEN)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Control port TX status (ack=%d), cookie=%llu",
|
||||
acked, (long long unsigned int)
|
||||
nla_get_u64(tb[NL80211_ATTR_COOKIE]));
|
||||
ack != NULL, (long long unsigned int) nla_get_u64(cookie));
|
||||
|
||||
os_memset(&event, 0, sizeof(event));
|
||||
event.eapol_tx_status.dst = frame;
|
||||
event.eapol_tx_status.data = frame + ETH_HLEN;
|
||||
event.eapol_tx_status.data_len = frame_len - ETH_HLEN;
|
||||
event.eapol_tx_status.ack = acked;
|
||||
event.eapol_tx_status.data_len = len - ETH_HLEN;
|
||||
event.eapol_tx_status.ack = ack != NULL;
|
||||
wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
|
||||
}
|
||||
|
||||
|
@ -2809,7 +2817,13 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
|
|||
nla_len(frame));
|
||||
break;
|
||||
case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS:
|
||||
nl80211_control_port_frame_tx_status(drv, tb);
|
||||
if (!frame)
|
||||
break;
|
||||
nl80211_control_port_frame_tx_status(drv,
|
||||
nla_data(frame),
|
||||
nla_len(frame),
|
||||
tb[NL80211_ATTR_ACK],
|
||||
tb[NL80211_ATTR_COOKIE]);
|
||||
break;
|
||||
default:
|
||||
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
|
||||
|
|
Loading…
Add table
Reference in a new issue