From d63f59d3cdca4a33d17d15ad72073ec2a6905f21 Mon Sep 17 00:00:00 2001 From: sephe Date: Thu, 26 Apr 2007 12:59:14 +0000 Subject: [PATCH] - Factor out ieee80211_reset_state() from ieee80211_newstate(), so 802.11 layer can clean up its internal state machine without state changing or going through driver code. - Merge sta_disassoc() and sta_disauth() into sta_disconnect(), which sends disassoc to associated STA and deauth to authenticating STA. - Call ieee80211_reset_state(), if operational mode is going to be changed, so we will do a proper state machine clean up. In the original way, if we are acting as AP and switch directly to act as STA, we will send out wrong management frames. - Call ieee80211_reset_state(), if PHY is going to be changed. This prevents panic (due to a proper assertion) under following scenario: o Current PHY of the AP is 11b. o An 11b STA joins the BSS created by the AP. Since AP's current PHY is 11b, this STA will not be counted as long slot time STA, i.e. long slot time STA count left untouched. o Switch AP's PHY to 11g. AP will panick (long slot time STA count is zero, while there is a long slot time STA associated, in ieee80211_node_leave_11g()). The assertion fails, because 802.11 state machine is doing its clean up as if AP were using 11g PHY, but it actually used 11b PHY. --- sys/netproto/802_11/ieee80211_proto.h | 3 +- sys/netproto/802_11/wlan/ieee80211.c | 23 ++++- sys/netproto/802_11/wlan/ieee80211_proto.c | 131 ++++++++++++++++------------- 3 files changed, 96 insertions(+), 61 deletions(-) diff --git a/sys/netproto/802_11/ieee80211_proto.h b/sys/netproto/802_11/ieee80211_proto.h index 9185358338..3a7184f0d0 100644 --- a/sys/netproto/802_11/ieee80211_proto.h +++ b/sys/netproto/802_11/ieee80211_proto.h @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_proto.h,v 1.11.2.5 2006/02/12 19:00:39 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/ieee80211_proto.h,v 1.11 2007/04/22 04:35:12 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/ieee80211_proto.h,v 1.12 2007/04/26 12:59:14 sephe Exp $ */ #ifndef _NET80211_IEEE80211_PROTO_H_ #define _NET80211_IEEE80211_PROTO_H_ @@ -222,6 +222,7 @@ void ieee80211_wme_updateparams(struct ieee80211com *); #define ieee80211_new_state(_ic, _nstate, _arg) \ (((_ic)->ic_newstate)((_ic), (_nstate), (_arg))) +void ieee80211_reset_state(struct ieee80211com *, enum ieee80211_state); void ieee80211_beacon_miss(struct ieee80211com *); void ieee80211_print_essid(const uint8_t *, int); void ieee80211_print_rateset(const struct ieee80211_rateset *); diff --git a/sys/netproto/802_11/wlan/ieee80211.c b/sys/netproto/802_11/wlan/ieee80211.c index fe36847b84..3977bab2e0 100644 --- a/sys/netproto/802_11/wlan/ieee80211.c +++ b/sys/netproto/802_11/wlan/ieee80211.c @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211.c,v 1.19.2.7 2006/03/11 19:25:23 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211.c,v 1.14 2007/04/01 13:59:41 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211.c,v 1.15 2007/04/26 12:59:14 sephe Exp $ */ /* @@ -667,6 +667,16 @@ ieee80211_media_change(struct ifnet *ifp) * Handle operating mode change. */ if (ic->ic_opmode != newopmode) { + /* + * Before committing operational mode change, we reset the + * internal state machine here, so the resetting is performed + * using the current operational mode instead of the new one. + * + * NB: It is safe to reset the internal state machine here, + * since all the parameters have been verified. + */ + ieee80211_reset_state(ic, ic->ic_state); + ic->ic_opmode = newopmode; switch (newopmode) { case IEEE80211_M_AHDEMO: @@ -850,6 +860,17 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) } /* + * Before committing any changes according to the new phymode, + * we reset the internal state machine first, so the resetting + * will be based on the current phymode instead of the new one. + * + * NB: We have verified that phymode is acceptable, so it is + * safe to reset the internal state machine here. + */ + if (ic->ic_bss) /* NB: can be called before lateattach */ + ieee80211_reset_state(ic, ic->ic_state); + + /* * Calculate the active channel set. */ memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active)); diff --git a/sys/netproto/802_11/wlan/ieee80211_proto.c b/sys/netproto/802_11/wlan/ieee80211_proto.c index 6360b2a065..561fe0e340 100644 --- a/sys/netproto/802_11/wlan/ieee80211_proto.c +++ b/sys/netproto/802_11/wlan/ieee80211_proto.c @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.17.2.9 2006/03/13 03:10:31 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_proto.c,v 1.11 2007/04/22 04:35:12 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_proto.c,v 1.12 2007/04/26 12:59:14 sephe Exp $ */ /* @@ -954,7 +954,7 @@ back: } static void -sta_disassoc(void *arg, struct ieee80211_node *ni) +sta_disconnect(void *arg, struct ieee80211_node *ni) { struct ieee80211com *ic = arg; @@ -962,16 +962,77 @@ sta_disassoc(void *arg, struct ieee80211_node *ni) IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_ASSOC_LEAVE); ieee80211_node_leave(ic, ni); + } else if (ni->ni_flags & IEEE80211_NODE_AREF) { + IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_ASSOC_LEAVE); + ieee80211_node_leave(ic, ni); } } -static void -sta_deauth(void *arg, struct ieee80211_node *ni) +void +ieee80211_reset_state(struct ieee80211com *ic, + enum ieee80211_state cur_state) { - struct ieee80211com *ic = arg; + struct ieee80211_node *ni; + + IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, + "%s reset internal state machine (%s)\n", + __func__, ieee80211_state_name[cur_state]); + + ni = ic->ic_bss; + KASSERT(ni != NULL, ("empty ic_bss\n")); + + switch (cur_state) { + case IEEE80211_S_INIT: + break; + case IEEE80211_S_RUN: + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + /* + * Avoid sending disassoc to self. This could happen + * when operational mode is switched directly from + * HOSTAP/IBSS to STA. + */ + if (!IEEE80211_ADDR_EQ(ic->ic_myaddr, ni->ni_macaddr)) { + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DISASSOC, + IEEE80211_REASON_ASSOC_LEAVE); + ieee80211_sta_leave(ic, ni); + } + break; + case IEEE80211_M_HOSTAP: + ieee80211_iterate_nodes(&ic->ic_sta, + sta_disconnect, ic); + break; + default: + break; + } + break; + case IEEE80211_S_ASSOC: + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + /* + * Avoid sending deauth to self. + */ + if (!IEEE80211_ADDR_EQ(ic->ic_myaddr, ni->ni_macaddr)) { + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_LEAVE); + } + break; + default: + break; + } + break; + case IEEE80211_S_SCAN: + ieee80211_cancel_scan(ic); + /* FALL THROUGH */ + case IEEE80211_S_AUTH: + break; + } - IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_ASSOC_LEAVE); + ieee80211_drain_mgtq(&ic->ic_mgtq); + ieee80211_reset_bss(ic); } static int @@ -989,62 +1050,14 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg if (ic->ic_flags_ext & IEEE80211_FEXT_SWBMISS) callout_stop(&ic->ic_swbmiss); switch (nstate) { - case IEEE80211_S_INIT: { - int reset = 1; - - switch (ostate) { - case IEEE80211_S_INIT: - reset = 0; - break; - case IEEE80211_S_RUN: - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DISASSOC, - IEEE80211_REASON_ASSOC_LEAVE); - ieee80211_sta_leave(ic, ni); - break; - case IEEE80211_M_HOSTAP: - ieee80211_iterate_nodes(&ic->ic_sta, - sta_disassoc, ic); - break; - default: - break; - } - break; - case IEEE80211_S_ASSOC: - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_AUTH_LEAVE); - break; - case IEEE80211_M_HOSTAP: - ieee80211_iterate_nodes(&ic->ic_sta, - sta_deauth, ic); - break; - default: - break; - } - break; - case IEEE80211_S_SCAN: - ieee80211_cancel_scan(ic); - /* FALL THROUGH */ - case IEEE80211_S_AUTH: - break; - } - - if (reset) { - ic->ic_mgt_timer = 0; - ieee80211_drain_mgtq(&ic->ic_mgtq); - ieee80211_reset_bss(ic); - } + case IEEE80211_S_INIT: + ieee80211_reset_state(ic, ostate); + ic->ic_mgt_timer = 0; if (ic->ic_auth->ia_detach != NULL) ic->ic_auth->ia_detach(ic); break; - } - + case IEEE80211_S_SCAN: switch (ostate) { case IEEE80211_S_INIT: -- 2.11.4.GIT