aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2003-06-25 04:40:23 (GMT)
committerJouni Malinen <j@w1.fi>2003-06-25 04:40:23 (GMT)
commitc69aeb5cf881c0d2a4842b3dcb4a09ffba1fbc82 (patch)
treeac9def78058a1f63f62c79fb5aeec56e7ccdbb02
parent996d0048264917bac7696158a6754af3b5fff035 (diff)
downloadhostap-history-c69aeb5cf881c0d2a4842b3dcb4a09ffba1fbc82.zip
hostap-history-c69aeb5cf881c0d2a4842b3dcb4a09ffba1fbc82.tar.gz
hostap-history-c69aeb5cf881c0d2a4842b3dcb4a09ffba1fbc82.tar.bz2
Changed STA activity polling to use TX status callback instead of
counting TX Exc events. This fixes expiration of power saving STAs when using kernel driver for 802.11 management. This should also fix hostapd, but since kernel driver does not yet use power save buffering for wlan#ap interface, this does not really work properly.
-rw-r--r--driver/modules/hostap_ap.c70
-rw-r--r--driver/modules/hostap_ap.h4
-rw-r--r--driver/modules/hostap_wlan.h3
-rw-r--r--hostapd/ap.h1
-rw-r--r--hostapd/receive.c15
-rw-r--r--hostapd/sta_info.c10
6 files changed, 57 insertions, 46 deletions
diff --git a/driver/modules/hostap_ap.c b/driver/modules/hostap_ap.c
index f561a9f..44054d6 100644
--- a/driver/modules/hostap_ap.c
+++ b/driver/modules/hostap_ap.c
@@ -277,9 +277,9 @@ static void ap_handle_timer(unsigned long data)
/* station activity detected; reset timeout state */
sta->timeout_next = STA_NULLFUNC;
next_time = sta->last_rx + ap->max_inactivity;
- } else if (sta->timeout_next == STA_DISASSOC && sta->txexc == 0) {
- /* data nullfunc frame poll did not produce TX errors; assume
- * station ACKed it */
+ } else if (sta->timeout_next == STA_DISASSOC &&
+ !(sta->flags & WLAN_STA_PENDING_POLL)) {
+ /* STA ACKed data nullfunc frame poll */
sta->timeout_next = STA_NULLFUNC;
next_time = jiffies + ap->max_inactivity;
}
@@ -321,13 +321,13 @@ static void ap_handle_timer(unsigned long data)
} else if (sta->timeout_next == STA_NULLFUNC) {
/* send data frame to poll STA and check whether this frame
* is ACKed */
- sta->txexc = 0;
/* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but
* it is apparently not retried so TX Exc events are not
* received for it */
+ sta->flags |= WLAN_STA_PENDING_POLL;
prism2_send_mgmt(local->dev, WLAN_FC_TYPE_DATA,
WLAN_FC_STYPE_DATA, NULL, 0, 1,
- sta->addr, 0);
+ sta->addr, ap->tx_callback_poll);
} else {
int deauth = sta->timeout_next == STA_DEAUTH;
u16 resp;
@@ -832,6 +832,33 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
}
dev_kfree_skb(skb);
}
+
+/* Called only as a tasklet (software IRQ); TX callback for poll frames used
+ * in verifying whether the STA is still present. */
+static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
+{
+ struct ap_data *ap = data;
+ struct net_device *dev = ap->local->dev;
+ struct hostap_ieee80211_hdr *hdr;
+ struct sta_info *sta;
+
+ if (skb->len < 24)
+ goto fail;
+ hdr = (struct hostap_ieee80211_hdr *) skb->data;
+ if (ok) {
+ spin_lock(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, hdr->addr1);
+ if (sta)
+ sta->flags &= ~WLAN_STA_PENDING_POLL;
+ spin_unlock(&ap->sta_table_lock);
+ } else {
+ PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity "
+ "poll frame\n", dev->name, MAC2STR(hdr->addr1));
+ }
+
+ fail:
+ dev_kfree_skb(skb);
+}
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
@@ -886,7 +913,10 @@ void hostap_init_data(local_info_t *local)
hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap);
ap->tx_callback_assoc =
hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap);
- if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0)
+ ap->tx_callback_poll =
+ hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap);
+ if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 ||
+ ap->tx_callback_poll == 0)
printk(KERN_WARNING "%s: failed to register TX callback for "
"AP\n", local->dev->name);
@@ -1056,7 +1086,7 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
}
p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n"
- "flags=0x%04x%s%s%s%s%s%s\n"
+ "flags=0x%04x%s%s%s%s%s%s%s\n"
"capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
sta->ap ? "AP" : "STA",
MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid,
@@ -1067,6 +1097,7 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
sta->flags & WLAN_STA_TIM ? " TIM" : "",
sta->flags & WLAN_STA_PERM ? " PERM" : "",
sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "",
+ sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "",
sta->capability, sta->listen_interval);
/* supported_rates: 500 kbit/s units with msb ignored */
for (i = 0; i < sizeof(sta->supported_rates); i++)
@@ -1081,8 +1112,7 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
"last_rx: silence=%d signal=%d rate=%d\n"
"tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n"
"tx[11M]=%d\n"
- "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n"
- "txexc=%d\n",
+ "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n",
jiffies, sta->last_auth, sta->last_assoc, sta->last_rx,
sta->last_tx,
sta->rx_packets, sta->tx_packets, sta->rx_bytes,
@@ -1091,8 +1121,7 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
sta->last_rx_signal, sta->last_rx_rate,
sta->tx_rate, sta->tx_count[0], sta->tx_count[1],
sta->tx_count[2], sta->tx_count[3], sta->rx_count[0],
- sta->rx_count[1], sta->rx_count[2], sta->rx_count[3],
- sta->txexc);
+ sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);
if (sta->crypt && sta->crypt->ops)
p += sprintf(p, "crypt=%s\n", sta->crypt->ops->name);
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
@@ -2653,7 +2682,6 @@ static int prism2_hostapd_get_info_sta(struct ap_data *ap,
return -ENOENT;
param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ;
- param->u.get_info_sta.txexc = sta->txexc;
atomic_dec(&sta->users);
@@ -2661,21 +2689,6 @@ static int prism2_hostapd_get_info_sta(struct ap_data *ap,
}
-static int prism2_hostapd_reset_txexc_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta)
- sta->txexc = 0;
- spin_unlock_bh(&ap->sta_table_lock);
-
- return sta ? 0 : -ENOENT;
-}
-
-
static int prism2_hostapd_set_flags_sta(struct ap_data *ap,
struct prism2_hostapd_param *param)
{
@@ -2709,8 +2722,6 @@ static int prism2_hostapd(struct ap_data *ap,
return prism2_hostapd_remove_sta(ap, param);
case PRISM2_HOSTAPD_GET_INFO_STA:
return prism2_hostapd_get_info_sta(ap, param);
- case PRISM2_HOSTAPD_RESET_TXEXC_STA:
- return prism2_hostapd_reset_txexc_sta(ap, param);
case PRISM2_HOSTAPD_SET_FLAGS_STA:
return prism2_hostapd_set_flags_sta(ap, param);
default:
@@ -2903,7 +2914,6 @@ void hostap_handle_sta_tx_exc(local_info_t *local,
return;
}
- sta->txexc++;
sta->tx_since_last_failure = 0;
sta->tx_consecutive_exc++;
diff --git a/driver/modules/hostap_ap.h b/driver/modules/hostap_ap.h
index 7ac6955..afbfce9 100644
--- a/driver/modules/hostap_ap.h
+++ b/driver/modules/hostap_ap.h
@@ -25,6 +25,7 @@
* controlling whether STA is authorized to
* send and receive non-IEEE 802.1X frames
*/
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
#define WLAN_RATE_1M BIT(0)
#define WLAN_RATE_2M BIT(1)
@@ -78,7 +79,6 @@ struct sta_info {
u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate)
*/
u32 tx_since_last_failure;
- u32 txexc;
u32 tx_consecutive_exc;
struct prism2_crypt_data *crypt;
@@ -212,7 +212,7 @@ struct ap_data {
*/
struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
- u16 tx_callback_auth, tx_callback_assoc;
+ u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll;
/* WEP operations for generating challenges to be used with shared key
* authentication */
diff --git a/driver/modules/hostap_wlan.h b/driver/modules/hostap_wlan.h
index 438fdd6..f7dbe93 100644
--- a/driver/modules/hostap_wlan.h
+++ b/driver/modules/hostap_wlan.h
@@ -922,7 +922,7 @@ enum {
PRISM2_HOSTAPD_ADD_STA = 2,
PRISM2_HOSTAPD_REMOVE_STA = 3,
PRISM2_HOSTAPD_GET_INFO_STA = 4,
- PRISM2_HOSTAPD_RESET_TXEXC_STA = 5,
+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
PRISM2_SET_ENCRYPTION = 6,
PRISM2_GET_ENCRYPTION = 7,
PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
@@ -946,7 +946,6 @@ struct prism2_hostapd_param {
} add_sta;
struct {
u32 inactive_sec;
- u32 txexc;
} get_info_sta;
struct {
u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
diff --git a/hostapd/ap.h b/hostapd/ap.h
index 24bfe14..5fdc387 100644
--- a/hostapd/ap.h
+++ b/hostapd/ap.h
@@ -8,6 +8,7 @@
#define WLAN_STA_TIM BIT(3)
#define WLAN_STA_PERM BIT(4)
#define WLAN_STA_AUTHORIZED BIT(5)
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
#define WLAN_RATE_1M BIT(0)
#define WLAN_RATE_2M BIT(1)
diff --git a/hostapd/receive.c b/hostapd/receive.c
index e07bedb..934a0c4 100644
--- a/hostapd/receive.c
+++ b/hostapd/receive.c
@@ -115,6 +115,8 @@ static void handle_tx_callback(hostapd *hapd, char *buf, size_t len, int ok)
{
struct ieee80211_hdr *hdr;
u16 fc, type, stype;
+ struct sta_info *sta;
+
hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control);
@@ -134,10 +136,15 @@ static void handle_tx_callback(hostapd *hapd, char *buf, size_t len, int ok)
case WLAN_FC_TYPE_DATA:
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
"DATA (TX callback) %s\n", ok ? "ACK" : "fail");
- /* TODO: could replace TXExc counter hack with kernel driver
- * in data polling for inactivity check with the new TX
- * callback.. */
- /* handle_data_cb(hapd, buf, len, stype, ok); */
+ sta = ap_get_sta(hapd, hdr->addr1);
+ if (sta && sta->flags & WLAN_STA_PENDING_POLL) {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "STA " MACSTR
+ " %s pending activity poll\n",
+ MAC2STR(sta->addr),
+ ok ? "ACKed" : "did not ACK");
+ if (ok)
+ sta->flags &= ~WLAN_STA_PENDING_POLL;
+ }
break;
default:
printf("unknown TX callback frame type %d\n", type);
diff --git a/hostapd/sta_info.c b/hostapd/sta_info.c
index 281079a..8b0e51e 100644
--- a/hostapd/sta_info.c
+++ b/hostapd/sta_info.c
@@ -168,7 +168,6 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
printf(" Could not get station info from kernel driver.\n");
/* assume the station has expired */
param.u.get_info_sta.inactive_sec = AP_MAX_INACTIVITY + 1;
- param.u.get_info_sta.txexc = 1;
}
if (param.u.get_info_sta.inactive_sec < AP_MAX_INACTIVITY) {
@@ -179,7 +178,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
next_time = AP_MAX_INACTIVITY -
param.u.get_info_sta.inactive_sec;
} else if (sta->timeout_next == STA_DISASSOC &&
- param.u.get_info_sta.txexc == 0) {
+ !(sta->flags & WLAN_STA_PENDING_POLL)) {
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
" Station has ACKed data poll\n");
/* data nullfunc frame poll did not produce TX errors; assume
@@ -201,12 +200,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
" Polling STA with data frame\n");
- memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_RESET_TXEXC_STA;
- memcpy(param.sta_addr, sta->addr, ETH_ALEN);
- if (hostapd_ioctl(hapd, &param, sizeof(param))) {
- printf(" Could not reset station TX Exc counter\n");
- }
+ sta->flags |= WLAN_STA_PENDING_POLL;
/* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but
* it is apparently not retried so TX Exc events are not