]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
AP: Do station poll in driver wrapper
authorJohannes Berg <johannes.berg@intel.com>
Thu, 20 Oct 2011 18:03:08 +0000 (21:03 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 20 Oct 2011 18:03:08 +0000 (21:03 +0300)
This offloads the station polling to driver wrappers, which may offload
it again to the driver. The hostap driver wrapper uses "real" data
frames while nl80211 uses null data frames.

Also add a specific event to indicate that a poll was successful for
future use with the nl80211 driver.

12 files changed:
src/ap/ap_drv_ops.h
src/ap/drv_callbacks.c
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/sta_info.c
src/drivers/driver.h
src/drivers/driver_hostap.c
src/drivers/driver_ndis.c
src/drivers/driver_nl80211.c
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/events.c

index 3321e57cd84a294e9c76a981a29abca85f3205b4..ebb6eff1944e906f90e0ae456e8c8f33d0d29cba 100644 (file)
@@ -207,4 +207,13 @@ static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
        return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
 }
 
+static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
+                                          const u8 *own_addr, const u8 *addr,
+                                          int qos)
+{
+       if (hapd->driver == NULL || hapd->driver->poll_client == NULL)
+               return;
+       hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
+}
+
 #endif /* AP_DRV_OPS */
index 7020ac3682a7a0dbbb1f73d282f7f24b9fdf343f..2dbf6ea7337d77255ed1718328bfe1d3e5951a83 100644 (file)
@@ -549,6 +549,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        break;
                }
                break;
+       case EVENT_DRIVER_CLIENT_POLL_OK:
+               hostapd_client_poll_ok(hapd, data->client_poll.addr);
+               break;
        case EVENT_RX_FROM_UNKNOWN:
                hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
                                            data->rx_from_unknown.len);
index 4b7fb2e240ce4f8b60ceaf7974e90a945e18d0b4..2b24c3fc20de4efc234352bc9682abd1915830d9 100644 (file)
@@ -1735,6 +1735,32 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
 }
 
 
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
+{
+       struct sta_info *sta;
+       struct hostapd_iface *iface = hapd->iface;
+
+       sta = ap_get_sta(hapd, addr);
+       if (sta == NULL && iface->num_bss > 1) {
+               size_t j;
+               for (j = 0; j < iface->num_bss; j++) {
+                       hapd = iface->bss[j];
+                       sta = ap_get_sta(hapd, addr);
+                       if (sta)
+                               break;
+               }
+       }
+       if (sta == NULL)
+               return;
+       if (!(sta->flags & WLAN_STA_PENDING_POLL))
+               return;
+
+       wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
+                  "activity poll", MAC2STR(sta->addr));
+       sta->flags &= ~WLAN_STA_PENDING_POLL;
+}
+
+
 void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
                                int wds)
 {
index 670640077375c659b0e7151fea0a6a716e80736e..b3580600865aa78b3fe31d99cbde48c494eb1d20 100644 (file)
@@ -75,5 +75,6 @@ u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
 int hostapd_update_time_adv(struct hostapd_data *hapd);
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
 
 #endif /* IEEE802_11_H */
index 958edd3f2d06c098a70a7a618dc21abb6c485465..d82b9ce86101ece2dfb54b8948dc2d24df5b1a2c 100644 (file)
@@ -319,52 +319,10 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
 
        if (sta->timeout_next == STA_NULLFUNC &&
            (sta->flags & WLAN_STA_ASSOC)) {
-#ifndef CONFIG_NATIVE_WINDOWS
-               /* send data frame to poll STA and check whether this frame
-                * is ACKed */
-               struct {
-                       struct ieee80211_hdr hdr;
-                       u16 qos_ctl;
-               } STRUCT_PACKED nulldata;
-               int size = sizeof(struct ieee80211_hdr);
-
-               wpa_printf(MSG_DEBUG, "  Polling STA with data frame");
+               wpa_printf(MSG_DEBUG, "  Polling STA");
                sta->flags |= WLAN_STA_PENDING_POLL;
-
-               os_memset(&nulldata, 0, sizeof(nulldata));
-               if (hapd->driver &&
-                   os_strcmp(hapd->driver->name, "hostap") == 0) {
-                       /*
-                        * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
-                        * but it is apparently not retried so TX Exc events
-                        * are not received for it.
-                        */
-                       nulldata.hdr.frame_control =
-                               IEEE80211_FC(WLAN_FC_TYPE_DATA,
-                                            WLAN_FC_STYPE_DATA);
-               } else {
-                       if (sta->flags & WLAN_STA_WMM) {
-                               nulldata.hdr.frame_control =
-                                       IEEE80211_FC(WLAN_FC_TYPE_DATA,
-                                                    WLAN_FC_STYPE_QOS_NULL);
-                               size = sizeof(nulldata);
-                       } else
-                               nulldata.hdr.frame_control =
-                                       IEEE80211_FC(WLAN_FC_TYPE_DATA,
-                                                    WLAN_FC_STYPE_NULLFUNC);
-               }
-
-               nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
-               os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, sta->addr,
-                         ETH_ALEN);
-               os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
-                         ETH_ALEN);
-               os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, hapd->own_addr,
-                         ETH_ALEN);
-
-               if (hostapd_drv_send_mlme(hapd, &nulldata, size) < 0)
-                       perror("ap_handle_timer: send");
-#endif /* CONFIG_NATIVE_WINDOWS */
+               hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
+                                       sta->flags & WLAN_STA_WMM);
        } else if (sta->timeout_next != STA_REMOVE) {
                int deauth = sta->timeout_next == STA_DEAUTH;
 
index 3c9f91e4aae7048761789dc2fe4a6ac1956cd41e..3c0ef2ae2f852f5b4ff98c707dad1bce4ee49ccb 100644 (file)
@@ -2501,6 +2501,20 @@ struct wpa_driver_ops {
         * sched_scan is supported.
         */
        int (*stop_sched_scan)(void *priv);
+
+       /**
+        * poll_client - Probe (null data or such) the given station
+        * @priv: Private driver interface data
+        * @own_addr: MAC address of sending interface
+        * @addr: MAC address of the station to probe
+        * @qos: Indicates whether station is QoS station
+        *
+        * This function is used to verify whether an associated station is
+        * still present. This function does not need to be implemented if the
+        * driver provides such inactivity polling mechanism.
+        */
+       void (*poll_client)(void *priv, const u8 *own_addr,
+                           const u8 *addr, int qos);
 };
 
 
@@ -2918,7 +2932,15 @@ enum wpa_event_type {
        /**
         * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped
         */
-       EVENT_SCHED_SCAN_STOPPED
+       EVENT_SCHED_SCAN_STOPPED,
+
+       /**
+        * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll
+        *
+        * This event indicates that the station responded to the poll
+        * initiated with @poll_client.
+        */
+       EVENT_DRIVER_CLIENT_POLL_OK
 };
 
 
@@ -3472,6 +3494,14 @@ union wpa_event_data {
                const u8 *bssid;
                const u8 *replay_ctr;
        } driver_gtk_rekey;
+
+       /**
+        * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events
+        * @addr: station address
+        */
+       struct client_poll {
+               u8 addr[ETH_ALEN];
+       } client_poll;
 };
 
 /**
index ad9a022734c6a3242fd6f39ad8598e2d55c4f55f..7a97ed52977927a7ca5f42ba36fa8c6ba60fba0d 100644 (file)
@@ -1143,6 +1143,33 @@ static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
        return mode;
 }
 
+
+static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
+                                         const u8 *addr, int qos)
+{
+       struct ieee80211_hdr hdr;
+
+       os_memset(&hdr, 0, sizeof(hdr));
+
+       /*
+        * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+        * but it is apparently not retried so TX Exc events
+        * are not received for it.
+        * This is the reason the driver overrides the default
+        * handling.
+        */
+       hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA,
+                                        WLAN_FC_STYPE_DATA);
+
+       hdr.frame_control |=
+               host_to_le16(WLAN_FC_FROMDS);
+       os_memcpy(hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+       os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+       os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+       hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr));
+}
+
 #else /* HOSTAPD */
 
 struct wpa_driver_hostap_data {
@@ -1650,6 +1677,7 @@ const struct wpa_driver_ops wpa_driver_hostap_ops = {
        .get_hw_feature_data = hostap_get_hw_feature_data,
        .set_ap_wps_ie = hostap_set_ap_wps_ie,
        .set_freq = hostap_set_freq,
+       .poll_client = wpa_driver_hostap_poll_client,
 #else /* HOSTAPD */
        .get_bssid = wpa_driver_hostap_get_bssid,
        .get_ssid = wpa_driver_hostap_get_ssid,
index d77cc1029d12b014566bd749e0689e23e60f7fc3..31339f5aa35a98d6641b6af156109ff0522b1180 100644 (file)
@@ -3328,5 +3328,6 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
        NULL /* add_tspec */,
        NULL /* add_sta_node */,
        NULL /* sched_scan */,
-       NULL /* stop_sched_scan */
+       NULL /* stop_sched_scan */,
+       NULL /* poll_client */
 };
index 5693f59bd30c6fd18eb4f2a32e08fa56d3287aa8..0c653766b3063181be5cde2ec58cc5479218d554 100644 (file)
@@ -7329,6 +7329,43 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
 }
 
 
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+                               int qos)
+{
+       struct i802_bss *bss = priv;
+       struct {
+               struct ieee80211_hdr hdr;
+               u16 qos_ctl;
+       } STRUCT_PACKED nulldata;
+       size_t size;
+
+       /* Send data frame to poll STA and check whether this frame is ACKed */
+
+       os_memset(&nulldata, 0, sizeof(nulldata));
+
+       if (qos) {
+               nulldata.hdr.frame_control =
+                       IEEE80211_FC(WLAN_FC_TYPE_DATA,
+                                    WLAN_FC_STYPE_QOS_NULL);
+               size = sizeof(nulldata);
+       } else {
+               nulldata.hdr.frame_control =
+                       IEEE80211_FC(WLAN_FC_TYPE_DATA,
+                                    WLAN_FC_STYPE_NULLFUNC);
+               size = sizeof(struct ieee80211_hdr);
+       }
+
+       nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
+       os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+       os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+       os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size) < 0)
+               wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
+                          "send poll frame");
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -7399,4 +7436,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .remove_pmkid = nl80211_remove_pmkid,
        .flush_pmkid = nl80211_flush_pmkid,
        .set_rekey_info = nl80211_set_rekey_info,
+       .poll_client = nl80211_poll_client,
 };
index 7b0cd2118e648f58aa2738f14c74b545e6c1148c..8f83a6bae8b558db5023cfae5347744341b8ecc1 100644 (file)
@@ -566,6 +566,16 @@ void ap_tx_status(void *ctx, const u8 *addr,
 }
 
 
+void ap_client_poll_ok(void *ctx, const u8 *addr)
+{
+#ifdef NEED_AP_MLME
+       struct wpa_supplicant *wpa_s = ctx;
+       if (wpa_s->ap_iface)
+               hostapd_client_poll_ok(wpa_s->ap_iface->bss[0], addr);
+#endif /* NEED_AP_MLME */
+}
+
+
 void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len)
 {
 #ifdef NEED_AP_MLME
index b913be3e228a3f4f26e832b51a67ce560a183b6f..b94ead7f0188d1ead6b11c9651fdf55a2d365542 100644 (file)
@@ -41,6 +41,7 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
                                 size_t buflen, int verbose);
 void ap_tx_status(void *ctx, const u8 *addr,
                  const u8 *buf, size_t len, int ack);
+void ap_client_poll_ok(void *ctx, const u8 *addr);
 void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len);
 void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt);
 void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok);
index 43b22ab54396e9d9bc1065cb64a45910c866f611..232a7768fd2dc06b6a097608b5e842607494e2a1 100644 (file)
@@ -2027,6 +2027,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #endif /* CONFIG_AP */
                break;
 #ifdef CONFIG_AP
+       case EVENT_DRIVER_CLIENT_POLL_OK:
+               ap_client_poll_ok(wpa_s, data->client_poll.addr);
+               break;
        case EVENT_RX_FROM_UNKNOWN:
                if (wpa_s->ap_iface == NULL)
                        break;