📄 if_ath.c.svn-base
字号:
break; case IEEE80211_M_IBSS: if ((sc->sc_nvaps != 0) && (ic->ic_opmode == IEEE80211_M_STA)) return NULL; ic_opmode = opmode; break; case IEEE80211_M_AHDEMO: case IEEE80211_M_MONITOR: if (sc->sc_nvaps != 0 && (ic->ic_opmode != opmode)) { /* preserve existing mode */ ic_opmode = ic->ic_opmode; } else ic_opmode = opmode; break; case IEEE80211_M_HOSTAP: case IEEE80211_M_WDS: /* permit multiple APs and/or WDS links */ /* XXX sta+ap for repeater/bridge application */ if ((sc->sc_nvaps != 0) && (ic->ic_opmode == IEEE80211_M_STA)) return NULL; /* XXX not right, beacon buffer is allocated on RUN trans */ if (opmode == IEEE80211_M_HOSTAP && STAILQ_EMPTY(&sc->sc_bbuf)) return NULL; /* * XXX Not sure if this is correct when operating only * with WDS links. */ ic_opmode = IEEE80211_M_HOSTAP; break; default: return NULL; } if (sc->sc_nvaps >= ath_maxvaps) { EPRINTF(sc, "Too many virtual APs (%d already exist).\n", sc->sc_nvaps); return NULL; } dev = alloc_etherdev(sizeof(struct ath_vap) + sc->sc_rc->arc_vap_space); if (dev == NULL) { /* XXX msg */ return NULL; } avp = netdev_priv(dev); ieee80211_vap_setup(ic, dev, name, opmode, flags); /* override with driver methods */ vap = &avp->av_vap; avp->av_newstate = vap->iv_newstate; vap->iv_newstate = ath_newstate; vap->iv_key_alloc = ath_key_alloc; vap->iv_key_delete = ath_key_delete; vap->iv_key_set = ath_key_set; vap->iv_key_update_begin = ath_key_update_begin; vap->iv_key_update_end = ath_key_update_end; if (sc->sc_default_ieee80211_debug) { /* User specified defaults for new VAPs were provided, so * use those (only). */ vap->iv_debug = (sc->sc_default_ieee80211_debug & ~IEEE80211_MSG_IC); } else { /* If no default VAP debug flags are passed, allow a few to * transfer down from the driver to new VAPs so we can have load * time debugging for VAPs too. */ vap->iv_debug = 0 | ((sc->sc_debug & ATH_DEBUG_RATE) ? IEEE80211_MSG_XRATE : 0) | ((sc->sc_debug & ATH_DEBUG_XMIT) ? IEEE80211_MSG_OUTPUT : 0) | ((sc->sc_debug & ATH_DEBUG_RECV) ? IEEE80211_MSG_INPUT : 0) | 0 ; } ic->ic_debug = (sc->sc_default_ieee80211_debug & IEEE80211_MSG_IC);#ifdef ATH_SUPERG_COMP vap->iv_comp_set = ath_comp_set;#endif /* Let rate control register proc entries for the VAP */ if (sc->sc_rc->ops->dynamic_proc_register) sc->sc_rc->ops->dynamic_proc_register(vap); /* XXX: VAPs emulate ethernet - true/false/good/bad? */ dev->type = ARPHRD_ETHER; if (opmode == IEEE80211_M_MONITOR) /* Use RadioTAP interface type for monitor mode. */ dev->type = ARPHRD_IEEE80211_RADIOTAP; if (flags & IEEE80211_CLONE_BSSID) { if (sc->sc_hasbmask) { struct ieee80211vap *v; uint64_t id_mask = 0; unsigned int id; /* Hardware supports the BSSID mask and a unique * BSSID was requested. Assign a new MAC address * and expand our BSSID mask to cover the active * virtual APs with distinct addresses. */ /* Do a full search to mark all the allocated VAPs. */ TAILQ_FOREACH(v, &ic->ic_vaps, iv_next) id_mask |= (1 << ATH_GET_VAP_ID(v->iv_myaddr)); for (id = 1; id < ath_maxvaps; id++) { /* Get the first available slot. */ if ((id_mask & (1 << id)) == 0) { ATH_SET_VAP_BSSID(vap->iv_myaddr, id); ATH_SET_VAP_BSSID(vap->iv_bssid, id); break; } } } else { EPRINTF(sc, "Unique BSSID requested on HW that does" "does not support the necessary features."); } } avp->av_bslot = -1;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) atomic_set(&avp->av_beacon_alloc, 0);#else clear_bit(0, &avp->av_beacon_alloc);#endif STAILQ_INIT(&avp->av_mcastq.axq_q); ATH_TXQ_LOCK_INIT(&avp->av_mcastq); if (IEEE80211_IS_MODE_BEACON(opmode)) { unsigned int slot; /* Allocate beacon state for hostap/ibss. We know * a buffer is available because of the check above. */ avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf); STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list); /* Assign the VAP to a beacon xmit slot. As * above, this cannot fail to find one. */ avp->av_bslot = 0; for (slot = 0; slot < ath_maxvaps; slot++) if (sc->sc_bslot[slot] == NULL) { /* XXX: Hack, space out slots to better * deal with misses. */ if (slot + 1 < ath_maxvaps && sc->sc_bslot[slot+1] == NULL) { avp->av_bslot = slot + 1; break; } avp->av_bslot = slot; /* NB: keep looking for a double slot */ } KASSERT(sc->sc_bslot[avp->av_bslot] == NULL, ("beacon slot %u not empty?", avp->av_bslot)); sc->sc_bslot[avp->av_bslot] = vap; sc->sc_nbcnvaps++; if ((opmode == IEEE80211_M_HOSTAP) && (sc->sc_hastsfadd)) { /* * Multiple VAPs are to transmit beacons and we * have h/w support for TSF adjusting; enable use * of staggered beacons. */ /* XXX check for beacon interval too small */ if (ath_maxvaps > 4) { DPRINTF(sc, ATH_DEBUG_BEACON, "Staggered beacons are not " "possible with maxvaps set " "to %d.\n", ath_maxvaps); sc->sc_stagbeacons = 0; } else { sc->sc_stagbeacons = 1; } } DPRINTF(sc, ATH_DEBUG_BEACON, "sc->sc_stagbeacons %sabled\n", (sc->sc_stagbeacons ? "en" : "dis")); } if (sc->sc_hastsfadd) ath_hal_settsfadjust(sc->sc_ah, sc->sc_stagbeacons); SET_NETDEV_DEV(dev, ATH_GET_NETDEV_DEV(mdev)); /* complete setup */ (void) ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); ic->ic_opmode = ic_opmode; if (opmode != IEEE80211_M_WDS) sc->sc_nvaps++; if (opmode == IEEE80211_M_STA) sc->sc_nstavaps++; else if (opmode == IEEE80211_M_MONITOR) sc->sc_nmonvaps++; /* * Adhoc demo mode is a pseudo mode; to the HAL it's * just IBSS mode and the driver doesn't use management * frames. Other modes carry over directly to the HAL. */ if (ic->ic_opmode == IEEE80211_M_AHDEMO) sc->sc_opmode = HAL_M_IBSS; else sc->sc_opmode = (HAL_OPMODE) ic->ic_opmode; /* NB: compatible */#ifdef ATH_SUPERG_XR if (vap->iv_flags & IEEE80211_F_XR) { if (ath_descdma_setup(sc, &sc->sc_grppolldma, &sc->sc_grppollbuf, "grppoll", (sc->sc_xrpollcount + 1) * HAL_ANTENNA_MAX_MODE, 1) != 0) EPRINTF(sc, "DMA setup failed\n"); if (!sc->sc_xrtxq) sc->sc_xrtxq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, HAL_XR_DATA); if (sc->sc_hasdiversity) { /* Save current diversity state if user destroys XR VAP */ sc->sc_olddiversity = sc->sc_diversity; ath_hal_setdiversity(sc->sc_ah, 0); sc->sc_diversity = 0; } }#endif if (ic->ic_dev->flags & IFF_RUNNING) { /* restart hardware */ if (ath_startrecv(sc) != 0) /* restart recv */ EPRINTF(sc, "Unable to start receive logic.\n"); if (sc->sc_beacons) ath_beacon_config(sc, NULL); /* restart beacons */ ath_hal_intrset(ah, sc->sc_imask); } return vap;}static voidath_vap_delete(struct ieee80211vap *vap){ struct net_device *dev = vap->iv_ic->ic_dev; struct ath_softc *sc = netdev_priv(dev); struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp = ATH_VAP(vap); int decrease = 1; unsigned int i; KASSERT(vap->iv_state == IEEE80211_S_INIT, ("VAP not stopped")); if (dev->flags & IFF_RUNNING) { /* * Quiesce the hardware while we remove the VAP. In * particular we need to reclaim all references to the * VAP state by any frames pending on the tx queues. * * XXX: Can we do this w/o affecting other VAPs? */ ath_hal_intrset(ah, 0); /* disable interrupts */ ath_draintxq(sc); /* stop xmit side */ ath_stoprecv(sc); /* stop recv side */ } /* * Reclaim any pending mcast bufs on the VAP. */ ath_tx_draintxq(sc, &avp->av_mcastq); ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq); /* * Reclaim beacon state. Note this must be done before * VAP instance is reclaimed as we may have a reference * to it in the buffer for the beacon frame. */ if (avp->av_bcbuf != NULL) { if (avp->av_bslot != -1) { sc->sc_bslot[avp->av_bslot] = NULL; sc->sc_nbcnvaps--; } ath_beacon_return(sc, avp->av_bcbuf); avp->av_bcbuf = NULL; if (sc->sc_nbcnvaps == 0) sc->sc_stagbeacons = 0; } if (vap->iv_opmode == IEEE80211_M_STA) { sc->sc_nstavaps--; sc->sc_nostabeacons = 0; } else if (vap->iv_opmode == IEEE80211_M_MONITOR) sc->sc_nmonvaps--; else if (vap->iv_opmode == IEEE80211_M_WDS) decrease = 0; ieee80211_vap_detach(vap); /* NB: memory is reclaimed through dev->destructor callback */ if (decrease) sc->sc_nvaps--;#ifdef ATH_SUPERG_XR /* * If it's an XR VAP, free the memory allocated explicitly. * Since the XR VAP is not registered, OS cannot free the memory. */ if (vap->iv_flags & IEEE80211_F_XR) { ath_grppoll_stop(vap); ath_descdma_cleanup(sc, &sc->sc_grppolldma, &sc->sc_grppollbuf, BUS_DMA_FROMDEVICE); memset(&sc->sc_grppollbuf, 0, sizeof(sc->sc_grppollbuf)); memset(&sc->sc_grppolldma, 0, sizeof(sc->sc_grppolldma)); if (vap->iv_xrvap) vap->iv_xrvap->iv_xrvap = NULL; kfree(vap->iv_dev); ath_tx_cleanupq(sc, sc->sc_xrtxq); sc->sc_xrtxq = NULL; if (sc->sc_hasdiversity) { /* Restore diversity setting to old diversity setting */ ath_hal_setdiversity(ah, sc->sc_olddiversity); sc->sc_diversity = sc->sc_olddiversity; } }#endif for (i = 0; i < IEEE80211_APPIE_NUM_OF_FRAME; i++) { if (vap->app_ie[i].ie != NULL) { FREE(vap->app_ie[i].ie, M_DEVBUF); vap->app_ie[i].ie = NULL; vap->app_ie[i].length = 0; } } if (dev->flags & IFF_RUNNING) { /* Restart RX & TX machines if device is still running. */ if (ath_startrecv(sc) != 0) /* restart recv. */ EPRINTF(sc, "Unable to start receive logic.\n"); if (sc->sc_beacons) ath_beacon_config(sc, NULL); /* restart beacons */ ath_hal_intrset(ah, sc->sc_imask); }}voidath_suspend(struct net_device *dev){ DPRINTF(((struct ath_softc *)netdev_priv(dev)), ATH_DEBUG_ANY, "flags=%x\n", dev->flags); ath_stop(dev);}voidath_resume(struct net_device *dev){ DPRINTF(((struct ath_softc *)netdev_priv(dev)), ATH_DEBUG_ANY, "flags=%x\n", dev->flags); ath_init(dev);}/* NB: Int. mit. was not implemented so that it could be enabled/disabled, * and actually in 0.9.30.13 HAL it really can't even be disabled because * it will start adjusting registers even when we turn off the capability * in the HAL. * * NB: This helper function basically clobbers all the related registers * if we have disabled int. mit. cap, allowing us to turn it on and off and * work around the bug preventing it from being disabled. */static inline void ath_override_intmit_if_disabled(struct ath_softc *sc){ /* Restore int. mit. registers if they were turned off. */ if (sc->sc_hasintmit && !sc->sc_useintmit) ath_hal_restore_default_intmit(sc->sc_ah); /* Sanity check... remove later. */ if (!sc->sc_useintmit) { ath_hal_verify_default_intmit(sc->sc_ah); /* If we don't have int. mit. and we don't have DFS on channel, * it is safe to filter error packets. */ if (!ath_radar_is_dfs_required(sc, &sc->sc_curchan)) { ath_hal_setrxfilter(sc->sc_ah, ath_hal_getrxfilter(sc->sc_ah) & ~HAL_RX_FILTER_PHYERR); } } else { /* Make sure that we have errors in RX filter because ANI needs * them. */ ath_hal_setrxfilter(sc->sc_ah, ath_hal_getrxfilter(sc->sc_ah) | HAL_RX_FILTER_PHYERR); }}static inline HAL_BOOL ath_hw_puttxbuf(struct ath_softc *sc, u_int qnum, u_int32_t txdp, const char *msg){ HAL_BOOL result; u_int32_t txdp_2; result = ath_hal_puttxbuf(sc->sc_ah, qnum, txdp); if (!result) { DPRINTF(sc, ATH_DEBUG_WATCHDOG, "TXQ%d: BUG failed to set TXDP:%08x\n", qnum, txdp); ath_txq_check(sc, &sc->sc_txq[qnum], msg); return result; } txdp_2 = ath_hal_gettxbuf(sc->sc_ah, qnum); if (txdp_2 != txdp) { DPRINTF(sc, ATH_DEBUG_WATCHDOG, "TXQ%d: BUG failed to set TXDP:%08x (is %08x)\n", qnum, txdp, txdp_2); ath_txq_check(sc, &sc->sc_txq[qnum], msg); } return result;}/* If channel change is successful, sc->sc_curchan is updated with the new * channel */static HAL_BOOL ath_hw_reset(struct ath_softc *sc, HAL_OPMODE opmode, HAL_CHANNEL *channel, HAL_BOOL bChannelChange, HAL_STATUS *status){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -