AP: Use QoS nullfunc for connection poll
authorJohannes Berg <johannes.berg@intel.com>
Sat, 1 Oct 2011 18:04:11 +0000 (21:04 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 1 Oct 2011 18:04:11 +0000 (21:04 +0300)
When polling a station that has been inactive for a while, hostapd currently
always uses a null data frame. This is a bit strange with uAPSD clients
(though it seems to mostly work) since the EOSP bit can never be set in a
non-QoS frame. Make hostapd use QoS null data frames for probing when the
station is a QoS STA.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
src/ap/sta_info.c

index ef90bf9..958edd3 100644 (file)
@@ -322,12 +322,16 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
 #ifndef CONFIG_NATIVE_WINDOWS
                /* send data frame to poll STA and check whether this frame
                 * is ACKed */
-               struct ieee80211_hdr hdr;
+               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");
                sta->flags |= WLAN_STA_PENDING_POLL;
 
-               os_memset(&hdr, 0, sizeof(hdr));
+               os_memset(&nulldata, 0, sizeof(nulldata));
                if (hapd->driver &&
                    os_strcmp(hapd->driver->name, "hostap") == 0) {
                        /*
@@ -335,22 +339,30 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                         * but it is apparently not retried so TX Exc events
                         * are not received for it.
                         */
-                       hdr.frame_control =
+                       nulldata.hdr.frame_control =
                                IEEE80211_FC(WLAN_FC_TYPE_DATA,
                                             WLAN_FC_STYPE_DATA);
                } else {
-                       hdr.frame_control =
-                               IEEE80211_FC(WLAN_FC_TYPE_DATA,
-                                            WLAN_FC_STYPE_NULLFUNC);
+                       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);
                }
 
-               hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
-               os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
-               os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
+               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);
-               os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
 
-               if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 0)
+               if (hostapd_drv_send_mlme(hapd, &nulldata, size) < 0)
                        perror("ap_handle_timer: send");
 #endif /* CONFIG_NATIVE_WINDOWS */
        } else if (sta->timeout_next != STA_REMOVE) {