mirror of
https://github.com/proski/madwifi
synced 2024-11-22 06:21:47 +03:00
Merge from madwifi-dfs r3150. Fixes for AP+STA mode state machine logic
git-svn-id: http://madwifi-project.org/svn/madwifi/trunk@3152 0192ed92-7a03-0410-a25b-9323aeb14dbd
This commit is contained in:
parent
e3d16ecc8f
commit
ec46fcf728
@ -972,27 +972,46 @@ ieee80211_init(struct net_device *dev, int forcescan)
|
||||
* 802.11 state machine as appropriate.
|
||||
* XXX parent should always be up+running
|
||||
*/
|
||||
if (IS_RUNNING(ic->ic_dev) &&
|
||||
ic->ic_roaming != IEEE80211_ROAMING_MANUAL) {
|
||||
if (IS_RUNNING(ic->ic_dev)) {
|
||||
if (vap->iv_opmode == IEEE80211_M_STA) {
|
||||
/*
|
||||
* Try to be intelligent about clocking the state
|
||||
* machine. If we're currently in RUN state then
|
||||
* we should be able to apply any new state/parameters
|
||||
* simply by re-associating. Otherwise we need to
|
||||
* re-scan to select an appropriate ap.
|
||||
*/
|
||||
if (vap->iv_state != IEEE80211_S_RUN || forcescan)
|
||||
ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
|
||||
else
|
||||
ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1);
|
||||
if(ic->ic_roaming != IEEE80211_ROAMING_MANUAL) {
|
||||
/*
|
||||
* Try to be intelligent about clocking the state
|
||||
* machine. If we're currently in RUN state then
|
||||
* we should be able to apply any new state/parameters
|
||||
* simply by re-associating. Otherwise we need to
|
||||
* re-scan to select an appropriate ap.
|
||||
*/
|
||||
if (vap->iv_state != IEEE80211_S_RUN || forcescan) {
|
||||
IEEE80211_DPRINTF(vap,
|
||||
IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
|
||||
"Bringing vap %p[%s] to %s\n",
|
||||
vap, vap->iv_nickname,
|
||||
ieee80211_state_name[IEEE80211_S_SCAN]);
|
||||
ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
|
||||
}
|
||||
else {
|
||||
IEEE80211_DPRINTF(vap,
|
||||
IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
|
||||
"Bringing vap %p[%s] to %s\n",
|
||||
vap, vap->iv_nickname,
|
||||
ieee80211_state_name[IEEE80211_S_ASSOC]);
|
||||
ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* When the old state is running the vap must
|
||||
* be brought to init.
|
||||
*/
|
||||
if (vap->iv_state == IEEE80211_S_RUN)
|
||||
if (vap->iv_state == IEEE80211_S_RUN) {
|
||||
IEEE80211_DPRINTF(vap,
|
||||
IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
|
||||
"Bringing vap %p[%s] to %s\n",
|
||||
vap, vap->iv_nickname,
|
||||
ieee80211_state_name[IEEE80211_S_INIT]);
|
||||
ieee80211_new_state(vap, IEEE80211_S_INIT, -1);
|
||||
}
|
||||
/*
|
||||
* For monitor+wds modes there's nothing to do but
|
||||
* start running. Otherwise, if this is the first
|
||||
@ -1002,9 +1021,20 @@ ieee80211_init(struct net_device *dev, int forcescan)
|
||||
*/
|
||||
if (vap->iv_opmode == IEEE80211_M_MONITOR ||
|
||||
vap->iv_opmode == IEEE80211_M_WDS) {
|
||||
IEEE80211_DPRINTF(vap,
|
||||
IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
|
||||
"Bringing vap %p[%s] to %s\n",
|
||||
vap, vap->iv_nickname,
|
||||
ieee80211_state_name[IEEE80211_S_RUN]);
|
||||
ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
|
||||
} else
|
||||
} else {
|
||||
IEEE80211_DPRINTF(vap,
|
||||
IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
|
||||
"Bringing vap %p[%s] to %s\n",
|
||||
vap, vap->iv_nickname,
|
||||
ieee80211_state_name[IEEE80211_S_SCAN]);
|
||||
ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -1263,8 +1293,6 @@ __ieee80211_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int
|
||||
enum ieee80211_state ostate;
|
||||
|
||||
ostate = vap->iv_state;
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__,
|
||||
ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
|
||||
vap->iv_state = nstate; /* state transition */
|
||||
del_timer(&vap->iv_mgtsend);
|
||||
if ((vap->iv_opmode != IEEE80211_M_HOSTAP) &&
|
||||
@ -1610,104 +1638,234 @@ __ieee80211_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the dominant state of the device (init, running, or scanning (and/or associating)) */
|
||||
static int get_dominant_state(struct ieee80211com *ic) {
|
||||
int nscanning = 0;
|
||||
int nrunning = 0;
|
||||
struct ieee80211vap *tmpvap;
|
||||
|
||||
TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
|
||||
if (tmpvap->iv_opmode == IEEE80211_M_MONITOR)
|
||||
/* skip monitor vaps as their
|
||||
* S_RUN shouldn't have any
|
||||
* influence on modifying state
|
||||
* transition */
|
||||
continue;
|
||||
if (tmpvap->iv_state == IEEE80211_S_RUN)
|
||||
nrunning++;
|
||||
else if (tmpvap->iv_state == IEEE80211_S_SCAN ||
|
||||
tmpvap->iv_state == IEEE80211_S_AUTH ||
|
||||
tmpvap->iv_state == IEEE80211_S_ASSOC)
|
||||
{
|
||||
KASSERT((nscanning <= 1), ("Two VAPs cannot scan at the same time\n"));
|
||||
nscanning++;
|
||||
}
|
||||
}
|
||||
KASSERT(!(nscanning && nrunning), ("SCAN and RUN can't happen at the same time\n"));
|
||||
KASSERT((nscanning <= 1), ("Two VAPs must not SCAN at the same time\n"));
|
||||
|
||||
if (nrunning > 0)
|
||||
return IEEE80211_S_RUN;
|
||||
else if (nscanning > 0)
|
||||
return IEEE80211_S_SCAN;
|
||||
else
|
||||
return IEEE80211_S_INIT;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_vap_states(struct ieee80211com *ic, struct ieee80211vap* highlighed)
|
||||
{
|
||||
/* RE-count the number of VAPs in RUN, SCAN states */
|
||||
int nrunning = 0;
|
||||
int nscanning = 0;
|
||||
struct ieee80211vap *tmpvap;
|
||||
TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
|
||||
IEEE80211_DPRINTF(tmpvap, IEEE80211_MSG_STATE,
|
||||
"%s: VAP %s%p[%24s]%s = %s%s%s.\n",
|
||||
__func__,
|
||||
(highlighed == tmpvap ? "*" : " "),
|
||||
tmpvap, tmpvap->iv_nickname, (highlighed == tmpvap ? "*" : " "),
|
||||
ieee80211_state_name[tmpvap->iv_state],
|
||||
tmpvap->iv_state == IEEE80211_S_RUN ? "[RUNNING]" : "",
|
||||
(tmpvap->iv_state == IEEE80211_S_SCAN ||
|
||||
tmpvap->iv_state == IEEE80211_S_AUTH ||
|
||||
tmpvap->iv_state == IEEE80211_S_ASSOC) ? "[SCANNING]" : ""
|
||||
);
|
||||
if (tmpvap->iv_opmode == IEEE80211_M_MONITOR)
|
||||
{
|
||||
/* skip monitor vaps as their
|
||||
* S_RUN shouldn't have any
|
||||
* influence on modifying state
|
||||
* transition */
|
||||
continue;
|
||||
}
|
||||
if (tmpvap->iv_state == IEEE80211_S_RUN)
|
||||
{
|
||||
KASSERT((nscanning == 0), ("SCAN and RUN can't happen at the same time\n"));
|
||||
nrunning++;
|
||||
}
|
||||
if (tmpvap->iv_state == IEEE80211_S_SCAN ||
|
||||
tmpvap->iv_state == IEEE80211_S_AUTH || /* STA in WDS/Repeater */
|
||||
tmpvap->iv_state == IEEE80211_S_ASSOC)
|
||||
{
|
||||
KASSERT((nscanning == 0), ("Two VAPs cannot scan at the same time\n"));
|
||||
KASSERT((nrunning == 0), ("SCAN and RUN can't happen at the same time\n"));
|
||||
nscanning++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ieee80211_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
|
||||
{
|
||||
struct ieee80211com *ic = vap->iv_ic;
|
||||
enum ieee80211_state ostate;
|
||||
enum ieee80211_state dstate;
|
||||
int blocked = 0;
|
||||
struct ieee80211vap *tmpvap;
|
||||
|
||||
ostate = vap->iv_state;
|
||||
dstate = get_dominant_state(ic);
|
||||
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
|
||||
"%s: %p[%s] %s -> %s (dominant %s)\n",
|
||||
__func__, vap, vap->iv_nickname,
|
||||
ieee80211_state_name[ostate],
|
||||
ieee80211_state_name[nstate],
|
||||
ieee80211_state_name[dstate]);
|
||||
|
||||
switch (nstate) {
|
||||
case IEEE80211_S_AUTH:
|
||||
case IEEE80211_S_ASSOC:
|
||||
case IEEE80211_S_SCAN:
|
||||
if (ostate == IEEE80211_S_INIT) {
|
||||
int nrunning, nscanning;
|
||||
|
||||
nrunning = nscanning = 0;
|
||||
TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
|
||||
if (vap != tmpvap) {
|
||||
if (tmpvap->iv_opmode == IEEE80211_M_MONITOR)
|
||||
/* skip monitor vaps as their
|
||||
* S_RUN shouldn't have any
|
||||
* influence on modifying state
|
||||
* transition */
|
||||
continue;
|
||||
if (tmpvap->iv_state == IEEE80211_S_RUN)
|
||||
nrunning++;
|
||||
else if (tmpvap->iv_state == IEEE80211_S_SCAN ||
|
||||
tmpvap->iv_state == IEEE80211_S_AUTH || /* STA in WDS/Repeater */
|
||||
tmpvap->iv_state == IEEE80211_S_ASSOC)
|
||||
nscanning++;
|
||||
}
|
||||
switch (dstate) {
|
||||
case IEEE80211_S_RUN:
|
||||
if(vap->iv_opmode == IEEE80211_M_MONITOR ||
|
||||
vap->iv_opmode == IEEE80211_M_WDS ||
|
||||
vap->iv_opmode == IEEE80211_M_HOSTAP)
|
||||
{
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
|
||||
"%s: Jumping directly to RUN on VAP %p [%s].\n",
|
||||
__func__, vap, vap->iv_nickname);
|
||||
/* One or more VAPs are running, so non-station VAPs
|
||||
* can skip SCAN/AUTH/ASSOC states and just run. */
|
||||
__ieee80211_newstate(vap, IEEE80211_S_RUN, arg);
|
||||
}
|
||||
|
||||
KASSERT(!(nscanning && nrunning), ("SCAN and RUN can't happen at the same time\n"));
|
||||
|
||||
if (!nscanning && !nrunning) {
|
||||
/* when no one is running or scanning, start a new scan */
|
||||
else {
|
||||
/* We'll use this flag briefly to mark transition in progress */
|
||||
ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_PENDING;
|
||||
/* IEEE80211_M_IBSS or IEEE80211_M_STA VAP
|
||||
* is forced to scan, we need to change
|
||||
* all other VAPs state to S_INIT and pend for
|
||||
* the scan completion */
|
||||
TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
|
||||
if (vap != tmpvap && tmpvap->iv_opmode != IEEE80211_M_MONITOR) {
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
|
||||
"%s: Setting SCAN_PENDING flag on VAP %p [%s].\n",
|
||||
__func__, tmpvap, tmpvap->iv_nickname);
|
||||
tmpvap->iv_flags_ext |= IEEE80211_FEXT_SCAN_PENDING;
|
||||
if(tmpvap->iv_state != IEEE80211_S_INIT) {
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
|
||||
"%s: Forcing INIT state on VAP %p [%s].\n",
|
||||
__func__, tmpvap, tmpvap->iv_nickname);
|
||||
tmpvap->iv_newstate(tmpvap, IEEE80211_S_INIT, 0);
|
||||
}
|
||||
else {
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
|
||||
"%s: NOT forcing INIT state on VAP %p [%s].\n",
|
||||
__func__, tmpvap, tmpvap->iv_nickname);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* We used this flag briefly to mark transition in progress */
|
||||
ic->ic_flags_ext &= ~IEEE80211_FEXT_SCAN_PENDING;
|
||||
/* Transition S_INIT -> S_SCAN */
|
||||
__ieee80211_newstate(vap, nstate, arg);
|
||||
} else if (!nscanning && nrunning) {
|
||||
/* when no one is scanning but someone is running, bypass
|
||||
* scan and go to run state immediately */
|
||||
if (vap->iv_opmode == IEEE80211_M_MONITOR ||
|
||||
vap->iv_opmode == IEEE80211_M_WDS ||
|
||||
vap->iv_opmode == IEEE80211_M_HOSTAP) {
|
||||
__ieee80211_newstate(vap, IEEE80211_S_RUN, arg);
|
||||
} else {
|
||||
/* MW: avoid invalid S_INIT -> S_RUN transition */
|
||||
__ieee80211_newstate(vap, nstate, arg);
|
||||
}
|
||||
} else if (nscanning && !nrunning) {
|
||||
/* when someone is scanning and no one is running, set
|
||||
* the scan pending flag. Don't go through state machine */
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
|
||||
"%s: %s -> %s with SCAN_PENDING\n",
|
||||
__func__,
|
||||
ieee80211_state_name[ostate],
|
||||
ieee80211_state_name[nstate]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_S_SCAN:
|
||||
case IEEE80211_S_AUTH:
|
||||
case IEEE80211_S_ASSOC:
|
||||
/* this VAP was scanning */
|
||||
if (ostate == IEEE80211_S_SCAN || /* STA in WDS/Repeater needs to bring up other VAPs */
|
||||
ostate == IEEE80211_S_AUTH ||
|
||||
ostate == IEEE80211_S_ASSOC)
|
||||
{
|
||||
/* Transition (S_SCAN|S_AUTH|S_ASSOC) -> S_SCAN */
|
||||
__ieee80211_newstate(vap, nstate, arg);
|
||||
}
|
||||
else {
|
||||
/* Someone else is scanning, so block the transition */
|
||||
vap->iv_flags_ext |= IEEE80211_FEXT_SCAN_PENDING;
|
||||
__ieee80211_newstate(vap, IEEE80211_S_INIT, arg);
|
||||
blocked = 1;
|
||||
}
|
||||
} else {
|
||||
/* the VAP is forced to scan, we need to change all other VAPs state
|
||||
* to INIT and pend for the scan completion */
|
||||
TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
|
||||
if (vap != tmpvap && tmpvap->iv_state != IEEE80211_S_INIT) {
|
||||
tmpvap->iv_newstate(tmpvap, IEEE80211_S_INIT, 0);
|
||||
tmpvap->iv_flags_ext |= IEEE80211_FEXT_SCAN_PENDING;
|
||||
}
|
||||
}
|
||||
|
||||
/* start the new scan */
|
||||
break;
|
||||
case IEEE80211_S_INIT:
|
||||
/* Transition S_INIT -> S_SCAN */
|
||||
__ieee80211_newstate(vap, nstate, arg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IEEE80211_S_RUN:
|
||||
if ((ostate == IEEE80211_S_SCAN) || /* AP coming out of scan */
|
||||
(vap->iv_opmode == IEEE80211_M_STA)) { /* STA in WDS/Repeater needs to bring up other VAPs */
|
||||
/* this VAP was scanning */
|
||||
if (ostate == IEEE80211_S_SCAN || /* STA in WDS/Repeater needs to bring up other VAPs */
|
||||
ostate == IEEE80211_S_AUTH ||
|
||||
ostate == IEEE80211_S_ASSOC)
|
||||
{
|
||||
/* Transition (S_SCAN|S_AUTH|S_ASSOC) -> S_RUN */
|
||||
__ieee80211_newstate(vap, nstate, arg);
|
||||
|
||||
/* bring up all other vaps pending on the scan */
|
||||
TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
|
||||
if (vap != tmpvap) {
|
||||
if (tmpvap->iv_flags_ext & IEEE80211_FEXT_SCAN_PENDING) {
|
||||
tmpvap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_PENDING;
|
||||
tmpvap->iv_newstate(tmpvap, IEEE80211_S_RUN, 0);
|
||||
/* Then bring up all other vaps pending on the scan*/
|
||||
dstate = get_dominant_state(ic);
|
||||
if (dstate == IEEE80211_S_RUN) {
|
||||
TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
|
||||
if (vap != tmpvap &&
|
||||
tmpvap->iv_opmode != IEEE80211_M_MONITOR &&
|
||||
(tmpvap->iv_flags_ext & IEEE80211_FEXT_SCAN_PENDING)) {
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
|
||||
"%s: Clearing SCAN_PENDING flag from VAP %p [%s] and transitioning to RUN state.\n",
|
||||
__func__, tmpvap, tmpvap->iv_nickname);
|
||||
tmpvap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_PENDING;
|
||||
if(tmpvap->iv_state != IEEE80211_S_RUN) {
|
||||
tmpvap->iv_newstate(tmpvap, IEEE80211_S_RUN, 0);
|
||||
}
|
||||
else if(tmpvap->iv_opmode == IEEE80211_M_HOSTAP) {
|
||||
/* Force other AP through -> INIT -> RUN to make
|
||||
* sure beacons are reallocated */
|
||||
tmpvap->iv_newstate(tmpvap, IEEE80211_S_INIT, 0);
|
||||
tmpvap->iv_newstate(tmpvap, IEEE80211_S_RUN, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
} else if (dstate == IEEE80211_S_SCAN) {
|
||||
/* Force to scan pending... someone is scanning */
|
||||
vap->iv_flags_ext |= IEEE80211_FEXT_SCAN_PENDING;
|
||||
__ieee80211_newstate(vap, IEEE80211_S_INIT, arg);
|
||||
blocked = 1;
|
||||
}
|
||||
else {
|
||||
__ieee80211_newstate(vap, nstate, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case IEEE80211_S_INIT:
|
||||
if (ostate == IEEE80211_S_INIT)
|
||||
vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_PENDING;
|
||||
/* fall through */
|
||||
|
||||
default:
|
||||
__ieee80211_newstate(vap, nstate, arg);
|
||||
}
|
||||
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
|
||||
"%s: %s requested transition %s -> %s on VAP %p [%s]. "
|
||||
"Dominant state is %s.\n",
|
||||
__func__,
|
||||
(blocked ? "BLOCKED" : "ALLOWED"),
|
||||
ieee80211_state_name[ostate],
|
||||
ieee80211_state_name[nstate],
|
||||
vap,
|
||||
vap->iv_nickname,
|
||||
ieee80211_state_name[dstate]);
|
||||
|
||||
dump_vap_states(ic, vap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user