📄 ieee80211_proto.c.svn-base
字号:
* 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) { 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 * vap to be brought up, start a scan which may be * preempted if the station is locked to a particular * channel. */ 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 { 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;#undef IS_RUNNING}intieee80211_open(struct net_device *dev){ return ieee80211_init(dev, 0);}/* * Start all runnable VAPs on a device. */voidieee80211_start_running(struct ieee80211com *ic){ struct ieee80211vap *vap; struct net_device *dev; /* XXX locking */ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { dev = vap->iv_dev; /* NB: avoid recursion */ if ((dev->flags & IFF_UP) && !(dev->flags & IFF_RUNNING)) ieee80211_open(dev); }}EXPORT_SYMBOL(ieee80211_start_running);/* * Stop a vap. We force it down using the state machine * then mark its device not running. If this is the last * vap running on the underlying device then we close it * too to ensure it will be properly initialized when the * next vap is brought up. */intieee80211_stop(struct net_device *dev){ struct ieee80211vap *vap = netdev_priv(dev); struct ieee80211com *ic = vap->iv_ic; struct net_device *parent = ic->ic_dev; IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, "%s\n", "stop running"); ieee80211_new_state(vap, IEEE80211_S_INIT, -1); if (dev->flags & IFF_RUNNING) { dev->flags &= ~IFF_RUNNING; /* mark us stopped */ del_timer(&vap->iv_mgtsend); if (--ic->ic_nopened == 0 && (parent->flags & IFF_RUNNING)) dev_close(parent); }#ifdef ATH_SUPERG_XR /* * also stop the XR vap. */ if (vap->iv_xrvap && !(vap->iv_flags & IEEE80211_F_XR)) { ieee80211_stop(vap->iv_xrvap->iv_dev); del_timer(&vap->iv_xrvapstart); vap->iv_xrvap->iv_dev->flags = dev->flags; }#endif return 0;}EXPORT_SYMBOL(ieee80211_stop);/* * Stop all VAPs running on a device. */voidieee80211_stop_running(struct ieee80211com *ic){ struct ieee80211vap *vap; struct net_device *dev; /* XXX locking */ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { dev = vap->iv_dev; if (dev->flags & IFF_RUNNING) /* NB: avoid recursion */ ieee80211_stop(dev); }}EXPORT_SYMBOL(ieee80211_stop_running);#ifdef ATH_SUPERG_DYNTURBO/* * Switch between turbo and non-turbo operating modes. * Use the specified channel flags to locate the new * channel, update 802.11 state, and then call back into * the driver to effect the change. */voidieee80211_dturbo_switch(struct ieee80211com *ic, int newflags){#ifdef IEEE80211_DEBUG /* XXX use first vap for debug flags */ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);#endif struct ieee80211_channel *chan; chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags); if (chan == NULL) { /* XXX should not happen */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPG, "%s: no channel with freq %u flags 0x%x\n", __func__, ic->ic_bsschan->ic_freq, newflags); return; } IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPG, "%s: %s -> %s (freq %u flags 0x%x)\n", __func__, ieee80211_phymode_name[ieee80211_chan2mode(ic->ic_bsschan)], ieee80211_phymode_name[ieee80211_chan2mode(chan)], chan->ic_freq, chan->ic_flags); ic->ic_bsschan = chan; ic->ic_curchan = chan; ic->ic_set_channel(ic); /* NB: do not need to reset ERP state because in sta mode */}EXPORT_SYMBOL(ieee80211_dturbo_switch);#endif /* ATH_SUPERG_DYNTURBO */voidieee80211_beacon_miss(struct ieee80211com *ic){ struct ieee80211vap *vap; if (ic->ic_flags & IEEE80211_F_SCAN) { /* XXX check ic_curchan != ic_bsschan? */ return; } /* XXX locking */ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, "%s\n", "beacon miss"); /* * Our handling is only meaningful for stations that are * associated; any other conditions else will be handled * through different means (e.g. the tx timeout on mgt frames). */ if (vap->iv_opmode != IEEE80211_M_STA || vap->iv_state != IEEE80211_S_RUN) continue; if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {#ifdef ATH_SUPERG_DYNTURBO /* * If we receive a beacon miss interrupt when using * dynamic turbo, attempt to switch modes before * reassociating. */ if (IEEE80211_ATH_CAP(vap, vap->iv_bss, IEEE80211_ATHC_TURBOP)) ieee80211_dturbo_switch(ic, ic->ic_bsschan->ic_flags ^ IEEE80211_CHAN_TURBO);#endif /* ATH_SUPERG_DYNTURBO */ /* * Try to reassociate before scanning for a new ap. */ ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1); } else { /* * Somebody else is controlling state changes (e.g. * a user-mode app) don't do anything that would * confuse them; just drop into scan mode so they'll * notified of the state change and given control. */ ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); } }}EXPORT_SYMBOL(ieee80211_beacon_miss);/* * STA software beacon timer callback. This is called * only when we have a series beacon misses. */static voidieee80211_sta_swbmiss(unsigned long arg){ struct ieee80211vap *vap = (struct ieee80211vap *)arg; ieee80211_beacon_miss(vap->iv_ic);}/* * Per-ieee80211vap watchdog timer callback. This * is used only to timeout the xmit of management frames. */static voidieee80211_tx_timeout(unsigned long arg){ struct ieee80211vap *vap = (struct ieee80211vap *)arg; IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: state %s%s\n", __func__, ieee80211_state_name[vap->iv_state], vap->iv_ic->ic_flags & IEEE80211_F_SCAN ? ", scan active" : ""); if (vap->iv_state != IEEE80211_S_INIT && (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { /* * NB: it's safe to specify a timeout as the reason here; * it'll only be used in the right state. */ ieee80211_new_state(vap, IEEE80211_S_SCAN, IEEE80211_SCAN_FAIL_TIMEOUT); }}static voidsta_disassoc(void *arg, struct ieee80211_node *ni){ struct ieee80211vap *vap = arg; if (ni->ni_vap == vap && ni->ni_associd != 0) { IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_ASSOC_LEAVE); ieee80211_node_leave(ni); }}static voidsta_deauth(void *arg, struct ieee80211_node *ni){ struct ieee80211vap *vap = arg; if (ni->ni_vap == vap) IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_ASSOC_LEAVE);}/* * Context: softIRQ (tasklet) and process */intieee80211_new_state(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg){ struct ieee80211com *ic = vap->iv_ic; int rc; IEEE80211_VAPS_LOCK_BH(ic); rc = vap->iv_newstate(vap, nstate, arg); IEEE80211_VAPS_UNLOCK_BH(ic); return rc;}static int__ieee80211_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg){ struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; enum ieee80211_state ostate; ostate = vap->iv_state; vap->iv_state = nstate; /* state transition */ del_timer(&vap->iv_mgtsend); if ((vap->iv_opmode != IEEE80211_M_HOSTAP) && (ostate != IEEE80211_S_SCAN)) ieee80211_cancel_scan(vap); /* background scan */ ni = vap->iv_bss; /* NB: no reference held */ switch (nstate) { case IEEE80211_S_INIT: switch (ostate) { case IEEE80211_S_INIT: break; case IEEE80211_S_RUN: switch (vap->iv_opmode) { case IEEE80211_M_STA: IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_ASSOC_LEAVE); ieee80211_sta_leave(ni); break; case IEEE80211_M_HOSTAP: ieee80211_iterate_nodes(&ic->ic_sta, sta_disassoc, vap); break; default: break; } goto reset; case IEEE80211_S_ASSOC: switch (vap->iv_opmode) { case IEEE80211_M_STA: IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); break; case IEEE80211_M_HOSTAP: ieee80211_iterate_nodes(&ic->ic_sta, sta_deauth, vap); break; default: break; } goto reset; case IEEE80211_S_SCAN: ieee80211_cancel_scan(vap); goto reset; case IEEE80211_S_AUTH: reset: ieee80211_reset_bss(vap); break; } if (vap->iv_auth != NULL && vap->iv_auth->ia_detach != NULL) vap->iv_auth->ia_detach(vap); break; case IEEE80211_S_SCAN: switch (ostate) { case IEEE80211_S_INIT: createibss: if ((vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS || vap->iv_opmode == IEEE80211_M_AHDEMO) && vap->iv_des_chan != IEEE80211_CHAN_ANYC) { /* * AP operation and we already have a channel; * bypass the scan and startup immediately. */ ieee80211_create_ibss(vap, vap->iv_des_chan); } else { ieee80211_check_scan(vap, IEEE80211_SCAN_ACTIVE | IEEE80211_SCAN_FLUSH, IEEE80211_SCAN_FOREVER, vap->iv_des_nssid, vap->iv_des_ssid, NULL); } break; case IEEE80211_S_SCAN: case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: /* * These can happen either because of a timeout * on an assoc/auth response or because of a * change in state that requires a reset. For * the former we're called with a non-zero arg * that is the cause for the failure; pass this * to the scan code so it can update state. * Otherwise trigger a new scan unless we're in * manual roaming mode in which case an application * must issue an explicit scan request. */ if (arg != 0) ieee80211_scan_assoc_fail(ic, vap->iv_bss->ni_macaddr, arg); if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) ieee80211_check_scan(vap, IEEE80211_SCAN_ACTIVE, IEEE80211_SCAN_FOREVER, vap->iv_des_nssid, vap->iv_des_ssid, NULL); break; case IEEE80211_S_RUN: /* beacon miss */ if (vap->iv_opmode == IEEE80211_M_STA) { ieee80211_sta_leave(ni); vap->iv_flags &= ~IEEE80211_F_SIBSS; /* XXX */ if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) ieee80211_check_scan(vap, IEEE80211_SCAN_ACTIVE, IEEE80211_SCAN_FOREVER, vap->iv_des_nssid, vap->iv_des_ssid, NULL); } else { ieee80211_iterate_nodes(&ic->ic_sta, sta_disassoc, vap); goto createibss; } break; } break; case IEEE80211_S_AUTH: /* auth frames are possible between IBSS nodes, * see 802.11-1999, chapter 5.7.6 */ KASSERT(vap->iv_opmode == IEEE80211_M_STA || vap->iv_opmode == IEEE80211_M_IBSS, ("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_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 1); break; case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: switch (arg) { case IEEE80211_FC0_SUBTYPE_AUTH: /* ??? */ IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 2); break; case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 1); break; } break; case IEEE80211_S_RUN: switch (arg) { case IEEE80211_FC0_SUBTYPE_AUTH: IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 2); vap->iv_state = ostate; /* stay RUN */ break; case IEEE80211_FC0_SUBTYPE_DEAUTH: ieee80211_sta_leave(ni); if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { /* try to reauth */ IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 1); } break; } break; } break; case IEEE80211_S_ASSOC:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -