summaryrefslogtreecommitdiff
path: root/sys/dev/ic/if_wi_hostap.c
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2003-01-21 20:09:40 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2003-01-21 20:09:40 +0000
commit505d220db494d84f01398907d0a6a9af8e971105 (patch)
tree266f75a2bae2bb07dc97f138c16afbb86edbe447 /sys/dev/ic/if_wi_hostap.c
parent1908f8cbef776236c874cdacbe9591ac4bd8fcf0 (diff)
Use a 2-level timeout for hostap. Instead of of sending a station
a deauth/disassoc packet when the inactivity timer fires, just set a flag, re-queue it and set the master wihap timer if needed. What this does is to effectively bundle (and serialize) deauth/disassoc packets so if a large number need to be sent at once we don't stomp all over the card. We also only do at most 10 stations at a time. The sta_list has been changed from a doubly linked list to a tailq. Inactive stations are kept at the head of the queue, new ones are added to the tail. Idea and OK by mickey@, prompted by an issue found by merith AT vantronix DOT net
Diffstat (limited to 'sys/dev/ic/if_wi_hostap.c')
-rw-r--r--sys/dev/ic/if_wi_hostap.c133
1 files changed, 96 insertions, 37 deletions
diff --git a/sys/dev/ic/if_wi_hostap.c b/sys/dev/ic/if_wi_hostap.c
index 111d642df87..796a6ded490 100644
--- a/sys/dev/ic/if_wi_hostap.c
+++ b/sys/dev/ic/if_wi_hostap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wi_hostap.c,v 1.22 2003/01/21 16:26:40 millert Exp $ */
+/* $OpenBSD: if_wi_hostap.c,v 1.23 2003/01/21 20:09:39 millert Exp $ */
/*
* Copyright (c) 2002
@@ -76,6 +76,7 @@
#include <dev/ic/if_wi_ieee.h>
#include <dev/ic/if_wivar.h>
+void wihap_timeout(void *v);
void wihap_sta_timeout(void *v);
struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr);
void wihap_sta_delete(struct wihap_sta_info *sta);
@@ -198,11 +199,12 @@ wihap_init(struct wi_softc *sc)
whi->apflags = WIHAPFL_ACTIVE;
- LIST_INIT(&whi->sta_list);
+ TAILQ_INIT(&whi->sta_list);
for (i = 0; i < WI_STA_HASH_SIZE; i++)
LIST_INIT(&whi->sta_hash[i]);
whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME;
+ timeout_set(&whi->tmo, wihap_timeout, sc);
}
/* wihap_sta_disassoc()
@@ -266,7 +268,6 @@ wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
/* wihap_shutdown()
*
* Disassociate all stations and free up data structures.
- * Caller must raise to splimp().
*/
void
wihap_shutdown(struct wi_softc *sc)
@@ -284,18 +285,21 @@ wihap_shutdown(struct wi_softc *sc)
s = splimp();
+ /* Disable wihap inactivity timer. */
+ timeout_del(&whi->tmo);
+
/* Delete all stations from the list. */
- for (sta = LIST_FIRST(&whi->sta_list);
- sta != LIST_END(&whi->sta_list); sta = next) {
+ for (sta = TAILQ_FIRST(&whi->sta_list);
+ sta != TAILQ_END(&whi->sta_list); sta = next) {
timeout_del(&sta->tmo);
if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
printf("wihap_shutdown: FREE(sta=0x%x)\n", sta);
- next = LIST_NEXT(sta, list);
+ next = TAILQ_NEXT(sta, list);
if (sta->challenge)
FREE(sta->challenge, M_TEMP);
FREE(sta, M_DEVBUF);
}
- LIST_INIT(&whi->sta_list);
+ TAILQ_INIT(&whi->sta_list);
/* Broadcast disassoc and deauth to all the stations. */
if (sc->wi_flags & WI_FLAGS_ATTACHED) {
@@ -328,47 +332,100 @@ addr_cmp(u_int8_t a[], u_int8_t b[])
*(u_int32_t *)(a ) == *(u_int32_t *)(b));
}
+/* wihap_sta_movetail(): move sta to the tail of the station list in whi */
+static __inline void
+wihap_sta_movetail(struct wihap_info *whi, struct wihap_sta_info *sta)
+{
+ TAILQ_REMOVE(&whi->sta_list, sta, list);
+ sta->flags &= ~WI_SIFLAGS_DEAD;
+ TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
+}
+
void
-wihap_sta_timeout(void *v)
+wihap_timeout(void *v)
{
- struct wihap_sta_info *sta = v;
- struct wi_softc *sc = sta->sc;
+ struct wi_softc *sc = v;
struct wihap_info *whi = &sc->wi_hostap_info;
- int s;
+ struct wihap_sta_info *sta, *next;
+ int i, s;
- s = splsoftnet();
+ s = splimp();
- if (sta->flags & WI_SIFLAGS_ASSOC) {
- if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
- printf("wihap_timer: disassoc due to inactivity: %s\n",
- ether_sprintf(sta->addr));
+ for (i = 10, sta = TAILQ_FIRST(&whi->sta_list);
+ i != 0 && sta != TAILQ_END(&whi->sta_list) &&
+ (sta->flags & WI_SIFLAGS_DEAD); i--, sta = next) {
+ next = TAILQ_NEXT(sta, list);
+ if (timeout_pending(&sta->tmo)) {
+ /* Became alive again, move to end of list. */
+ wihap_sta_movetail(whi, sta);
+ } else if (sta->flags & WI_SIFLAGS_ASSOC) {
+ if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
+ printf("wihap_timeout: disassoc due to inactivity: %s\n",
+ ether_sprintf(sta->addr));
+
+ /* Disassoc station. */
+ wihap_sta_disassoc(sc, sta->addr,
+ IEEE80211_REASON_ASSOC_EXPIRE);
+ sta->flags &= ~WI_SIFLAGS_ASSOC;
+
+ /*
+ * Move to end of the list and reset station timeout.
+ * We do this to make sure we don't get deauthed
+ * until inactivity_time seconds have passed.
+ */
+ wihap_sta_movetail(whi, sta);
+ timeout_add(&sta->tmo, hz * whi->inactivity_time);
+ } else if (sta->flags & WI_SIFLAGS_AUTHEN) {
+ if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
+ printf("wihap_timeout: deauth due to inactivity: %s\n",
+ ether_sprintf(sta->addr));
+
+ /* Deauthenticate station. */
+ wihap_sta_deauth(sc, sta->addr,
+ IEEE80211_REASON_AUTH_EXPIRE);
+ sta->flags &= ~WI_SIFLAGS_AUTHEN;
+
+ /* Delete the station if it's not permanent. */
+ if (sta->flags & WI_SIFLAGS_PERM)
+ wihap_sta_movetail(whi, sta);
+ else
+ wihap_sta_delete(sta);
+ }
+ }
- /* Disassoc station. */
- wihap_sta_disassoc(sc, sta->addr,
- IEEE80211_REASON_ASSOC_EXPIRE);
- sta->flags &= ~WI_SIFLAGS_ASSOC;
+ /* Restart the timeout if there are still dead stations left. */
+ sta = TAILQ_FIRST(&whi->sta_list);
+ if (sta != NULL && (sta->flags & WI_SIFLAGS_DEAD))
+ timeout_add(&whi->tmo, 1); /* still work left, requeue */
- timeout_add(&sta->tmo, hz * whi->inactivity_time);
+ splx(s);
+}
- } else if (sta->flags & WI_SIFLAGS_AUTHEN) {
+void
+wihap_sta_timeout(void *v)
+{
+ struct wihap_sta_info *sta = v;
+ struct wi_softc *sc = sta->sc;
+ struct wihap_info *whi = &sc->wi_hostap_info;
+ int s;
- if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
- printf("wihap_timer: deauth due to inactivity: %s\n",
- ether_sprintf(sta->addr));
+ s = splimp();
- /* Deauthenticate station. */
- wihap_sta_deauth(sc, sta->addr, IEEE80211_REASON_AUTH_EXPIRE);
- sta->flags &= ~WI_SIFLAGS_AUTHEN;
+ /* Mark sta as dead and move it to the head of the list. */
+ TAILQ_REMOVE(&whi->sta_list, sta, list);
+ sta->flags |= WI_SIFLAGS_DEAD;
+ TAILQ_INSERT_HEAD(&whi->sta_list, sta, list);
+
+ /* Add wihap timeout if we have not already done so. */
+ if (!timeout_pending(&whi->tmo))
+ timeout_add(&whi->tmo, hz / 10);
- /* Delete the station if it's not permanent. */
- if (!(sta->flags & WI_SIFLAGS_PERM))
- wihap_sta_delete(sta);
- }
splx(s);
}
/* wihap_sta_delete()
* Delete a single station and free up its data structure.
+ * Caller must raise to splimp().
*/
void
wihap_sta_delete(struct wihap_sta_info *sta)
@@ -381,7 +438,7 @@ wihap_sta_delete(struct wihap_sta_info *sta)
whi->asid_inuse_mask[i >> 4] &= ~(1UL << (i & 0xf));
- LIST_REMOVE(sta, list);
+ TAILQ_REMOVE(&whi->sta_list, sta, list);
LIST_REMOVE(sta, hash);
if (sta->challenge)
FREE(sta->challenge, M_TEMP);
@@ -417,7 +474,7 @@ wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr)
sta->asid = 0xc001 + i;
/* Insert in list and hash list. */
- LIST_INSERT_HEAD(&whi->sta_list, sta, list);
+ TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash);
sta->sc = sc;
@@ -494,7 +551,7 @@ wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
{
struct wihap_info *whi = &sc->wi_hostap_info;
struct wihap_sta_info *sta;
- int i;
+ int i, s;
u_int16_t algo;
u_int16_t seq;
@@ -542,7 +599,9 @@ wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
printf("wihap_auth_req: new station\n");
/* Create new station. */
+ s = splimp();
sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);
+ splx(s);
if (sta == NULL) {
/* Out of memory! */
status = IEEE80211_STATUS_TOO_MANY_STATIONS;
@@ -1231,7 +1290,7 @@ wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
reqall.nstations = whi->n_stations;
n = 0;
s = splimp();
- sta = LIST_FIRST(&whi->sta_list);
+ sta = TAILQ_FIRST(&whi->sta_list);
while (sta && reqall.size >= n+sizeof(struct hostap_sta)) {
bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN);
@@ -1246,7 +1305,7 @@ wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
if (error)
break;
- sta = LIST_NEXT(sta, list);
+ sta = TAILQ_NEXT(sta, list);
n += sizeof(struct hostap_sta);
}
splx(s);