📄 if_ath.c
字号:
ic->ic_scan_start = ath_scan_start; ic->ic_scan_end = ath_scan_end; ic->ic_set_channel = ath_set_channel; ic->ic_set_coverageclass = ath_set_coverageclass; ic->ic_mhz2ieee = ath_mhz2ieee; if (register_netdev(dev)) { printk(KERN_ERR "%s: unable to register device\n", dev->name); goto bad3; } /* * Attach dynamic MIB vars and announce support * now that we have a device name with unit number. */#ifdef CONFIG_SYSCTL ath_dynamic_sysctl_register(sc);#endif /* CONFIG_SYSCTL */ ieee80211_announce(ic); ath_announce(dev);#ifdef ATH_TX99_DIAG printk("%s: TX99 support enabled\n", dev->name);#endif sc->sc_invalid = 0; if (autocreate) { if (!strcmp(autocreate, "none")) autocreatemode = -1; else if (!strcmp(autocreate, "sta")) autocreatemode = IEEE80211_M_STA; else if (!strcmp(autocreate, "ap")) autocreatemode = IEEE80211_M_HOSTAP; else if (!strcmp(autocreate, "adhoc")) autocreatemode = IEEE80211_M_IBSS; else if (!strcmp(autocreate, "ahdemo")) autocreatemode = IEEE80211_M_AHDEMO; else if (!strcmp(autocreate, "wds")) autocreatemode = IEEE80211_M_WDS; else if (!strcmp(autocreate, "monitor")) autocreatemode = IEEE80211_M_MONITOR; else { printk(KERN_INFO "Unknown autocreate mode: %s\n", autocreate); autocreatemode = -1; } } if (autocreatemode != -1) { rtnl_lock(); error = ieee80211_create_vap(ic, "ath%d", dev, autocreatemode, IEEE80211_CLONE_BSSID); rtnl_unlock(); if (error) printk(KERN_ERR "%s: autocreation of vap failed: %d\n", dev->name, error); } return 0;bad3: ieee80211_ifdetach(ic); ath_rate_detach(sc->sc_rc);bad2: ath_tx_cleanup(sc); ath_desc_free(sc);bad: if (ah) ath_hal_detach(ah); ATH_TXBUF_LOCK_DESTROY(sc); ATH_LOCK_DESTROY(sc); sc->sc_invalid = 1; return error;}intath_detach(struct net_device *dev){ struct ath_softc *sc = dev->priv; struct ath_hal *ah = sc->sc_ah; HAL_INT tmp; DPRINTF(sc, ATH_DEBUG_ANY, "%s: flags %x\n", __func__, dev->flags); ath_stop(dev); ath_hal_setpower(sc->sc_ah, HAL_PM_AWAKE); /* Flush the radar task if it's scheduled */ if (sc->sc_rtasksched == 1) ATH_FLUSH_TASKS(); sc->sc_invalid = 1; /* * NB: the order of these is important: * o call the 802.11 layer before detaching the hal to * ensure callbacks into the driver to delete global * key cache entries can be handled * o reclaim the tx queue data structures after calling * the 802.11 layer as we'll get called back to reclaim * node state and potentially want to use them * o to cleanup the tx queues the hal is called, so detach * it last * Other than that, it's straightforward... */ ieee80211_ifdetach(&sc->sc_ic); ath_hal_intrset(ah, 0); /* disable further intr's */ ath_hal_getisr(ah, &tmp); /* clear ISR */ if(dev->irq) { free_irq(dev->irq, dev); dev->irq = 0; }#ifdef ATH_TX99_DIAG if (sc->sc_tx99 != NULL) sc->sc_tx99->detach(sc->sc_tx99);#endif ath_rate_detach(sc->sc_rc); ath_desc_free(sc); ath_tx_cleanup(sc); ath_hal_detach(ah);#ifdef CONFIG_SYSCTL ath_dynamic_sysctl_unregister(sc);#endif /* CONFIG_SYSCTL */ ATH_LOCK_DESTROY(sc); dev->stop = NULL; /* prevent calling ath_stop again */ unregister_netdev(dev); return 0;}static struct ieee80211vap *ath_vap_create(struct ieee80211com *ic, const char *name, int unit, int opmode, int flags, struct net_device *mdev){ struct ath_softc *sc = ic->ic_dev->priv; struct net_device *dev; struct ath_vap *avp; struct ieee80211vap *vap; int ic_opmode; /* XXX ic unlocked and race against add */ switch (opmode) { case IEEE80211_M_STA: /* ap+sta for repeater application */ if (sc->sc_nstavaps != 0) /* only one sta regardless */ return NULL; if ((sc->sc_nvaps != 0) && (!(flags & IEEE80211_NO_STABEACONS))) return NULL; /* If using station beacons, must first up */ if (flags & IEEE80211_NO_STABEACONS) { sc->sc_nostabeacons = 1; ic_opmode = IEEE80211_M_HOSTAP; /* Run with chip in AP mode */ } else ic_opmode = opmode; break; case IEEE80211_M_IBSS: if (sc->sc_nvaps != 0) /* only one */ 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 ap's 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_BCBUF) { printk(KERN_WARNING "too many virtual ap's (already got %d)\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 = dev->priv; ieee80211_vap_setup(ic, dev, name, unit, 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;#ifdef ATH_SUPERG_COMP vap->iv_comp_set = ath_comp_set;#endif /* Let rate control register proc entries for the vap */ ath_rate_dynamic_proc_register(vap); /* * Change the interface type for monitor mode. */ if (opmode == IEEE80211_M_MONITOR) dev->type = ARPHRD_IEEE80211_PRISM; if ((flags & IEEE80211_CLONE_BSSID) && sc->sc_nvaps != 0 && opmode != IEEE80211_M_WDS && sc->sc_hasbmask) { struct ieee80211vap *v; int id_mask, 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 ap's with distinct addresses. */ /* do a full search to mark all the allocated vaps */ id_mask = 0; TAILQ_FOREACH(v, &ic->ic_vaps, iv_next) id_mask |= (1 << ATH_GET_VAP_ID(v->iv_myaddr)); for (id = 0; id < ATH_BCBUF; id++) { /* get the first available slot */ if ((id_mask & (1 << id)) == 0) { ATH_SET_VAP_BSSID(vap->iv_myaddr, id); break; } } } avp->av_bslot = -1; STAILQ_INIT(&avp->av_mcastq.axq_q); ATH_TXQ_LOCK_INIT(&avp->av_mcastq); if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_IBSS) { /* * 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); if (opmode == IEEE80211_M_HOSTAP || !sc->sc_hasveol) { int slot; /* * 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_BCBUF; slot++) if (sc->sc_bslot[slot] == NULL) { /* * XXX hack, space out slots to better * deal with misses */ if (slot + 1 < ATH_BCBUF && 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 (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 */ sc->sc_stagbeacons = 1; } } if (sc->sc_hastsfadd) ath_hal_settsfadjust(sc->sc_ah, sc->sc_stagbeacons); SET_NETDEV_DEV(dev, mdev->class_dev.dev); /* 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) printk("%s:grppoll Buf allocation failed \n",__func__); 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 return vap;}static voidath_vap_delete(struct ieee80211vap *vap){ struct net_device *dev = vap->iv_ic->ic_dev; struct ath_softc *sc = dev->priv; struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp = ATH_VAP(vap); int decrease = 1; 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 vap's? */ 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--; if (sc->sc_nostabeacons) 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 its an XR vap ,free the memory allocated explicitly. * since the XR vap is not registered , OS can not 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 if (dev->flags & IFF_RUNNING) { /* * Restart rx+tx machines if device is still running. */ if (ath_startrecv(sc) != 0) /* restart recv */ printk("%s: %s: unable to start recv logic\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -