]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Handle control port TX status events over nl80211
authorMarkus Theil <markus.theil@tu-ilmenau.de>
Wed, 10 Jun 2020 08:32:57 +0000 (10:32 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 21 Jun 2020 14:55:26 +0000 (17:55 +0300)
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>
src/drivers/driver.h
src/drivers/driver_common.c
src/drivers/driver_nl80211_capa.c
src/drivers/driver_nl80211_event.c

index 0ecda49dd1df2ab824206d17bcc1c81fa043c847..cb412cbfe292c04cf3bc2eaee7af924f222d81f7 100644 (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) \
index 23a6a42931020c4668a44672d841d784a646647b..a7ebe956680b7a6289693fc1792372f0e785ca0d 100644 (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
index 5d255815315f174a6d8f6eb3676c4ef1eb48609b..46f61fdbf9255104fb1f6b1ebdd3d1490df35eb8 100644 (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))
index 6a2de1f3c21188d94de24e95a0bb47ddb39f1f3e..1873b1826dfc4eee67c489e3e085e4e435793eeb 100644 (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);