nl80211: Handle control port TX status events over nl80211

In order to retransmit faster in AP mode, hostapd can handle TX status
notifications. When using nl80211, this is currently only possible with
socket control messages. Add support for receiving such events directly
over nl80211 and detecting, if this feature is supported.

This finally allows for a clean separation between management/control
path (over nl80211) and in-kernel data path.

A follow up commit enables the feature in AP mode.

Control port TX status contains the original frame content for matching
with the current hostapd code. Furthermore, a cookie is included, which
allows for matching against outstanding cookies in the future. This
commit only prints the cookie value for debugging purposes on TX status
receive.

Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
This commit is contained in:
Markus Theil 2020-06-10 10:32:57 +02:00 committed by Jouni Malinen
parent f7c657b79f
commit 6f19cc4d78
4 changed files with 43 additions and 0 deletions

View file

@ -1931,6 +1931,8 @@ struct wpa_driver_capa {
/** Driver supports a separate control port RX for EAPOL frames */
#define WPA_DRIVER_FLAGS2_CONTROL_PORT_RX 0x0000000000000001ULL
/** Driver supports TX status reports for EAPOL frames through control port */
#define WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS 0x0000000000000002ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \

View file

@ -328,6 +328,7 @@ const char * driver_flag2_to_string(u64 flag2)
#define DF2S(x) case WPA_DRIVER_FLAGS2_ ## x: return #x
switch (flag2) {
DF2S(CONTROL_PORT_RX);
DF2S(CONTROL_PORT_TX_STATUS);
}
return "UNKNOWN";
#undef DF2S

View file

@ -620,6 +620,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH))
capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
if (ext_feature_isset(
ext_features, len,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS))
capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_VLAN_OFFLOAD))

View file

@ -138,6 +138,8 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
C2S(NL80211_CMD_CONTROL_PORT_FRAME)
C2S(NL80211_CMD_UPDATE_OWE_INFO)
C2S(NL80211_CMD_UNPROT_BEACON)
C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS)
default:
return "NL80211_CMD_UNKNOWN";
}
@ -2557,6 +2559,37 @@ 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)
{
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)
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]));
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;
wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
}
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
@ -2775,6 +2808,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
mlme_event_unprot_beacon(drv, nla_data(frame),
nla_len(frame));
break;
case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS:
nl80211_control_port_frame_tx_status(drv, tb);
break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);