AP: Use QoS nullfunc for connection poll

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>
This commit is contained in:
Johannes Berg 2011-10-01 21:04:11 +03:00 committed by Jouni Malinen
parent ed908a55da
commit 1473f95e98

View file

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