📄 ieee80211_proto.c.svn-base
字号:
KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("switch to %s state when operating in mode %u", ieee80211_state_name[nstate], vap->iv_opmode)); switch (ostate) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, "%s: invalid transition\n", __func__); break; case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); break; case IEEE80211_S_RUN: ieee80211_sta_leave(ni); if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { /* NB: caller specifies ASSOC/REASSOC by arg */ IEEE80211_SEND_MGMT(ni, arg ? IEEE80211_FC0_SUBTYPE_REASSOC_REQ : IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); } break; } break; case IEEE80211_S_RUN: if (vap->iv_flags & IEEE80211_F_WPA) { /* XXX validate prerequisites */ } switch (ostate) { case IEEE80211_S_INIT: if (vap->iv_opmode == IEEE80211_M_MONITOR || vap->iv_opmode == IEEE80211_M_WDS || vap->iv_opmode == IEEE80211_M_HOSTAP) { /* * Already have a channel; bypass the * scan and startup immediately. */ ieee80211_create_ibss(vap, ic->ic_curchan); /* In WDS mode, allocate and initialize peer node. */ if (vap->iv_opmode == IEEE80211_M_WDS) { /* XXX: This is horribly non-atomic. */ struct ieee80211_node *wds_ni = ieee80211_find_node(&ic->ic_sta, vap->wds_mac); if (wds_ni == NULL) { wds_ni = ieee80211_alloc_node_table( vap, vap->wds_mac); if (wds_ni != NULL) { ieee80211_add_wds_addr( &ic->ic_sta, wds_ni, vap->wds_mac, 1); ieee80211_ref_node(wds_ni); /* pin in memory */ } else IEEE80211_DPRINTF( vap, IEEE80211_MSG_NODE, "%s: Unable to " "allocate node for " "WDS: " MAC_FMT "\n", __func__, MAC_ADDR( vap->wds_mac) ); } if (wds_ni != NULL) { ieee80211_node_authorize(wds_ni); wds_ni->ni_chan = vap->iv_bss->ni_chan; wds_ni->ni_capinfo = ni->ni_capinfo; wds_ni->ni_associd = 1; wds_ni->ni_ath_flags = vap->iv_ath_cap; } } break; } /* fall thru... */ case IEEE80211_S_AUTH: IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, "%s: invalid transition\n", __func__); break; case IEEE80211_S_RUN: break; case IEEE80211_S_SCAN: /* adhoc/hostap mode */ case IEEE80211_S_ASSOC: /* infra mode */ KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, ("%s: bogus xmit rate %u setup", __func__, ni->ni_txrate));#ifdef IEEE80211_DEBUG if (ieee80211_msg_debug(vap)) { ieee80211_note(vap, "%s with " MAC_FMT " ssid ", (vap->iv_opmode == IEEE80211_M_STA ? "associated" : "synchronized "), MAC_ADDR(vap->iv_bssid)); ieee80211_print_essid(vap->iv_bss->ni_essid, ni->ni_esslen); printk(" channel %d start %uMb\n", ieee80211_chan2ieee(ic, ic->ic_curchan), IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); }#endif if (vap->iv_opmode == IEEE80211_M_STA) { ieee80211_scan_assoc_success(ic, ni->ni_macaddr); ieee80211_notify_node_join(ni, (arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | \ (arg == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)); } break; } /* WDS/Repeater: Start software beacon timer for STA */ if (ostate != IEEE80211_S_RUN && (vap->iv_opmode == IEEE80211_M_STA && vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) { vap->iv_swbmiss.function = ieee80211_sta_swbmiss; vap->iv_swbmiss.data = (unsigned long) vap; vap->iv_swbmiss_period = IEEE80211_TU_TO_JIFFIES( vap->iv_ic->ic_bmissthreshold * ni->ni_intval); mod_timer(&vap->iv_swbmiss, jiffies + vap->iv_swbmiss_period); } /* * Start/stop the authenticator when operating as an * AP. We delay until here to allow configuration to * happen out of order. */ /* XXX WDS? */ if (vap->iv_opmode == IEEE80211_M_HOSTAP && /* XXX IBSS/AHDEMO */ vap->iv_auth->ia_attach != NULL) { /* XXX check failure */ vap->iv_auth->ia_attach(vap); } else if (vap->iv_auth->ia_detach != NULL) vap->iv_auth->ia_detach(vap); /* * When 802.1x is not in use mark the port authorized * at this point so traffic can flow. */ if (ni->ni_authmode != IEEE80211_AUTH_8021X) ieee80211_node_authorize(ni);#ifdef ATH_SUPERG_XR /* * fire a timer to bring up XR vap if configured. */ if (ostate != IEEE80211_S_RUN && vap->iv_xrvap && !(vap->iv_flags & IEEE80211_F_XR)) { vap->iv_xrvapstart.function = ieee80211_start_xrvap; vap->iv_xrvapstart.data = (unsigned long) vap->iv_xrvap; mod_timer(&vap->iv_xrvapstart, jiffies + HZ); /* start xr vap on next second */ /* * do not let the normal vap automatically bring up XR vap. * let the timer handler start the XR vap. if you let the * normal vap automatically start the XR vap normal vap will not * have the bssid initialized and the XR vap will use the * invalid bssid in XRIE of its beacon. */ if (vap->iv_xrvap->iv_flags_ext & IEEE80211_FEXT_SCAN_PENDING) vap->iv_xrvap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_PENDING; } /* * when an XR vap transitions to RUN state, * normal vap needs to update the XR IE * with the xr vaps MAC address. */ if (vap->iv_flags & IEEE80211_F_XR) vap->iv_xrvap->iv_flags |= IEEE80211_F_XRUPDATE;#endif break; } 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")); nscanning++; } } KASSERT(!(nscanning && nrunning), ("SCAN and RUN can't happen at the " "same time")); KASSERT((nscanning <= 1), ("Two VAPs must not SCAN at the " "same time")); 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]" : "" ); /* Ignore monitors they are passive */ if (tmpvap->iv_opmode == IEEE80211_M_MONITOR) { continue; } if (tmpvap->iv_state == IEEE80211_S_RUN) { KASSERT((nscanning == 0), ("SCAN and RUN can't happen " "at the same time")); nrunning++; } if (tmpvap->iv_state == IEEE80211_S_SCAN || /* STA in WDS/Repeater */ tmpvap->iv_state == IEEE80211_S_AUTH || tmpvap->iv_state == IEEE80211_S_ASSOC) { KASSERT((nscanning == 0), ("Two VAPs cannot scan at " "the same time")); KASSERT((nrunning == 0), ("SCAN and RUN can't happen " "at the same time")); nscanning++; } }}static intieee80211_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: 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); } 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); break; } break; case IEEE80211_S_SCAN: case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: /* this VAP was scanning */ /* STA in WDS/Repeater needs to bring up other VAPs */ if (ostate == IEEE80211_S_SCAN || 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; } break; case IEEE80211_S_INIT: /* Transition S_INIT -> S_SCAN */ __ieee80211_newstate(vap, nstate, arg); break; } break; case IEEE80211_S_RUN: /* this VAP was scanning */ /* STA in WDS/Repeater needs to bring up other VAPs */ if (ostate == IEEE80211_S_SCAN || ostate == IEEE80211_S_AUTH || ostate == IEEE80211_S_ASSOC) { /* Transition (S_SCAN|S_AUTH|S_ASSOC) -> S_RUN */ __ieee80211_newstate(vap, nstate, arg); /* 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 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; 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;}#ifdef ATH_SUPERG_XR/* * start the XR vap . * called from a timer when normal vap enters RUN state . */static voidieee80211_start_xrvap(unsigned long data){ struct ieee80211vap *vap = (struct ieee80211vap *)data; /* make sure that the normal vap is still in RUN state */ if (vap->iv_xrvap->iv_state == IEEE80211_S_RUN) ieee80211_init(vap->iv_dev, 0);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -