📄 ieee80211_proto.c
字号:
/* * Select mode; we can be called early in which case we * always use auto mode. We know we'll be called when * entering the RUN state with bsschan setup properly * so state will eventually get set correctly */ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC) mode = ieee80211_chan2mode(ic->ic_bsschan); else mode = IEEE80211_MODE_AUTO; if ((vap->iv_opmode == IEEE80211_M_HOSTAP && (wme->wme_flags & WME_F_AGGRMODE) != 0) || (vap->iv_opmode != IEEE80211_M_HOSTAP && (vap->iv_bss->ni_flags & IEEE80211_NODE_QOS) == 0) || (vap->iv_flags & IEEE80211_F_WME) == 0) { struct ieee80211vap *tmpvap; u_int8_t burstEnabled = 0; /* check if bursting enabled on at least one vap */ TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) { if (tmpvap->iv_ath_cap & IEEE80211_ATHC_BURST) { burstEnabled = 1; break; } } wme->wme_chanParams.cap_wmeParams[WME_AC_BE].wmep_aifsn = phyParam[mode].aifsn; wme->wme_chanParams.cap_wmeParams[WME_AC_BE].wmep_logcwmin = phyParam[mode].logcwmin; wme->wme_chanParams.cap_wmeParams[WME_AC_BE].wmep_logcwmax = phyParam[mode].logcwmax; wme->wme_chanParams.cap_wmeParams[WME_AC_BE].wmep_txopLimit = burstEnabled ? phyParam[mode].txopLimit : 0; wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE].wmep_aifsn = phyParam[mode].aifsn; wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE].wmep_logcwmin = phyParam[mode].logcwmin; wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE].wmep_logcwmax = phyParam[mode].logcwmax; wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE].wmep_txopLimit = burstEnabled ? phyParam[mode].txopLimit : 0; } if (ic->ic_opmode == IEEE80211_M_HOSTAP && ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) { static const u_int8_t logCwMin[IEEE80211_MODE_MAX] = { /* IEEE80211_MODE_AUTO */ 3, /* IEEE80211_MODE_11A */ 3, /* IEEE80211_MODE_11B */ 4, /* IEEE80211_MODE_11G */ 3, /* IEEE80211_MODE_FH */ 4, /* IEEE80211_MODE_TURBO_A */ 3, /* IEEE80211_MODE_TURBO_G */ 3 }; wme->wme_chanParams.cap_wmeParams[WME_AC_BE].wmep_logcwmin = wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE].wmep_logcwmin = logCwMin[mode]; } if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* XXX ibss? */ /* * Arrange for a beacon update and bump the parameter * set number so associated stations load the new values. */ wme->wme_bssChanParams.cap_info_count = (wme->wme_bssChanParams.cap_info_count + 1) & WME_QOSINFO_COUNT; vap->iv_flags |= IEEE80211_F_WMEUPDATE; } wme->wme_update(ic); IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, "%s: WME params updated, cap_info 0x%x\n", __func__, vap->iv_opmode == IEEE80211_M_STA ? wme->wme_wmeChanParams.cap_info_count : wme->wme_bssChanParams.cap_info_count);}voidieee80211_wme_updateparams(struct ieee80211vap *vap){ struct ieee80211com *ic = vap->iv_ic; if (ic->ic_caps & IEEE80211_C_WME) { IEEE80211_LOCK(ic); ieee80211_wme_updateparams_locked(vap); IEEE80211_UNLOCK(ic); }}/* * Start a vap. If this is the first vap running on the * underlying device then we first bring it up. */intieee80211_init(struct net_device *dev, int forcescan){#define IS_RUNNING(_dev) \ ((_dev->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP)) struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; struct net_device *parent = ic->ic_dev; IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, "start running (state=%d)\n", vap->iv_state); if ((dev->flags & IFF_RUNNING) == 0) { if (ic->ic_nopened++ == 0 && (parent->flags & IFF_RUNNING) == 0) dev_open(parent); /* * Mark us running. Note that we do this after * opening the parent device to avoid recursion. */ dev->flags |= IFF_RUNNING; /* mark us running */ } /* * If the parent is up and running, then kick the * 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 (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); } else { /* * When the old state is running the vap must * be brought to init. */ if (vap->iv_state == IEEE80211_S_RUN) 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_new_state(vap, IEEE80211_S_RUN, -1); } else 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 vap's 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; if ((dev->flags & IFF_UP) && !(dev->flags & IFF_RUNNING)) /* NB: avoid recursion */ ieee80211_open(dev); }}EXPORT_SYMBOL(ieee80211_start_running);/* * Stop a vap. We force it down using the state machine * then mark it's 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 = dev->priv; 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 vap's 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){ /* XXX use first vap for debug flags */ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 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_prevchan = ic->ic_curchan; 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; /* grab the lock so that only one vap can go through transition at any time */ 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; 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 && 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -