Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2008-09-25 13:16:16 -07:00
commit db4148da2c
60 changed files with 1077 additions and 1080 deletions

View file

@ -7107,7 +7107,7 @@ static int airo_get_aplist(struct net_device *dev,
*/ */
static int airo_set_scan(struct net_device *dev, static int airo_set_scan(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_param *vwrq, struct iw_point *dwrq,
char *extra) char *extra)
{ {
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;

View file

@ -147,7 +147,7 @@ static int airo_probe(struct pcmcia_device *p_dev)
DEBUG(0, "airo_attach()\n"); DEBUG(0, "airo_attach()\n");
/* Interrupt setup */ /* Interrupt setup */
p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
p_dev->irq.Handler = NULL; p_dev->irq.Handler = NULL;

View file

@ -2124,7 +2124,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
udelay(2300); mdelay(2);
/* /*
* Set the channel (with AGC turned off) * Set the channel (with AGC turned off)

View file

@ -820,8 +820,6 @@
#define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [5210] */ #define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [5210] */
#define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset [5210] */ #define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset [5210] */
#define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ #define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */
#define AR5K_RESET_CTL_CHIP (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA | \
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY)
/* /*
* Sleep control register * Sleep control register

View file

@ -173,8 +173,10 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
udelay(15); udelay(15);
if (ah->ah_version == AR5K_AR5210) { if (ah->ah_version == AR5K_AR5210) {
val &= AR5K_RESET_CTL_CHIP; val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
mask &= AR5K_RESET_CTL_CHIP; | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
} else { } else {
val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
@ -361,16 +363,20 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
/* Reset chipset */ /* Reset chipset */
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | if (ah->ah_version == AR5K_AR5210) {
AR5K_RESET_CTL_BASEBAND | bus_flags); ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
mdelay(2);
} else {
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
AR5K_RESET_CTL_BASEBAND | bus_flags);
}
if (ret) { if (ret) {
ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
return -EIO; return -EIO;
} }
if (ah->ah_version == AR5K_AR5210)
udelay(2300);
/* ...wakeup again!*/ /* ...wakeup again!*/
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
if (ret) { if (ret) {

View file

@ -16,7 +16,6 @@
/* Implementation of beacon processing. */ /* Implementation of beacon processing. */
#include <asm/unaligned.h>
#include "core.h" #include "core.h"
/* /*
@ -26,7 +25,6 @@
* the operating mode of the station (AP or AdHoc). Parameters are AIFS * the operating mode of the station (AP or AdHoc). Parameters are AIFS
* settings and channel width min/max * settings and channel width min/max
*/ */
static int ath_beaconq_config(struct ath_softc *sc) static int ath_beaconq_config(struct ath_softc *sc)
{ {
struct ath_hal *ah = sc->sc_ah; struct ath_hal *ah = sc->sc_ah;
@ -63,19 +61,18 @@ static int ath_beaconq_config(struct ath_softc *sc)
* up all required antenna switch parameters, rate codes, and channel flags. * up all required antenna switch parameters, rate codes, and channel flags.
* Beacons are always sent out at the lowest rate, and are not retried. * Beacons are always sent out at the lowest rate, and are not retried.
*/ */
static void ath_beacon_setup(struct ath_softc *sc, static void ath_beacon_setup(struct ath_softc *sc,
struct ath_vap *avp, struct ath_buf *bf) struct ath_vap *avp, struct ath_buf *bf)
{ {
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
struct ath_hal *ah = sc->sc_ah; struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds; struct ath_desc *ds;
int flags, antenna; struct ath9k_11n_rate_series series[4];
const struct ath9k_rate_table *rt; const struct ath9k_rate_table *rt;
int flags, antenna;
u8 rix, rate; u8 rix, rate;
int ctsrate = 0; int ctsrate = 0;
int ctsduration = 0; int ctsduration = 0;
struct ath9k_11n_rate_series series[4];
DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n", DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n",
__func__, skb, skb->len); __func__, skb, skb->len);
@ -115,20 +112,21 @@ static void ath_beacon_setup(struct ath_softc *sc,
rate |= rt->info[rix].shortPreamble; rate |= rt->info[rix].shortPreamble;
ath9k_hw_set11n_txdesc(ah, ds, ath9k_hw_set11n_txdesc(ah, ds,
skb->len + FCS_LEN, /* frame length */ skb->len + FCS_LEN, /* frame length */
ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */
avp->av_btxctl.txpower, /* txpower XXX */ avp->av_btxctl.txpower, /* txpower XXX */
ATH9K_TXKEYIX_INVALID, /* no encryption */ ATH9K_TXKEYIX_INVALID, /* no encryption */
ATH9K_KEY_TYPE_CLEAR, /* no encryption */ ATH9K_KEY_TYPE_CLEAR, /* no encryption */
flags /* no ack, veol for beacons */ flags /* no ack,
veol for beacons */
); );
/* NB: beacon's BufLen must be a multiple of 4 bytes */ /* NB: beacon's BufLen must be a multiple of 4 bytes */
ath9k_hw_filltxdesc(ah, ds, ath9k_hw_filltxdesc(ah, ds,
roundup(skb->len, 4), /* buffer length */ roundup(skb->len, 4), /* buffer length */
true, /* first segment */ true, /* first segment */
true, /* last segment */ true, /* last segment */
ds /* first descriptor */ ds /* first descriptor */
); );
memzero(series, sizeof(struct ath9k_11n_rate_series) * 4); memzero(series, sizeof(struct ath9k_11n_rate_series) * 4);
@ -153,22 +151,23 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
struct ath_buf *bf; struct ath_buf *bf;
struct ath_vap *avp; struct ath_vap *avp;
struct sk_buff *skb; struct sk_buff *skb;
int cabq_depth;
struct ath_txq *cabq; struct ath_txq *cabq;
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
int cabq_depth;
avp = sc->sc_vaps[if_id]; avp = sc->sc_vaps[if_id];
ASSERT(avp);
cabq = sc->sc_cabq; cabq = sc->sc_cabq;
ASSERT(avp);
if (avp->av_bcbuf == NULL) { if (avp->av_bcbuf == NULL) {
DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
__func__, avp, avp->av_bcbuf); __func__, avp, avp->av_bcbuf);
return NULL; return NULL;
} }
bf = avp->av_bcbuf; bf = avp->av_bcbuf;
skb = (struct sk_buff *) bf->bf_mpdu; skb = (struct sk_buff *)bf->bf_mpdu;
if (skb) { if (skb) {
pci_unmap_single(sc->pdev, bf->bf_dmacontext, pci_unmap_single(sc->pdev, bf->bf_dmacontext,
skb_end_pointer(skb) - skb->head, skb_end_pointer(skb) - skb->head,
@ -179,17 +178,19 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
bf->bf_mpdu = skb; bf->bf_mpdu = skb;
if (skb == NULL) if (skb == NULL)
return NULL; return NULL;
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
/* /*
* TODO: make sure the seq# gets assigned properly (vs. other * TODO: make sure the seq# gets assigned properly (vs. other
* TX frames) * TX frames)
*/ */
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
sc->seq_no += 0x10; sc->seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
} }
bf->bf_buf_addr = bf->bf_dmacontext = bf->bf_buf_addr = bf->bf_dmacontext =
pci_map_single(sc->pdev, skb->data, pci_map_single(sc->pdev, skb->data,
skb_end_pointer(skb) - skb->head, skb_end_pointer(skb) - skb->head,
@ -241,7 +242,6 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
* Startup beacon transmission for adhoc mode when they are sent entirely * Startup beacon transmission for adhoc mode when they are sent entirely
* by the hardware using the self-linked descriptor + veol trick. * by the hardware using the self-linked descriptor + veol trick.
*/ */
static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
{ {
struct ath_hal *ah = sc->sc_ah; struct ath_hal *ah = sc->sc_ah;
@ -278,7 +278,6 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
* min/max, and enable aifs). The info structure does not need to be * min/max, and enable aifs). The info structure does not need to be
* persistant. * persistant.
*/ */
int ath_beaconq_setup(struct ath_hal *ah) int ath_beaconq_setup(struct ath_hal *ah)
{ {
struct ath9k_tx_queue_info qi; struct ath9k_tx_queue_info qi;
@ -299,26 +298,24 @@ int ath_beaconq_setup(struct ath_hal *ah)
* the ATH interface. This routine also calculates the beacon "slot" for * the ATH interface. This routine also calculates the beacon "slot" for
* staggared beacons in the mBSSID case. * staggared beacons in the mBSSID case.
*/ */
int ath_beacon_alloc(struct ath_softc *sc, int if_id) int ath_beacon_alloc(struct ath_softc *sc, int if_id)
{ {
struct ath_vap *avp; struct ath_vap *avp;
struct ieee80211_hdr *wh; struct ieee80211_hdr *hdr;
struct ath_buf *bf; struct ath_buf *bf;
struct sk_buff *skb; struct sk_buff *skb;
__le64 tstamp;
avp = sc->sc_vaps[if_id]; avp = sc->sc_vaps[if_id];
ASSERT(avp); ASSERT(avp);
/* Allocate a beacon descriptor if we haven't done so. */ /* Allocate a beacon descriptor if we haven't done so. */
if (!avp->av_bcbuf) { if (!avp->av_bcbuf) {
/* /* Allocate beacon state for hostap/ibss. We know
* Allocate beacon state for hostap/ibss. We know * a buffer is available. */
* a buffer is available.
*/
avp->av_bcbuf = list_first_entry(&sc->sc_bbuf, avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
struct ath_buf, list); struct ath_buf, list);
list_del(&avp->av_bcbuf->list); list_del(&avp->av_bcbuf->list);
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
@ -362,9 +359,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
} }
/* /*
* NB: the beacon data buffer must be 32-bit aligned; * NB: the beacon data buffer must be 32-bit aligned.
* we assume the wbuf routines will return us something
* with this alignment (perhaps should assert).
* FIXME: Fill avp->av_btxctl.txpower and * FIXME: Fill avp->av_btxctl.txpower and
* avp->av_btxctl.shortPreamble * avp->av_btxctl.shortPreamble
*/ */
@ -375,6 +370,9 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
return -ENOMEM; return -ENOMEM;
} }
tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
sc->bc_tstamp = le64_to_cpu(tstamp);
/* /*
* Calculate a TSF adjustment factor required for * Calculate a TSF adjustment factor required for
* staggered beacons. Note that we assume the format * staggered beacons. Note that we assume the format
@ -408,8 +406,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
__func__, "stagger", __func__, "stagger",
avp->av_bslot, intval, (unsigned long long)tsfadjust); avp->av_bslot, intval, (unsigned long long)tsfadjust);
wh = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
memcpy(&wh[1], &val, sizeof(val)); memcpy(&hdr[1], &val, sizeof(val));
} }
bf->bf_buf_addr = bf->bf_dmacontext = bf->bf_buf_addr = bf->bf_dmacontext =
@ -425,9 +423,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
* Reclaim beacon resources and return buffer to the pool. * Reclaim beacon resources and return buffer to the pool.
* *
* Checks the VAP to put the beacon frame buffer back to the ATH object * Checks the VAP to put the beacon frame buffer back to the ATH object
* queue, and de-allocates any wbuf frames that were sent as CAB traffic. * queue, and de-allocates any skbs that were sent as CAB traffic.
*/ */
void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
{ {
if (avp->av_bcbuf != NULL) { if (avp->av_bcbuf != NULL) {
@ -459,10 +456,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
* Transmit one or more beacon frames at SWBA. Dynamic updates to the frame * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame
* contents are done as needed and the slot time is also adjusted based on * contents are done as needed and the slot time is also adjusted based on
* current state. * current state.
*
* This tasklet is not scheduled, it's called in ISR context.
*/ */
void ath9k_beacon_tasklet(unsigned long data) void ath9k_beacon_tasklet(unsigned long data)
{ {
struct ath_softc *sc = (struct ath_softc *)data; struct ath_softc *sc = (struct ath_softc *)data;
@ -490,6 +484,8 @@ void ath9k_beacon_tasklet(unsigned long data)
* and wait for the next. Missed beacons indicate * and wait for the next. Missed beacons indicate
* a problem and should not occur. If we miss too * a problem and should not occur. If we miss too
* many consecutive beacons reset the device. * many consecutive beacons reset the device.
*
* FIXME: Clean up this mess !!
*/ */
if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) { if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) {
sc->sc_bmisscount++; sc->sc_bmisscount++;
@ -505,19 +501,16 @@ void ath9k_beacon_tasklet(unsigned long data)
__func__, sc->sc_bmisscount); __func__, sc->sc_bmisscount);
if (show_cycles) { if (show_cycles) {
/* /*
* Display cycle counter stats * Display cycle counter stats from HW
* from HW to aide in debug of * to aide in debug of stickiness.
* stickiness.
*/ */
DPRINTF(sc, DPRINTF(sc, ATH_DBG_BEACON,
ATH_DBG_BEACON,
"%s: busy times: rx_clear=%d, " "%s: busy times: rx_clear=%d, "
"rx_frame=%d, tx_frame=%d\n", "rx_frame=%d, tx_frame=%d\n",
__func__, rx_clear, rx_frame, __func__, rx_clear, rx_frame,
tx_frame); tx_frame);
} else { } else {
DPRINTF(sc, DPRINTF(sc, ATH_DBG_BEACON,
ATH_DBG_BEACON,
"%s: unable to obtain " "%s: unable to obtain "
"busy times\n", __func__); "busy times\n", __func__);
} }
@ -529,8 +522,7 @@ void ath9k_beacon_tasklet(unsigned long data)
} else if (sc->sc_bmisscount >= BSTUCK_THRESH) { } else if (sc->sc_bmisscount >= BSTUCK_THRESH) {
if (sc->sc_flags & SC_OP_NO_RESET) { if (sc->sc_flags & SC_OP_NO_RESET) {
if (sc->sc_bmisscount == BSTUCK_THRESH) { if (sc->sc_bmisscount == BSTUCK_THRESH) {
DPRINTF(sc, DPRINTF(sc, ATH_DBG_BEACON,
ATH_DBG_BEACON,
"%s: beacon is officially " "%s: beacon is officially "
"stuck\n", __func__); "stuck\n", __func__);
ath9k_hw_dmaRegDump(ah); ath9k_hw_dmaRegDump(ah);
@ -542,13 +534,12 @@ void ath9k_beacon_tasklet(unsigned long data)
ath_bstuck_process(sc); ath_bstuck_process(sc);
} }
} }
return; return;
} }
if (sc->sc_bmisscount != 0) { if (sc->sc_bmisscount != 0) {
if (sc->sc_flags & SC_OP_NO_RESET) { if (sc->sc_flags & SC_OP_NO_RESET) {
DPRINTF(sc, DPRINTF(sc, ATH_DBG_BEACON,
ATH_DBG_BEACON,
"%s: resume beacon xmit after %u misses\n", "%s: resume beacon xmit after %u misses\n",
__func__, sc->sc_bmisscount); __func__, sc->sc_bmisscount);
} else { } else {
@ -572,10 +563,12 @@ void ath9k_beacon_tasklet(unsigned long data)
tsftu = TSF_TO_TU(tsf>>32, tsf); tsftu = TSF_TO_TU(tsf>>32, tsf);
slot = ((tsftu % intval) * ATH_BCBUF) / intval; slot = ((tsftu % intval) * ATH_BCBUF) / intval;
if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF]; if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF];
DPRINTF(sc, ATH_DBG_BEACON, DPRINTF(sc, ATH_DBG_BEACON,
"%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
__func__, slot, (unsigned long long) tsf, tsftu, __func__, slot, (unsigned long long)tsf, tsftu,
intval, if_id); intval, if_id);
bfaddr = 0; bfaddr = 0;
if (if_id != ATH_IF_ID_ANY) { if (if_id != ATH_IF_ID_ANY) {
bf = ath_beacon_generate(sc, if_id); bf = ath_beacon_generate(sc, if_id);
@ -632,9 +625,8 @@ void ath9k_beacon_tasklet(unsigned long data)
* Tasklet for Beacon Stuck processing * Tasklet for Beacon Stuck processing
* *
* Processing for Beacon Stuck. * Processing for Beacon Stuck.
* Basically calls the ath_internal_reset function to reset the chip. * Basically resets the chip.
*/ */
void ath_bstuck_process(struct ath_softc *sc) void ath_bstuck_process(struct ath_softc *sc)
{ {
DPRINTF(sc, ATH_DBG_BEACON, DPRINTF(sc, ATH_DBG_BEACON,
@ -658,13 +650,12 @@ void ath_bstuck_process(struct ath_softc *sc)
* interrupt when we stop seeing beacons from the AP * interrupt when we stop seeing beacons from the AP
* we've associated with. * we've associated with.
*/ */
void ath_beacon_config(struct ath_softc *sc, int if_id) void ath_beacon_config(struct ath_softc *sc, int if_id)
{ {
struct ath_hal *ah = sc->sc_ah; struct ath_hal *ah = sc->sc_ah;
u32 nexttbtt, intval;
struct ath_beacon_config conf; struct ath_beacon_config conf;
enum ath9k_opmode av_opmode; enum ath9k_opmode av_opmode;
u32 nexttbtt, intval;
if (if_id != ATH_IF_ID_ANY) if (if_id != ATH_IF_ID_ANY)
av_opmode = sc->sc_vaps[if_id]->av_opmode; av_opmode = sc->sc_vaps[if_id]->av_opmode;
@ -673,12 +664,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
memzero(&conf, sizeof(struct ath_beacon_config)); memzero(&conf, sizeof(struct ath_beacon_config));
/* FIXME: Use default values for now - Sujith */
/* Query beacon configuration first */
/*
* Protocol stack doesn't support dynamic beacon configuration,
* use default configurations.
*/
conf.beacon_interval = sc->hw->conf.beacon_int ? conf.beacon_interval = sc->hw->conf.beacon_int ?
sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
conf.listen_interval = 1; conf.listen_interval = 1;
@ -687,8 +672,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
/* extract tstamp from last beacon and convert to TU */ /* extract tstamp from last beacon and convert to TU */
nexttbtt = TSF_TO_TU(get_unaligned_le32(conf.u.last_tstamp + 4), nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp);
get_unaligned_le32(conf.u.last_tstamp));
/* XXX conditionalize multi-bss support? */ /* XXX conditionalize multi-bss support? */
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
/* /*
@ -704,12 +689,14 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
} }
if (nexttbtt == 0) /* e.g. for ap mode */ if (nexttbtt == 0) /* e.g. for ap mode */
nexttbtt = intval; nexttbtt = intval;
else if (intval) /* NB: can be 0 for monitor mode */ else if (intval) /* NB: can be 0 for monitor mode */
nexttbtt = roundup(nexttbtt, intval); nexttbtt = roundup(nexttbtt, intval);
DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
__func__, nexttbtt, intval, conf.beacon_interval); __func__, nexttbtt, intval, conf.beacon_interval);
/* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */
if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
struct ath9k_beacon_state bs; struct ath9k_beacon_state bs;
@ -723,19 +710,19 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
* last beacon we received (which may be none). * last beacon we received (which may be none).
*/ */
dtimperiod = conf.dtim_period; dtimperiod = conf.dtim_period;
if (dtimperiod <= 0) /* NB: 0 if not known */ if (dtimperiod <= 0) /* NB: 0 if not known */
dtimperiod = 1; dtimperiod = 1;
dtimcount = conf.dtim_count; dtimcount = conf.dtim_count;
if (dtimcount >= dtimperiod) /* NB: sanity check */ if (dtimcount >= dtimperiod) /* NB: sanity check */
dtimcount = 0; /* XXX? */ dtimcount = 0;
cfpperiod = 1; /* NB: no PCF support yet */ cfpperiod = 1; /* NB: no PCF support yet */
cfpcount = 0; cfpcount = 0;
sleepduration = conf.listen_interval * intval; sleepduration = conf.listen_interval * intval;
if (sleepduration <= 0) if (sleepduration <= 0)
sleepduration = intval; sleepduration = intval;
#define FUDGE 2 #define FUDGE 2
/* /*
* Pull nexttbtt forward to reflect the current * Pull nexttbtt forward to reflect the current
* TSF and calculate dtim+cfp state for the result. * TSF and calculate dtim+cfp state for the result.
@ -759,6 +746,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
bs.bs_cfpmaxduration = 0; bs.bs_cfpmaxduration = 0;
/* /*
* Calculate the number of consecutive beacons to miss * Calculate the number of consecutive beacons to miss
* before taking a BMISS interrupt. The configuration * before taking a BMISS interrupt. The configuration
@ -767,9 +755,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
* result to at most 15 beacons. * result to at most 15 beacons.
*/ */
if (sleepduration > intval) { if (sleepduration > intval) {
bs.bs_bmissthreshold = bs.bs_bmissthreshold = conf.listen_interval *
conf.listen_interval * ATH_DEFAULT_BMISS_LIMIT / 2;
ATH_DEFAULT_BMISS_LIMIT / 2;
} else { } else {
bs.bs_bmissthreshold = bs.bs_bmissthreshold =
DIV_ROUND_UP(conf.bmiss_timeout, intval); DIV_ROUND_UP(conf.bmiss_timeout, intval);
@ -789,8 +776,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
* XXX fixed at 100ms * XXX fixed at 100ms
*/ */
bs.bs_sleepduration = bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100),
roundup(IEEE80211_MS_TO_TU(100), sleepduration); sleepduration);
if (bs.bs_sleepduration > bs.bs_dtimperiod) if (bs.bs_sleepduration > bs.bs_dtimperiod)
bs.bs_sleepduration = bs.bs_dtimperiod; bs.bs_sleepduration = bs.bs_dtimperiod;
@ -834,9 +821,9 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
/* /*
* Pull nexttbtt forward to reflect the current * Pull nexttbtt forward to reflect the current
* TSF . * TSF
*/ */
#define FUDGE 2 #define FUDGE 2
if (!(intval & ATH9K_BEACON_RESET_TSF)) { if (!(intval & ATH9K_BEACON_RESET_TSF)) {
tsf = ath9k_hw_gettsf64(ah); tsf = ath9k_hw_gettsf64(ah);
tsftu = TSF_TO_TU((u32)(tsf>>32), tsftu = TSF_TO_TU((u32)(tsf>>32),

View file

@ -534,7 +534,8 @@ int ath_vap_attach(struct ath_softc *sc,
avp->av_opmode = opmode; avp->av_opmode = opmode;
avp->av_bslot = -1; avp->av_bslot = -1;
ath9k_hw_set_tsfadjust(sc->sc_ah, 1); if (opmode == ATH9K_M_HOSTAP)
ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
sc->sc_vaps[if_id] = avp; sc->sc_vaps[if_id] = avp;
sc->sc_nvaps++; sc->sc_nvaps++;

View file

@ -1001,6 +1001,7 @@ struct ath_softc {
u32 sc_bhalq; u32 sc_bhalq;
u32 sc_bmisscount; u32 sc_bmisscount;
u32 ast_be_xmit; /* beacons transmitted */ u32 ast_be_xmit; /* beacons transmitted */
u64 bc_tstamp;
/* Rate */ /* Rate */
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];

View file

@ -2526,6 +2526,11 @@ static void ath9k_ani_reset(struct ath_hal *ah)
} }
} }
/*
* Process a MIB interrupt. We may potentially be invoked because
* any of the MIB counters overflow/trigger so don't assume we're
* here because a PHY error counter triggered.
*/
void ath9k_hw_procmibevent(struct ath_hal *ah, void ath9k_hw_procmibevent(struct ath_hal *ah,
const struct ath9k_node_stats *stats) const struct ath9k_node_stats *stats)
{ {
@ -2533,18 +2538,20 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
u32 phyCnt1, phyCnt2; u32 phyCnt1, phyCnt2;
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n"); DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n");
/* Reset these counters regardless */
REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_OFDM, 0);
REG_WRITE(ah, AR_FILT_CCK, 0); REG_WRITE(ah, AR_FILT_CCK, 0);
if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
/* Clear the mib counters and save them in the stats */
ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
ahp->ah_stats.ast_nodestats = *stats; ahp->ah_stats.ast_nodestats = *stats;
if (!DO_ANI(ah)) if (!DO_ANI(ah))
return; return;
/* NB: these are not reset-on-read */
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
@ -2552,6 +2559,7 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
struct ar5416AniState *aniState = ahp->ah_curani; struct ar5416AniState *aniState = ahp->ah_curani;
u32 ofdmPhyErrCnt, cckPhyErrCnt; u32 ofdmPhyErrCnt, cckPhyErrCnt;
/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
ahp->ah_stats.ast_ani_ofdmerrs += ahp->ah_stats.ast_ani_ofdmerrs +=
ofdmPhyErrCnt - aniState->ofdmPhyErrCount; ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
@ -2562,11 +2570,17 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
cckPhyErrCnt - aniState->cckPhyErrCount; cckPhyErrCnt - aniState->cckPhyErrCount;
aniState->cckPhyErrCount = cckPhyErrCnt; aniState->cckPhyErrCount = cckPhyErrCnt;
/*
* NB: figure out which counter triggered. If both
* trigger we'll only deal with one as the processing
* clobbers the error counter so the trigger threshold
* check will never be true.
*/
if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
ath9k_hw_ani_ofdm_err_trigger(ah); ath9k_hw_ani_ofdm_err_trigger(ah);
if (aniState->cckPhyErrCount > aniState->cckTrigHigh) if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
ath9k_hw_ani_cck_err_trigger(ah); ath9k_hw_ani_cck_err_trigger(ah);
/* NB: always restart to insure the h/w counters are reset */
ath9k_ani_restart(ah); ath9k_ani_restart(ah);
} }
} }

View file

@ -20,6 +20,7 @@
*/ */
#include "core.h" #include "core.h"
/* FIXME: remove this include! */
#include "../net/mac80211/rate.h" #include "../net/mac80211/rate.h"
static u32 tx_triglevel_max; static u32 tx_triglevel_max;
@ -1812,20 +1813,18 @@ static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv)
} }
static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta) static void ath_setup_rates(struct ath_softc *sc,
struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta,
struct ath_rate_node *rc_priv)
{ {
struct ieee80211_supported_band *sband;
struct ieee80211_hw *hw = local_to_hw(local);
struct ath_softc *sc = hw->priv;
struct ath_rate_node *rc_priv = sta->rate_ctrl_priv;
int i, j = 0; int i, j = 0;
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
for (i = 0; i < sband->n_bitrates; i++) { for (i = 0; i < sband->n_bitrates; i++) {
if (sta->sta.supp_rates[local->hw.conf.channel->band] & BIT(i)) { if (sta->supp_rates[sband->band] & BIT(i)) {
rc_priv->neg_rates.rs_rates[j] rc_priv->neg_rates.rs_rates[j]
= (sband->bitrates[i].bitrate * 2) / 10; = (sband->bitrates[i].bitrate * 2) / 10;
j++; j++;
@ -1852,19 +1851,17 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
} }
/* Rate Control callbacks */ /* Rate Control callbacks */
static void ath_tx_status(void *priv, struct net_device *dev, static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ath_softc *sc = priv; struct ath_softc *sc = priv;
struct ath_tx_info_priv *tx_info_priv; struct ath_tx_info_priv *tx_info_priv;
struct ath_node *an; struct ath_node *an;
struct sta_info *sta;
struct ieee80211_local *local;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
__le16 fc; __le16 fc;
local = hw_to_local(sc->hw);
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control; fc = hdr->frame_control;
tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
@ -1873,8 +1870,7 @@ static void ath_tx_status(void *priv, struct net_device *dev,
an = ath_node_find(sc, hdr->addr1); an = ath_node_find(sc, hdr->addr1);
spin_unlock_bh(&sc->node_lock); spin_unlock_bh(&sc->node_lock);
sta = sta_info_get(local, hdr->addr1); if (!an || !priv_sta || !ieee80211_is_data(fc)) {
if (!an || !sta || !ieee80211_is_data(fc)) {
if (tx_info->driver_data[0] != NULL) { if (tx_info->driver_data[0] != NULL) {
kfree(tx_info->driver_data[0]); kfree(tx_info->driver_data[0]);
tx_info->driver_data[0] = NULL; tx_info->driver_data[0] = NULL;
@ -1882,24 +1878,22 @@ static void ath_tx_status(void *priv, struct net_device *dev,
return; return;
} }
if (tx_info->driver_data[0] != NULL) { if (tx_info->driver_data[0] != NULL) {
ath_rate_tx_complete(sc, an, sta->rate_ctrl_priv, tx_info_priv); ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
kfree(tx_info->driver_data[0]); kfree(tx_info->driver_data[0]);
tx_info->driver_data[0] = NULL; tx_info->driver_data[0] = NULL;
} }
} }
static void ath_tx_aggr_resp(struct ath_softc *sc, static void ath_tx_aggr_resp(struct ath_softc *sc,
struct sta_info *sta, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta,
struct ath_node *an, struct ath_node *an,
u8 tidno) u8 tidno)
{ {
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_local *local;
struct ath_atx_tid *txtid; struct ath_atx_tid *txtid;
struct ieee80211_supported_band *sband;
u16 buffersize = 0; u16 buffersize = 0;
int state; int state;
DECLARE_MAC_BUF(mac); struct sta_info *si;
if (!(sc->sc_flags & SC_OP_TXAGGR)) if (!(sc->sc_flags & SC_OP_TXAGGR))
return; return;
@ -1908,11 +1902,16 @@ static void ath_tx_aggr_resp(struct ath_softc *sc,
if (!txtid->paused) if (!txtid->paused)
return; return;
local = hw_to_local(sc->hw); /*
sband = hw->wiphy->bands[hw->conf.channel->band]; * XXX: This is entirely busted, we aren't supposed to
* access the sta from here because it's internal
* to mac80211, and looking at the state without
* locking is wrong too.
*/
si = container_of(sta, struct sta_info, sta);
buffersize = IEEE80211_MIN_AMPDU_BUF << buffersize = IEEE80211_MIN_AMPDU_BUF <<
sband->ht_info.ampdu_factor; /* FIXME */ sband->ht_info.ampdu_factor; /* FIXME */
state = sta->ampdu_mlme.tid_state_tx[tidno]; state = si->ampdu_mlme.tid_state_tx[tidno];
if (state & HT_ADDBA_RECEIVED_MSK) { if (state & HT_ADDBA_RECEIVED_MSK) {
txtid->addba_exchangecomplete = 1; txtid->addba_exchangecomplete = 1;
@ -1928,18 +1927,15 @@ static void ath_tx_aggr_resp(struct ath_softc *sc,
} }
} }
static void ath_get_rate(void *priv, struct net_device *dev, static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb, struct sk_buff *skb, struct rate_selection *sel)
struct rate_selection *sel)
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ath_softc *sc = priv;
struct sta_info *sta;
struct ath_softc *sc = (struct ath_softc *)priv;
struct ieee80211_hw *hw = sc->hw; struct ieee80211_hw *hw = sc->hw;
struct ath_tx_info_priv *tx_info_priv; struct ath_tx_info_priv *tx_info_priv;
struct ath_rate_node *ath_rc_priv; struct ath_rate_node *ath_rc_priv = priv_sta;
struct ath_node *an; struct ath_node *an;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
int is_probe = FALSE, chk, ret; int is_probe = FALSE, chk, ret;
@ -1955,8 +1951,7 @@ static void ath_get_rate(void *priv, struct net_device *dev,
ASSERT(tx_info->driver_data[0] != NULL); ASSERT(tx_info->driver_data[0] != NULL);
tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
sta = sta_info_get(local, hdr->addr1); lowest_idx = rate_lowest_index(sband, sta);
lowest_idx = rate_lowest_index(local, sband, sta);
tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10; tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
/* lowest rate for management and multicast/broadcast frames */ /* lowest rate for management and multicast/broadcast frames */
if (!ieee80211_is_data(fc) || if (!ieee80211_is_data(fc) ||
@ -1965,8 +1960,6 @@ static void ath_get_rate(void *priv, struct net_device *dev,
return; return;
} }
ath_rc_priv = sta->rate_ctrl_priv;
/* Find tx rate for unicast frames */ /* Find tx rate for unicast frames */
ath_rate_findrate(sc, ath_rc_priv, ath_rate_findrate(sc, ath_rc_priv,
ATH_11N_TXMAXTRY, 4, ATH_11N_TXMAXTRY, 4,
@ -1975,8 +1968,7 @@ static void ath_get_rate(void *priv, struct net_device *dev,
&is_probe, &is_probe,
false); false);
if (is_probe) if (is_probe)
sel->probe_idx = ((struct ath_tx_ratectrl *) sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
sta->rate_ctrl_priv)->probe_rate;
/* Ratecontrol sometimes returns invalid rate index */ /* Ratecontrol sometimes returns invalid rate index */
if (tx_info_priv->rcs[0].rix != 0xff) if (tx_info_priv->rcs[0].rix != 0xff)
@ -2020,37 +2012,31 @@ static void ath_get_rate(void *priv, struct net_device *dev,
__func__, __func__,
print_mac(mac, hdr->addr1)); print_mac(mac, hdr->addr1));
} else if (chk == AGGR_EXCHANGE_PROGRESS) } else if (chk == AGGR_EXCHANGE_PROGRESS)
ath_tx_aggr_resp(sc, sta, an, tid); ath_tx_aggr_resp(sc, sband, sta, an, tid);
} }
} }
} }
static void ath_rate_init(void *priv, void *priv_sta, static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_local *local, struct ieee80211_sta *sta, void *priv_sta)
struct sta_info *sta)
{ {
struct ieee80211_supported_band *sband; struct ath_softc *sc = priv;
struct ieee80211_hw *hw = local_to_hw(local);
struct ieee80211_conf *conf = &local->hw.conf;
struct ath_softc *sc = hw->priv;
struct ath_rate_node *ath_rc_priv = priv_sta; struct ath_rate_node *ath_rc_priv = priv_sta;
int i, j = 0; int i, j = 0;
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; ath_setup_rates(sc, sband, sta, ath_rc_priv);
if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
ath_setup_rates(local, sta);
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
for (i = 0; i < MCS_SET_SIZE; i++) { for (i = 0; i < MCS_SET_SIZE; i++) {
if (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
if (j == ATH_RATE_MAX) if (j == ATH_RATE_MAX)
break; break;
} }
ath_rc_priv->neg_ht_rates.rs_nrates = j; ath_rc_priv->neg_ht_rates.rs_nrates = j;
} }
ath_rc_node_update(hw, priv_sta); ath_rc_node_update(sc->hw, priv_sta);
} }
static void ath_rate_clear(void *priv) static void ath_rate_clear(void *priv)
@ -2058,13 +2044,12 @@ static void ath_rate_clear(void *priv)
return; return;
} }
static void *ath_rate_alloc(struct ieee80211_local *local) static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{ {
struct ieee80211_hw *hw = local_to_hw(local);
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
return local->hw.priv; return hw->priv;
} }
static void ath_rate_free(void *priv) static void ath_rate_free(void *priv)
@ -2072,7 +2057,7 @@ static void ath_rate_free(void *priv)
return; return;
} }
static void *ath_rate_alloc_sta(void *priv, gfp_t gfp) static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{ {
struct ath_softc *sc = priv; struct ath_softc *sc = priv;
struct ath_vap *avp = sc->sc_vaps[0]; struct ath_vap *avp = sc->sc_vaps[0];
@ -2092,7 +2077,8 @@ static void *ath_rate_alloc_sta(void *priv, gfp_t gfp)
return rate_priv; return rate_priv;
} }
static void ath_rate_free_sta(void *priv, void *priv_sta) static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
void *priv_sta)
{ {
struct ath_rate_node *rate_priv = priv_sta; struct ath_rate_node *rate_priv = priv_sta;
struct ath_softc *sc = priv; struct ath_softc *sc = priv;
@ -2111,7 +2097,7 @@ static struct rate_control_ops ath_rate_ops = {
.alloc = ath_rate_alloc, .alloc = ath_rate_alloc,
.free = ath_rate_free, .free = ath_rate_free,
.alloc_sta = ath_rate_alloc_sta, .alloc_sta = ath_rate_alloc_sta,
.free_sta = ath_rate_free_sta .free_sta = ath_rate_free_sta,
}; };
int ath_rate_control_register(void) int ath_rate_control_register(void)

View file

@ -2258,7 +2258,7 @@ static int atmel_get_freq(struct net_device *dev,
static int atmel_set_scan(struct net_device *dev, static int atmel_set_scan(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_param *vwrq, struct iw_point *dwrq,
char *extra) char *extra)
{ {
struct atmel_private *priv = netdev_priv(dev); struct atmel_private *priv = netdev_priv(dev);

View file

@ -158,7 +158,7 @@ static int atmel_probe(struct pcmcia_device *p_dev)
DEBUG(0, "atmel_attach()\n"); DEBUG(0, "atmel_attach()\n");
/* Interrupt setup */ /* Interrupt setup */
p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
p_dev->irq.Handler = NULL; p_dev->irq.Handler = NULL;

View file

@ -188,6 +188,11 @@ void b43_rfkill_init(struct b43_wldev *dev)
"The built-in radio LED will not work.\n"); "The built-in radio LED will not work.\n");
#endif /* CONFIG_RFKILL_INPUT */ #endif /* CONFIG_RFKILL_INPUT */
#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE)
b43warn(wl, "The rfkill-input subsystem is not available. "
"The built-in radio LED will not work.\n");
#endif
err = input_register_polled_device(rfk->poll_dev); err = input_register_polled_device(rfk->poll_dev);
if (err) if (err)
goto err_unreg_rfk; goto err_unreg_rfk;

View file

@ -36,8 +36,6 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include "../net/mac80211/rate.h"
#include "iwl-3945.h" #include "iwl-3945.h"
#define RS_NAME "iwl-3945-rs" #define RS_NAME "iwl-3945-rs"
@ -319,10 +317,10 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
} }
} }
static void rs_rate_init(void *priv_rate, void *priv_sta, static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_local *local, struct sta_info *sta) struct ieee80211_sta *sta, void *priv_sta)
{ {
struct iwl3945_rs_sta *rs_sta = (void *)sta->rate_ctrl_priv; struct iwl3945_rs_sta *rs_sta = priv_sta;
int i; int i;
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
@ -333,22 +331,22 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
* after assoc.. */ * after assoc.. */
for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
if (sta->sta.supp_rates[local->hw.conf.channel->band] & (1 << i)) { if (sta->supp_rates[sband->band] & (1 << i)) {
rs_sta->last_txrate_idx = i; rs_sta->last_txrate_idx = i;
break; break;
} }
} }
/* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) if (sband->band == IEEE80211_BAND_5GHZ)
rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
IWL_DEBUG_RATE("leave\n"); IWL_DEBUG_RATE("leave\n");
} }
static void *rs_alloc(struct ieee80211_local *local) static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{ {
return local->hw.priv; return hw->priv;
} }
/* rate scale requires free function to be implemented */ /* rate scale requires free function to be implemented */
@ -356,17 +354,24 @@ static void rs_free(void *priv)
{ {
return; return;
} }
static void rs_clear(void *priv) static void rs_clear(void *priv)
{ {
return; return;
} }
static void *rs_alloc_sta(void *priv, gfp_t gfp) static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{ {
struct iwl3945_rs_sta *rs_sta; struct iwl3945_rs_sta *rs_sta;
struct iwl3945_sta_priv *psta = (void *) sta->drv_priv;
int i; int i;
/*
* XXX: If it's using sta->drv_priv anyway, it might
* as well just put all the information there.
*/
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp); rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp);
@ -375,6 +380,8 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp)
return NULL; return NULL;
} }
psta->rs_sta = rs_sta;
spin_lock_init(&rs_sta->lock); spin_lock_init(&rs_sta->lock);
rs_sta->start_rate = IWL_RATE_INVALID; rs_sta->start_rate = IWL_RATE_INVALID;
@ -400,10 +407,14 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp)
return rs_sta; return rs_sta;
} }
static void rs_free_sta(void *priv, void *priv_sta) static void rs_free_sta(void *priv, struct ieee80211_sta *sta,
void *priv_sta)
{ {
struct iwl3945_sta_priv *psta = (void *) sta->drv_priv;
struct iwl3945_rs_sta *rs_sta = priv_sta; struct iwl3945_rs_sta *rs_sta = priv_sta;
psta->rs_sta = NULL;
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
del_timer_sync(&rs_sta->rate_scale_flush); del_timer_sync(&rs_sta->rate_scale_flush);
kfree(rs_sta); kfree(rs_sta);
@ -445,26 +456,19 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
* NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by * NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by
* the hardware for each rate. * the hardware for each rate.
*/ */
static void rs_tx_status(void *priv_rate, static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband,
struct net_device *dev, struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb) struct sk_buff *skb)
{ {
u8 retries, current_count; u8 retries, current_count;
int scale_rate_index, first_index, last_index; int scale_rate_index, first_index, last_index;
unsigned long flags; unsigned long flags;
struct sta_info *sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iwl3945_rs_sta *rs_sta = priv_sta;
struct iwl3945_rs_sta *rs_sta;
struct ieee80211_supported_band *sband;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
retries = info->status.retry_count; retries = info->status.retry_count;
first_index = sband->bitrates[info->tx_rate_idx].hw_value; first_index = sband->bitrates[info->tx_rate_idx].hw_value;
if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
@ -472,17 +476,11 @@ static void rs_tx_status(void *priv_rate,
return; return;
} }
rcu_read_lock(); if (!priv_sta) {
sta = sta_info_get(local, hdr->addr1);
if (!sta || !sta->rate_ctrl_priv) {
rcu_read_unlock();
IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
return; return;
} }
rs_sta = (void *)sta->rate_ctrl_priv;
rs_sta->tx_packets++; rs_sta->tx_packets++;
scale_rate_index = first_index; scale_rate_index = first_index;
@ -549,8 +547,6 @@ static void rs_tx_status(void *priv_rate,
spin_unlock_irqrestore(&rs_sta->lock, flags); spin_unlock_irqrestore(&rs_sta->lock, flags);
rcu_read_unlock();
IWL_DEBUG_RATE("leave\n"); IWL_DEBUG_RATE("leave\n");
return; return;
@ -634,16 +630,15 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta,
* rate table and must reference the driver allocated rate table * rate table and must reference the driver allocated rate table
* *
*/ */
static void rs_get_rate(void *priv_rate, struct net_device *dev, static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb, struct sk_buff *skb, struct rate_selection *sel)
struct rate_selection *sel)
{ {
u8 low = IWL_RATE_INVALID; u8 low = IWL_RATE_INVALID;
u8 high = IWL_RATE_INVALID; u8 high = IWL_RATE_INVALID;
u16 high_low; u16 high_low;
int index; int index;
struct iwl3945_rs_sta *rs_sta; struct iwl3945_rs_sta *rs_sta = priv_sta;
struct iwl3945_rate_scale_data *window = NULL; struct iwl3945_rate_scale_data *window = NULL;
int current_tpt = IWL_INV_TPT; int current_tpt = IWL_INV_TPT;
int low_tpt = IWL_INV_TPT; int low_tpt = IWL_INV_TPT;
@ -651,34 +646,25 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
u32 fail_count; u32 fail_count;
s8 scale_action = 0; s8 scale_action = 0;
unsigned long flags; unsigned long flags;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct sta_info *sta;
u16 fc, rate_mask; u16 fc, rate_mask;
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest /* Send management frames and broadcast/multicast data using lowest
* rate. */ * rate. */
fc = le16_to_cpu(hdr->frame_control); fc = le16_to_cpu(hdr->frame_control);
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
is_multicast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) { !sta || !priv_sta) {
IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
sel->rate_idx = rate_lowest_index(local, sband, sta); sel->rate_idx = rate_lowest_index(sband, sta);
rcu_read_unlock();
return; return;
} }
rs_sta = (void *)sta->rate_ctrl_priv; rate_mask = sta->supp_rates[sband->band];
rate_mask = sta->sta.supp_rates[sband->band];
index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
if (sband->band == IEEE80211_BAND_5GHZ) if (sband->band == IEEE80211_BAND_5GHZ)
@ -811,8 +797,6 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
else else
sel->rate_idx = rs_sta->last_txrate_idx; sel->rate_idx = rs_sta->last_txrate_idx;
rcu_read_unlock();
IWL_DEBUG_RATE("leave: %d\n", index); IWL_DEBUG_RATE("leave: %d\n", index);
} }
@ -829,114 +813,28 @@ static struct rate_control_ops rs_ops = {
.free_sta = rs_free_sta, .free_sta = rs_free_sta,
}; };
int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
{
struct ieee80211_local *local = hw_to_local(hw);
struct iwl3945_priv *priv = hw->priv;
struct iwl3945_rs_sta *rs_sta;
struct sta_info *sta;
unsigned long flags;
int count = 0, i;
u32 samples = 0, success = 0, good = 0;
unsigned long now = jiffies;
u32 max_time = 0;
rcu_read_lock();
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
if (sta)
IWL_DEBUG_RATE("leave - no private rate data!\n");
else
IWL_DEBUG_RATE("leave - no station!\n");
rcu_read_unlock();
return sprintf(buf, "station %d not found\n", sta_id);
}
rs_sta = (void *)sta->rate_ctrl_priv;
spin_lock_irqsave(&rs_sta->lock, flags);
i = IWL_RATE_54M_INDEX;
while (1) {
u64 mask;
int j;
count +=
sprintf(&buf[count], " %2dMbs: ", iwl3945_rates[i].ieee / 2);
mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
buf[count++] =
(rs_sta->win[i].data & mask) ? '1' : '0';
samples += rs_sta->win[i].counter;
good += rs_sta->win[i].success_counter;
success += rs_sta->win[i].success_counter *
iwl3945_rates[i].ieee;
if (rs_sta->win[i].stamp) {
int delta =
jiffies_to_msecs(now - rs_sta->win[i].stamp);
if (delta > max_time)
max_time = delta;
count += sprintf(&buf[count], "%5dms\n", delta);
} else
buf[count++] = '\n';
j = iwl3945_get_prev_ieee_rate(i);
if (j == i)
break;
i = j;
}
spin_unlock_irqrestore(&rs_sta->lock, flags);
rcu_read_unlock();
/* Display the average rate of all samples taken.
*
* NOTE: We multiple # of samples by 2 since the IEEE measurement
* added from iwl3945_rates is actually 2X the rate */
if (samples)
count += sprintf(
&buf[count],
"\nAverage rate is %3d.%02dMbs over last %4dms\n"
"%3d%% success (%d good packets over %d tries)\n",
success / (2 * samples), (success * 5 / samples) % 10,
max_time, good * 100 / samples, good, samples);
else
count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
return count;
}
void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
{ {
struct iwl3945_priv *priv = hw->priv; struct iwl3945_priv *priv = hw->priv;
s32 rssi = 0; s32 rssi = 0;
unsigned long flags; unsigned long flags;
struct ieee80211_local *local = hw_to_local(hw);
struct iwl3945_rs_sta *rs_sta; struct iwl3945_rs_sta *rs_sta;
struct sta_info *sta; struct ieee80211_sta *sta;
struct iwl3945_sta_priv *psta;
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
if (!local->rate_ctrl->ops->name ||
strcmp(local->rate_ctrl->ops->name, RS_NAME)) {
IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n");
IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n");
return;
}
rcu_read_lock(); rcu_read_lock();
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) { psta = (void *) sta->drv_priv;
if (!sta || !psta) {
IWL_DEBUG_RATE("leave - no private rate data!\n"); IWL_DEBUG_RATE("leave - no private rate data!\n");
rcu_read_unlock(); rcu_read_unlock();
return; return;
} }
rs_sta = (void *)sta->rate_ctrl_priv; rs_sta = psta->rs_sta;
spin_lock_irqsave(&rs_sta->lock, flags); spin_lock_irqsave(&rs_sta->lock, flags);

View file

@ -175,15 +175,6 @@ static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
return rate; return rate;
} }
/**
* iwl3945_fill_rs_info - Fill an output text buffer with the rate representation
*
* NOTE: This is provided as a quick mechanism for a user to visualize
* the performance of the rate control algorithm and is not meant to be
* parsed software.
*/
extern int iwl3945_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
/** /**
* iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
* *

View file

@ -73,6 +73,10 @@ extern struct pci_device_id iwl3945_hw_card_ids[];
extern int iwl3945_param_hwcrypto; extern int iwl3945_param_hwcrypto;
extern int iwl3945_param_queues_num; extern int iwl3945_param_queues_num;
struct iwl3945_sta_priv {
struct iwl3945_rs_sta *rs_sta;
};
enum iwl3945_antenna { enum iwl3945_antenna {
IWL_ANTENNA_DIVERSITY, IWL_ANTENNA_DIVERSITY,
IWL_ANTENNA_MAIN, IWL_ANTENNA_MAIN,

View file

@ -35,8 +35,6 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include "../net/mac80211/rate.h"
#include "iwl-dev.h" #include "iwl-dev.h"
#include "iwl-sta.h" #include "iwl-sta.h"
#include "iwl-core.h" #include "iwl-core.h"
@ -169,9 +167,9 @@ struct iwl_lq_sta {
}; };
static void rs_rate_scale_perform(struct iwl_priv *priv, static void rs_rate_scale_perform(struct iwl_priv *priv,
struct net_device *dev,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
struct sta_info *sta); struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta);
static void rs_fill_link_cmd(const struct iwl_priv *priv, static void rs_fill_link_cmd(const struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, u32 rate_n_flags); struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
@ -357,20 +355,20 @@ static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
struct iwl_lq_sta *lq_data, u8 tid, struct iwl_lq_sta *lq_data, u8 tid,
struct sta_info *sta) struct ieee80211_sta *sta)
{ {
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n", IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n",
print_mac(mac, sta->sta.addr), tid); print_mac(mac, sta->addr), tid);
ieee80211_start_tx_ba_session(priv->hw, sta->sta.addr, tid); ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
} }
} }
static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
struct iwl_lq_sta *lq_data, struct iwl_lq_sta *lq_data,
struct sta_info *sta) struct ieee80211_sta *sta)
{ {
if ((tid < TID_MAX_LOAD_COUNT)) if ((tid < TID_MAX_LOAD_COUNT))
rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
@ -770,7 +768,8 @@ out:
/* /*
* mac80211 sends us Tx status * mac80211 sends us Tx status
*/ */
static void rs_tx_status(void *priv_rate, struct net_device *dev, static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb) struct sk_buff *skb)
{ {
int status; int status;
@ -778,11 +777,9 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
int rs_index, index = 0; int rs_index, index = 0;
struct iwl_lq_sta *lq_sta; struct iwl_lq_sta *lq_sta;
struct iwl_link_quality_cmd *table; struct iwl_link_quality_cmd *table;
struct sta_info *sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hw *hw = priv->hw;
struct ieee80211_hw *hw = local_to_hw(local);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_rate_scale_data *window = NULL; struct iwl_rate_scale_data *window = NULL;
struct iwl_rate_scale_data *search_win = NULL; struct iwl_rate_scale_data *search_win = NULL;
@ -808,15 +805,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
if (retries > 15) if (retries > 15)
retries = 15; retries = 15;
rcu_read_lock(); lq_sta = (struct iwl_lq_sta *)priv_sta;
sta = sta_info_get(local, hdr->addr1);
if (!sta || !sta->rate_ctrl_priv)
goto out;
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added) !lq_sta->ibss_sta_added)
@ -962,9 +951,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
} }
/* See if there's a better rate or modulation mode to try. */ /* See if there's a better rate or modulation mode to try. */
rs_rate_scale_perform(priv, dev, hdr, sta); rs_rate_scale_perform(priv, hdr, sta, lq_sta);
out: out:
rcu_read_unlock();
return; return;
} }
@ -1140,7 +1128,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
static int rs_switch_to_mimo2(struct iwl_priv *priv, static int rs_switch_to_mimo2(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf, struct ieee80211_conf *conf,
struct sta_info *sta, struct ieee80211_sta *sta,
struct iwl_scale_tbl_info *tbl, int index) struct iwl_scale_tbl_info *tbl, int index)
{ {
u16 rate_mask; u16 rate_mask;
@ -1148,10 +1136,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
s8 is_green = lq_sta->is_green; s8 is_green = lq_sta->is_green;
if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
!sta->sta.ht_info.ht_supported) !sta->ht_info.ht_supported)
return -1; return -1;
if (((sta->sta.ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
== WLAN_HT_CAP_SM_PS_STATIC) == WLAN_HT_CAP_SM_PS_STATIC)
return -1; return -1;
@ -1208,7 +1196,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
static int rs_switch_to_siso(struct iwl_priv *priv, static int rs_switch_to_siso(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf, struct ieee80211_conf *conf,
struct sta_info *sta, struct ieee80211_sta *sta,
struct iwl_scale_tbl_info *tbl, int index) struct iwl_scale_tbl_info *tbl, int index)
{ {
u16 rate_mask; u16 rate_mask;
@ -1216,7 +1204,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
s32 rate; s32 rate;
if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
!sta->sta.ht_info.ht_supported) !sta->ht_info.ht_supported)
return -1; return -1;
IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); IWL_DEBUG_RATE("LQ: try to switch to SISO\n");
@ -1268,7 +1256,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
static int rs_move_legacy_other(struct iwl_priv *priv, static int rs_move_legacy_other(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf, struct ieee80211_conf *conf,
struct sta_info *sta, struct ieee80211_sta *sta,
int index) int index)
{ {
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
@ -1376,7 +1364,7 @@ out:
static int rs_move_siso_to_other(struct iwl_priv *priv, static int rs_move_siso_to_other(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf, struct ieee80211_conf *conf,
struct sta_info *sta, int index) struct ieee80211_sta *sta, int index)
{ {
u8 is_green = lq_sta->is_green; u8 is_green = lq_sta->is_green;
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
@ -1487,7 +1475,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
static int rs_move_mimo_to_other(struct iwl_priv *priv, static int rs_move_mimo_to_other(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf, struct ieee80211_conf *conf,
struct sta_info *sta, int index) struct ieee80211_sta *sta, int index)
{ {
s8 is_green = lq_sta->is_green; s8 is_green = lq_sta->is_green;
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
@ -1680,12 +1668,11 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
* Do rate scaling and search for new modulation mode. * Do rate scaling and search for new modulation mode.
*/ */
static void rs_rate_scale_perform(struct iwl_priv *priv, static void rs_rate_scale_perform(struct iwl_priv *priv,
struct net_device *dev,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
struct sta_info *sta) struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hw *hw = priv->hw;
struct ieee80211_hw *hw = local_to_hw(local);
struct ieee80211_conf *conf = &hw->conf; struct ieee80211_conf *conf = &hw->conf;
int low = IWL_RATE_INVALID; int low = IWL_RATE_INVALID;
int high = IWL_RATE_INVALID; int high = IWL_RATE_INVALID;
@ -1700,7 +1687,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
__le16 fc; __le16 fc;
u16 rate_mask; u16 rate_mask;
u8 update_lq = 0; u8 update_lq = 0;
struct iwl_lq_sta *lq_sta;
struct iwl_scale_tbl_info *tbl, *tbl1; struct iwl_scale_tbl_info *tbl, *tbl1;
u16 rate_scale_index_msk = 0; u16 rate_scale_index_msk = 0;
u32 rate; u32 rate;
@ -1721,11 +1707,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
return; return;
} }
if (!sta || !sta->rate_ctrl_priv) if (!sta || !lq_sta)
return; return;
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
lq_sta->supp_rates = sta->sta.supp_rates[lq_sta->band];
tid = rs_tl_add_packet(lq_sta, hdr); tid = rs_tl_add_packet(lq_sta, hdr);
@ -2064,9 +2049,9 @@ out:
static void rs_initialize_lq(struct iwl_priv *priv, static void rs_initialize_lq(struct iwl_priv *priv,
struct ieee80211_conf *conf, struct ieee80211_conf *conf,
struct sta_info *sta) struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta)
{ {
struct iwl_lq_sta *lq_sta;
struct iwl_scale_tbl_info *tbl; struct iwl_scale_tbl_info *tbl;
int rate_idx; int rate_idx;
int i; int i;
@ -2075,10 +2060,9 @@ static void rs_initialize_lq(struct iwl_priv *priv,
u8 active_tbl = 0; u8 active_tbl = 0;
u8 valid_tx_ant; u8 valid_tx_ant;
if (!sta || !sta->rate_ctrl_priv) if (!sta || !lq_sta)
goto out; goto out;
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
i = lq_sta->last_txrate_idx; i = lq_sta->last_txrate_idx;
if ((lq_sta->lq.sta_id == 0xff) && if ((lq_sta->lq.sta_id == 0xff) &&
@ -2119,37 +2103,30 @@ static void rs_initialize_lq(struct iwl_priv *priv,
return; return;
} }
static void rs_get_rate(void *priv_rate, struct net_device *dev, static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb, struct sk_buff *skb, struct rate_selection *sel)
struct rate_selection *sel)
{ {
int i; int i;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_conf *conf = &local->hw.conf; struct ieee80211_conf *conf = &priv->hw->conf;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct sta_info *sta;
__le16 fc; __le16 fc;
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
struct iwl_lq_sta *lq_sta; struct iwl_lq_sta *lq_sta;
IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest /* Send management frames and broadcast/multicast data using lowest
* rate. */ * rate. */
fc = hdr->frame_control; fc = hdr->frame_control;
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) { !sta || !priv_sta) {
sel->rate_idx = rate_lowest_index(local, sband, sta); sel->rate_idx = rate_lowest_index(sband, sta);
goto out; return;
} }
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; lq_sta = (struct iwl_lq_sta *)priv_sta;
i = lq_sta->last_txrate_idx; i = lq_sta->last_txrate_idx;
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
@ -2167,23 +2144,22 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
lq_sta->lq.sta_id = sta_id; lq_sta->lq.sta_id = sta_id;
lq_sta->lq.rs_table[0].rate_n_flags = 0; lq_sta->lq.rs_table[0].rate_n_flags = 0;
lq_sta->ibss_sta_added = 1; lq_sta->ibss_sta_added = 1;
rs_initialize_lq(priv, conf, sta); rs_initialize_lq(priv, conf, sta, lq_sta);
} }
} }
if ((i < 0) || (i > IWL_RATE_COUNT)) { if ((i < 0) || (i > IWL_RATE_COUNT)) {
sel->rate_idx = rate_lowest_index(local, sband, sta); sel->rate_idx = rate_lowest_index(sband, sta);
goto out; return;
} }
if (sband->band == IEEE80211_BAND_5GHZ) if (sband->band == IEEE80211_BAND_5GHZ)
i -= IWL_FIRST_OFDM_RATE; i -= IWL_FIRST_OFDM_RATE;
sel->rate_idx = i; sel->rate_idx = i;
out:
rcu_read_unlock();
} }
static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
gfp_t gfp)
{ {
struct iwl_lq_sta *lq_sta; struct iwl_lq_sta *lq_sta;
struct iwl_priv *priv; struct iwl_priv *priv;
@ -2206,20 +2182,16 @@ static void *rs_alloc_sta(void *priv_rate, gfp_t gfp)
return lq_sta; return lq_sta;
} }
static void rs_rate_init(void *priv_rate, void *priv_sta, static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_local *local, struct ieee80211_sta *sta, void *priv_sta)
struct sta_info *sta)
{ {
int i, j; int i, j;
struct ieee80211_conf *conf = &local->hw.conf; struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_supported_band *sband; struct ieee80211_conf *conf = &priv->hw->conf;
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_lq_sta *lq_sta = priv_sta;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
lq_sta->flush_timer = 0; lq_sta->flush_timer = 0;
lq_sta->supp_rates = sta->sta.supp_rates[sband->band]; lq_sta->supp_rates = sta->supp_rates[sband->band];
for (j = 0; j < LQ_SIZE; j++) for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++) for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
@ -2232,17 +2204,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
lq_sta->ibss_sta_added = 0; lq_sta->ibss_sta_added = 0;
if (priv->iw_mode == NL80211_IFTYPE_AP) { if (priv->iw_mode == NL80211_IFTYPE_AP) {
u8 sta_id = iwl_find_station(priv, sta->sta.addr); u8 sta_id = iwl_find_station(priv, sta->addr);
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
/* for IBSS the call are from tasklet */ /* for IBSS the call are from tasklet */
IWL_DEBUG_RATE("LQ: ADD station %s\n", IWL_DEBUG_RATE("LQ: ADD station %s\n",
print_mac(mac, sta->sta.addr)); print_mac(mac, sta->addr));
if (sta_id == IWL_INVALID_STATION) { if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE("LQ: ADD station %s\n", IWL_DEBUG_RATE("LQ: ADD station %s\n",
print_mac(mac, sta->sta.addr)); print_mac(mac, sta->addr));
sta_id = iwl_add_station_flags(priv, sta->sta.addr, sta_id = iwl_add_station_flags(priv, sta->addr,
0, CMD_ASYNC, NULL); 0, CMD_ASYNC, NULL);
} }
if ((sta_id != IWL_INVALID_STATION)) { if ((sta_id != IWL_INVALID_STATION)) {
@ -2256,11 +2228,11 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
/* Find highest tx rate supported by hardware and destination station */ /* Find highest tx rate supported by hardware and destination station */
lq_sta->last_txrate_idx = 3; lq_sta->last_txrate_idx = 3;
for (i = 0; i < sband->n_bitrates; i++) for (i = 0; i < sband->n_bitrates; i++)
if (sta->sta.supp_rates[sband->band] & BIT(i)) if (sta->supp_rates[sband->band] & BIT(i))
lq_sta->last_txrate_idx = i; lq_sta->last_txrate_idx = i;
/* For MODE_IEEE80211A, skip over cck rates in global rate table */ /* For MODE_IEEE80211A, skip over cck rates in global rate table */
if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) if (sband->band == IEEE80211_BAND_5GHZ)
lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
lq_sta->is_dup = 0; lq_sta->is_dup = 0;
@ -2301,7 +2273,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
lq_sta->drv = priv; lq_sta->drv = priv;
rs_initialize_lq(priv, conf, sta); rs_initialize_lq(priv, conf, sta, lq_sta);
} }
static void rs_fill_link_cmd(const struct iwl_priv *priv, static void rs_fill_link_cmd(const struct iwl_priv *priv,
@ -2423,9 +2395,9 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv,
lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
} }
static void *rs_alloc(struct ieee80211_local *local) static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{ {
return local->hw.priv; return hw->priv;
} }
/* rate scale requires free function to be implemented */ /* rate scale requires free function to be implemented */
static void rs_free(void *priv_rate) static void rs_free(void *priv_rate)
@ -2446,12 +2418,12 @@ static void rs_clear(void *priv_rate)
#endif /* CONFIG_IWLWIFI_DEBUG */ #endif /* CONFIG_IWLWIFI_DEBUG */
} }
static void rs_free_sta(void *priv_rate, void *priv_sta) static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
void *priv_sta)
{ {
struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_priv *priv; struct iwl_priv *priv = priv_r;
priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
kfree(lq_sta); kfree(lq_sta);
IWL_DEBUG_RATE("leave\n"); IWL_DEBUG_RATE("leave\n");

View file

@ -2504,8 +2504,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
if (priv->current_ht_config.is_ht) iwl_set_rxon_ht(priv, &priv->current_ht_config);
iwl_set_rxon_ht(priv, &priv->current_ht_config);
iwl_set_rxon_chain(priv); iwl_set_rxon_chain(priv);
priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
@ -2568,8 +2567,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
iwl_chain_noise_reset(priv); iwl_chain_noise_reset(priv);
priv->start_calib = 1; priv->start_calib = 1;
/* we have just associated, don't start scan too early */
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
} }
static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
@ -3171,6 +3168,10 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
priv->power_data.dtim_period = bss_conf->dtim_period; priv->power_data.dtim_period = bss_conf->dtim_period;
priv->timestamp = bss_conf->timestamp; priv->timestamp = bss_conf->timestamp;
priv->assoc_capability = bss_conf->assoc_capability; priv->assoc_capability = bss_conf->assoc_capability;
/* we have just associated, don't start scan too early
* leave time for EAPOL exchange to complete
*/
priv->next_scan_jiffies = jiffies + priv->next_scan_jiffies = jiffies +
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
@ -3189,9 +3190,9 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
{ {
int ret;
unsigned long flags; unsigned long flags;
struct iwl_priv *priv = hw->priv; struct iwl_priv *priv = hw->priv;
int ret;
IWL_DEBUG_MAC80211("enter\n"); IWL_DEBUG_MAC80211("enter\n");
@ -3210,20 +3211,27 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
goto out_unlock; goto out_unlock;
} }
/* we don't schedule scan within next_scan_jiffies period */ /* We don't schedule scan within next_scan_jiffies period.
* Avoid scanning during possible EAPOL exchange, return
* success immediately.
*/
if (priv->next_scan_jiffies && if (priv->next_scan_jiffies &&
time_after(priv->next_scan_jiffies, jiffies)) { time_after(priv->next_scan_jiffies, jiffies)) {
IWL_DEBUG_SCAN("scan rejected: within next scan period\n"); IWL_DEBUG_SCAN("scan rejected: within next scan period\n");
ret = -EAGAIN; queue_work(priv->workqueue, &priv->scan_completed);
ret = 0;
goto out_unlock; goto out_unlock;
} }
/* if we just finished scan ask for delay */ /* if we just finished scan ask for delay */
if (iwl_is_associated(priv) && priv->last_scan_jiffies && if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
IWL_DEBUG_SCAN("scan rejected: within previous scan period\n"); IWL_DEBUG_SCAN("scan rejected: within previous scan period\n");
ret = -EAGAIN; queue_work(priv->workqueue, &priv->scan_completed);
ret = 0;
goto out_unlock; goto out_unlock;
} }
if (ssid_len) { if (ssid_len) {
priv->one_direct_scan = 1; priv->one_direct_scan = 1;
priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE); priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE);

View file

@ -646,8 +646,14 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
struct iwl_rxon_cmd *rxon = &priv->staging_rxon; struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
u32 val; u32 val;
if (!ht_info->is_ht) if (!ht_info->is_ht) {
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
RXON_FLG_CHANNEL_MODE_PURE_40_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
RXON_FLG_FAT_PROT_MSK |
RXON_FLG_HT_PROT_MSK);
return; return;
}
/* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */
if (iwl_is_fat_tx_allowed(priv, NULL)) if (iwl_is_fat_tx_allowed(priv, NULL))
@ -697,8 +703,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
} }
EXPORT_SYMBOL(iwl_set_rxon_ht); EXPORT_SYMBOL(iwl_set_rxon_ht);
/* #define IWL_NUM_RX_CHAINS_MULTIPLE 3
* Determine how many receiver/antenna chains to use. #define IWL_NUM_RX_CHAINS_SINGLE 2
#define IWL_NUM_IDLE_CHAINS_DUAL 2
#define IWL_NUM_IDLE_CHAINS_SINGLE 1
/* Determine how many receiver/antenna chains to use.
* More provides better reception via diversity. Fewer saves power. * More provides better reception via diversity. Fewer saves power.
* MIMO (dual stream) requires at least 2, but works better with 3. * MIMO (dual stream) requires at least 2, but works better with 3.
* This does not determine *which* chains to use, just how many. * This does not determine *which* chains to use, just how many.
@ -711,9 +721,9 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
/* # of Rx chains to use when expecting MIMO. */ /* # of Rx chains to use when expecting MIMO. */
if (is_single || (!is_cam && (priv->current_ht_config.sm_ps == if (is_single || (!is_cam && (priv->current_ht_config.sm_ps ==
WLAN_HT_CAP_SM_PS_STATIC))) WLAN_HT_CAP_SM_PS_STATIC)))
return 2; return IWL_NUM_RX_CHAINS_SINGLE;
else else
return 3; return IWL_NUM_RX_CHAINS_MULTIPLE;
} }
static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
@ -724,10 +734,11 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
switch (priv->current_ht_config.sm_ps) { switch (priv->current_ht_config.sm_ps) {
case WLAN_HT_CAP_SM_PS_STATIC: case WLAN_HT_CAP_SM_PS_STATIC:
case WLAN_HT_CAP_SM_PS_DYNAMIC: case WLAN_HT_CAP_SM_PS_DYNAMIC:
idle_cnt = (is_cam) ? 2 : 1; idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
IWL_NUM_IDLE_CHAINS_SINGLE;
break; break;
case WLAN_HT_CAP_SM_PS_DISABLED: case WLAN_HT_CAP_SM_PS_DISABLED:
idle_cnt = (is_cam) ? active_cnt : 1; idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
break; break;
case WLAN_HT_CAP_SM_PS_INVALID: case WLAN_HT_CAP_SM_PS_INVALID:
default: default:
@ -796,7 +807,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain); priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
if (!is_single && (active_rx_cnt >= 2) && is_cam) if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
else else
priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;

View file

@ -463,11 +463,6 @@ void iwl_init_scan_params(struct iwl_priv *priv)
int iwl_scan_initiate(struct iwl_priv *priv) int iwl_scan_initiate(struct iwl_priv *priv)
{ {
if (priv->iw_mode == NL80211_IFTYPE_AP) {
IWL_ERROR("APs don't scan.\n");
return 0;
}
if (!iwl_is_ready_rf(priv)) { if (!iwl_is_ready_rf(priv)) {
IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
return -EIO; return -EIO;
@ -479,8 +474,7 @@ int iwl_scan_initiate(struct iwl_priv *priv)
} }
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
IWL_DEBUG_SCAN("Scan request while abort pending. " IWL_DEBUG_SCAN("Scan request while abort pending\n");
"Queuing.\n");
return -EAGAIN; return -EAGAIN;
} }

View file

@ -1200,10 +1200,9 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
/* If a Tx command is being handled and it isn't in the actual /* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced * command queue then there a command routing bug has been introduced
* in the queue management code. */ * in the queue management code. */
if (txq_id != IWL_CMD_QUEUE_NUM) if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
IWL_ERROR("Error wrong command queue %d command id 0x%X\n", "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd))
txq_id, pkt->hdr.cmd); return;
BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];

View file

@ -7370,15 +7370,6 @@ static ssize_t show_temperature(struct device *d,
static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
static ssize_t show_rs_window(struct device *d,
struct device_attribute *attr,
char *buf)
{
struct iwl3945_priv *priv = d->driver_data;
return iwl3945_fill_rs_info(priv->hw, buf, IWL_AP_ID);
}
static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
static ssize_t show_tx_power(struct device *d, static ssize_t show_tx_power(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
@ -7840,7 +7831,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
#endif #endif
&dev_attr_power_level.attr, &dev_attr_power_level.attr,
&dev_attr_retry_rate.attr, &dev_attr_retry_rate.attr,
&dev_attr_rs_window.attr,
&dev_attr_statistics.attr, &dev_attr_statistics.attr,
&dev_attr_status.attr, &dev_attr_status.attr,
&dev_attr_temperature.attr, &dev_attr_temperature.attr,
@ -7908,6 +7898,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
SET_IEEE80211_DEV(hw, &pdev->dev); SET_IEEE80211_DEV(hw, &pdev->dev);
hw->rate_control_algorithm = "iwl-3945-rs"; hw->rate_control_algorithm = "iwl-3945-rs";
hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
priv = hw->priv; priv = hw->priv;

View file

@ -58,6 +58,7 @@ struct lbs_802_11_security {
u8 WPA2enabled; u8 WPA2enabled;
u8 wep_enabled; u8 wep_enabled;
u8 auth_mode; u8 auth_mode;
u32 key_mgmt;
}; };
/** Current Basic Service Set State Structure */ /** Current Basic Service Set State Structure */

View file

@ -1598,8 +1598,20 @@ static int lbs_set_encodeext(struct net_device *dev,
} }
out: out:
if (ret == 0) { /* key installation is time critical: postpone not! */ if (ret == 0) {
lbs_do_association_work(priv); /* 802.1x and WPA rekeying must happen as quickly as possible,
* especially during the 4-way handshake; thus if in
* infrastructure mode, and either (a) 802.1x is enabled or
* (b) WPA is being used, set the key right away.
*/
if (assoc_req->mode == IW_MODE_INFRA &&
((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ||
(assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) ||
assoc_req->secinfo.WPAenabled ||
assoc_req->secinfo.WPA2enabled)) {
lbs_do_association_work(priv);
} else
lbs_postpone_association_work(priv);
} else { } else {
lbs_cancel_association_work(priv); lbs_cancel_association_work(priv);
} }
@ -1707,13 +1719,17 @@ static int lbs_set_auth(struct net_device *dev,
case IW_AUTH_TKIP_COUNTERMEASURES: case IW_AUTH_TKIP_COUNTERMEASURES:
case IW_AUTH_CIPHER_PAIRWISE: case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP: case IW_AUTH_CIPHER_GROUP:
case IW_AUTH_KEY_MGMT:
case IW_AUTH_DROP_UNENCRYPTED: case IW_AUTH_DROP_UNENCRYPTED:
/* /*
* libertas does not use these parameters * libertas does not use these parameters
*/ */
break; break;
case IW_AUTH_KEY_MGMT:
assoc_req->secinfo.key_mgmt = dwrq->value;
updated = 1;
break;
case IW_AUTH_WPA_VERSION: case IW_AUTH_WPA_VERSION:
if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
assoc_req->secinfo.WPAenabled = 0; assoc_req->secinfo.WPAenabled = 0;
@ -1793,6 +1809,10 @@ static int lbs_get_auth(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
switch (dwrq->flags & IW_AUTH_INDEX) { switch (dwrq->flags & IW_AUTH_INDEX) {
case IW_AUTH_KEY_MGMT:
dwrq->value = priv->secinfo.key_mgmt;
break;
case IW_AUTH_WPA_VERSION: case IW_AUTH_WPA_VERSION:
dwrq->value = 0; dwrq->value = 0;
if (priv->secinfo.WPAenabled) if (priv->secinfo.WPAenabled)

View file

@ -398,7 +398,7 @@ static int netwave_probe(struct pcmcia_device *link)
link->io.IOAddrLines = 5; link->io.IOAddrLines = 5;
/* Interrupt setup */ /* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = &netwave_interrupt; link->irq.Handler = &netwave_interrupt;

View file

@ -5291,7 +5291,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
/* Trigger a scan (look for other cells in the vicinity) */ /* Trigger a scan (look for other cells in the vicinity) */
static int orinoco_ioctl_setscan(struct net_device *dev, static int orinoco_ioctl_setscan(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_param *srq, struct iw_point *srq,
char *extra) char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);

View file

@ -121,7 +121,7 @@ orinoco_cs_probe(struct pcmcia_device *link)
link->priv = dev; link->priv = dev;
/* Interrupt setup */ /* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt; link->irq.Handler = orinoco_interrupt;
link->irq.Instance = dev; link->irq.Instance = dev;

View file

@ -325,7 +325,7 @@ static int ray_probe(struct pcmcia_device *p_dev)
p_dev->io.IOAddrLines = 5; p_dev->io.IOAddrLines = 5;
/* Interrupt setup. For PCMCIA, driver takes what's given */ /* Interrupt setup. For PCMCIA, driver takes what's given */
p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
p_dev->irq.Handler = &ray_interrupt; p_dev->irq.Handler = &ray_interrupt;

View file

@ -1627,7 +1627,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
static int rndis_iw_set_scan(struct net_device *dev, static int rndis_iw_set_scan(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra) struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{ {
struct iw_param *param = &wrqu->param;
struct usbnet *usbdev = dev->priv; struct usbnet *usbdev = dev->priv;
union iwreq_data evt; union iwreq_data evt;
int ret = -EINVAL; int ret = -EINVAL;
@ -1635,7 +1634,7 @@ static int rndis_iw_set_scan(struct net_device *dev,
devdbg(usbdev, "SIOCSIWSCAN"); devdbg(usbdev, "SIOCSIWSCAN");
if (param->flags == 0) { if (wrqu->data.flags == 0) {
tmp = ccpu2(1); tmp = ccpu2(1);
ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
sizeof(tmp)); sizeof(tmp));

View file

@ -543,7 +543,8 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* provided but key 0 is not, then the key is not found * provided but key 0 is not, then the key is not found
* by the hardware during RX). * by the hardware during RX).
*/ */
key->hw_key_idx = 0; if (cmd == SET_KEY)
key->hw_key_idx = 0;
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
set_key = rt2x00dev->ops->lib->config_pairwise_key; set_key = rt2x00dev->ops->lib->config_pairwise_key;

View file

@ -381,7 +381,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
if (reg && reg == mask) if (reg && reg == mask)
return -ENOSPC; return -ENOSPC;
key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; key->hw_key_idx += reg ? ffz(reg) : 0;
/* /*
* Upload key to hardware * Upload key to hardware
@ -477,7 +477,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
return -ENOSPC; return -ENOSPC;
} }
key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; key->hw_key_idx += reg ? ffz(reg) : 0;
/* /*
* Upload key to hardware * Upload key to hardware

View file

@ -393,7 +393,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
if (reg && reg == mask) if (reg && reg == mask)
return -ENOSPC; return -ENOSPC;
key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; key->hw_key_idx += reg ? ffz(reg) : 0;
/* /*
* Upload key to hardware * Upload key to hardware
@ -494,7 +494,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
return -ENOSPC; return -ENOSPC;
} }
key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; key->hw_key_idx += reg ? ffz(reg) : 0;
/* /*
* Upload key to hardware * Upload key to hardware

View file

@ -195,7 +195,7 @@ spectrum_cs_probe(struct pcmcia_device *link)
link->priv = dev; link->priv = dev;
/* Interrupt setup */ /* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt; link->irq.Handler = orinoco_interrupt;
link->irq.Instance = dev; link->irq.Instance = dev;

View file

@ -4496,7 +4496,7 @@ wavelan_probe(struct pcmcia_device *p_dev)
p_dev->io.IOAddrLines = 3; p_dev->io.IOAddrLines = 3;
/* Interrupt setup */ /* Interrupt setup */
p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
p_dev->irq.Handler = wavelan_interrupt; p_dev->irq.Handler = wavelan_interrupt;

View file

@ -1917,7 +1917,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
p_dev->io.IOAddrLines = 5; p_dev->io.IOAddrLines = 5;
/* Interrupt setup */ /* Interrupt setup */
p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
p_dev->irq.Handler = wl3501_interrupt; p_dev->irq.Handler = wl3501_interrupt;

View file

@ -471,6 +471,11 @@ struct ieee80211s_hdr {
u8 eaddr3[6]; u8 eaddr3[6];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Mesh flags */
#define MESH_FLAGS_AE_A4 0x1
#define MESH_FLAGS_AE_A5_A6 0x2
#define MESH_FLAGS_PS_DEEP 0x4
/** /**
* struct ieee80211_quiet_ie * struct ieee80211_quiet_ie
* *

View file

@ -363,11 +363,13 @@ struct wiphy;
* wireless extensions but this is subject to reevaluation as soon as this * wireless extensions but this is subject to reevaluation as soon as this
* code is used more widely and we have a first user without wext. * code is used more widely and we have a first user without wext.
* *
* @add_virtual_intf: create a new virtual interface with the given name * @add_virtual_intf: create a new virtual interface with the given name,
* must set the struct wireless_dev's iftype.
* *
* @del_virtual_intf: remove the virtual interface determined by ifindex. * @del_virtual_intf: remove the virtual interface determined by ifindex.
* *
* @change_virtual_intf: change type of virtual interface * @change_virtual_intf: change type/configuration of virtual interface,
* keep the struct wireless_dev's iftype updated.
* *
* @add_key: add a key with the given parameters. @mac_addr will be %NULL * @add_key: add a key with the given parameters. @mac_addr will be %NULL
* when adding a group key. * when adding a group key.

View file

@ -1800,4 +1800,72 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
const u8 *addr); const u8 *addr);
/* Rate control API */
/**
* struct rate_selection - rate information for/from rate control algorithms
*
* @rate_idx: selected transmission rate index
* @nonerp_idx: Non-ERP rate to use instead if ERP cannot be used
* @probe_idx: rate for probing (or -1)
* @max_rate_idx: maximum rate index that can be used, this is
* input to the algorithm and will be enforced
*/
struct rate_selection {
s8 rate_idx, nonerp_idx, probe_idx, max_rate_idx;
};
struct rate_control_ops {
struct module *module;
const char *name;
void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir);
void (*clear)(void *priv);
void (*free)(void *priv);
void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp);
void (*rate_init)(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta);
void (*free_sta)(void *priv, struct ieee80211_sta *sta,
void *priv_sta);
void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb);
void (*get_rate)(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb,
struct rate_selection *sel);
void (*add_sta_debugfs)(void *priv, void *priv_sta,
struct dentry *dir);
void (*remove_sta_debugfs)(void *priv, void *priv_sta);
};
static inline int rate_supported(struct ieee80211_sta *sta,
enum ieee80211_band band,
int index)
{
return (sta == NULL || sta->supp_rates[band] & BIT(index));
}
static inline s8
rate_lowest_index(struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta)
{
int i;
for (i = 0; i < sband->n_bitrates; i++)
if (rate_supported(sta, sband->band, i))
return i;
/* warn when we cannot find a rate. */
WARN_ON(1);
return 0;
}
int ieee80211_rate_control_register(struct rate_control_ops *ops);
void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
#endif /* MAC80211_H */ #endif /* MAC80211_H */

View file

@ -223,9 +223,11 @@ struct wiphy {
* the netdev.) * the netdev.)
* *
* @wiphy: pointer to hardware description * @wiphy: pointer to hardware description
* @iftype: interface type
*/ */
struct wireless_dev { struct wireless_dev {
struct wiphy *wiphy; struct wiphy *wiphy;
enum nl80211_iftype iftype;
/* private to the generic wireless code */ /* private to the generic wireless code */
struct list_head list; struct list_head list;
@ -328,6 +330,15 @@ extern int ieee80211_frequency_to_channel(int freq);
*/ */
extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
int freq); int freq);
/**
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
*/
static inline struct ieee80211_channel *
ieee80211_get_channel(struct wiphy *wiphy, int freq)
{
return __ieee80211_get_channel(wiphy, freq);
}
/** /**
* __regulatory_hint - hint to the wireless core a regulatory domain * __regulatory_hint - hint to the wireless core a regulatory domain
* @wiphy: if a driver is providing the hint this is the driver's very * @wiphy: if a driver is providing the hint this is the driver's very
@ -380,13 +391,4 @@ extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
*/ */
extern int regulatory_hint(struct wiphy *wiphy, extern int regulatory_hint(struct wiphy *wiphy,
const char *alpha2, struct ieee80211_regdomain *rd); const char *alpha2, struct ieee80211_regdomain *rd);
/**
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
*/
static inline struct ieee80211_channel *
ieee80211_get_channel(struct wiphy *wiphy, int freq)
{
return __ieee80211_get_channel(wiphy, freq);
}
#endif /* __NET_WIRELESS_H */ #endif /* __NET_WIRELESS_H */

View file

@ -82,7 +82,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
enum nl80211_iftype type, u32 *flags, enum nl80211_iftype type, u32 *flags,
struct vif_params *params) struct vif_params *params)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct net_device *dev; struct net_device *dev;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int ret; int ret;
@ -95,15 +94,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
if (!nl80211_type_check(type)) if (!nl80211_type_check(type))
return -EINVAL; return -EINVAL;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ret = ieee80211_if_change_type(sdata, type); ret = ieee80211_if_change_type(sdata, type);
if (ret) if (ret)
return ret; return ret;
if (netif_running(sdata->dev))
return -EBUSY;
if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
ieee80211_sdata_set_mesh_id(sdata, ieee80211_sdata_set_mesh_id(sdata,
params->mesh_id_len, params->mesh_id_len,
@ -120,16 +119,12 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, u8 *mac_addr, u8 key_idx, u8 *mac_addr,
struct key_params *params) struct key_params *params)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct sta_info *sta = NULL; struct sta_info *sta = NULL;
enum ieee80211_key_alg alg; enum ieee80211_key_alg alg;
struct ieee80211_key *key; struct ieee80211_key *key;
int err; int err;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (params->cipher) { switch (params->cipher) {
@ -174,14 +169,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, u8 *mac_addr) u8 key_idx, u8 *mac_addr)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct sta_info *sta; struct sta_info *sta;
int ret; int ret;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
rcu_read_lock(); rcu_read_lock();
@ -222,7 +213,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
void (*callback)(void *cookie, void (*callback)(void *cookie,
struct key_params *params)) struct key_params *params))
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct sta_info *sta = NULL; struct sta_info *sta = NULL;
u8 seq[6] = {0}; u8 seq[6] = {0};
@ -232,9 +222,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
u16 iv16; u16 iv16;
int err = -ENOENT; int err = -ENOENT;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
rcu_read_lock(); rcu_read_lock();
@ -310,12 +297,8 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
u8 key_idx) u8 key_idx)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
if (dev == local->mdev)
return -EOPNOTSUPP;
rcu_read_lock(); rcu_read_lock();
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@ -496,13 +479,9 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *params) struct beacon_parameters *params)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct beacon_data *old; struct beacon_data *old;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type != NL80211_IFTYPE_AP) if (sdata->vif.type != NL80211_IFTYPE_AP)
@ -519,13 +498,9 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *params) struct beacon_parameters *params)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct beacon_data *old; struct beacon_data *old;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type != NL80211_IFTYPE_AP) if (sdata->vif.type != NL80211_IFTYPE_AP)
@ -541,13 +516,9 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct beacon_data *old; struct beacon_data *old;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type != NL80211_IFTYPE_AP) if (sdata->vif.type != NL80211_IFTYPE_AP)
@ -695,9 +666,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int err; int err;
if (dev == local->mdev || params->vlan == local->mdev)
return -EOPNOTSUPP;
/* Prevent a race with changing the rate control algorithm */ /* Prevent a race with changing the rate control algorithm */
if (!netif_running(dev)) if (!netif_running(dev))
return -ENETDOWN; return -ENETDOWN;
@ -725,7 +693,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
sta_apply_parameters(local, sta, params); sta_apply_parameters(local, sta, params);
rate_control_rate_init(sta, local); rate_control_rate_init(sta);
rcu_read_lock(); rcu_read_lock();
@ -752,9 +720,6 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct sta_info *sta; struct sta_info *sta;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (mac) { if (mac) {
@ -786,9 +751,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
struct sta_info *sta; struct sta_info *sta;
struct ieee80211_sub_if_data *vlansdata; struct ieee80211_sub_if_data *vlansdata;
if (dev == local->mdev || params->vlan == local->mdev)
return -EOPNOTSUPP;
rcu_read_lock(); rcu_read_lock();
/* XXX: get sta belonging to dev */ /* XXX: get sta belonging to dev */
@ -828,9 +790,6 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
struct sta_info *sta; struct sta_info *sta;
int err; int err;
if (dev == local->mdev)
return -EOPNOTSUPP;
if (!netif_running(dev)) if (!netif_running(dev))
return -ENETDOWN; return -ENETDOWN;
@ -884,9 +843,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
struct mesh_path *mpath; struct mesh_path *mpath;
struct sta_info *sta; struct sta_info *sta;
if (dev == local->mdev)
return -EOPNOTSUPP;
if (!netif_running(dev)) if (!netif_running(dev))
return -ENETDOWN; return -ENETDOWN;
@ -958,13 +914,9 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
u8 *dst, u8 *next_hop, struct mpath_info *pinfo) u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct mesh_path *mpath; struct mesh_path *mpath;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
@ -986,13 +938,9 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *dst, u8 *next_hop, int idx, u8 *dst, u8 *next_hop,
struct mpath_info *pinfo) struct mpath_info *pinfo)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct mesh_path *mpath; struct mesh_path *mpath;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
@ -1015,13 +963,9 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
struct bss_parameters *params) struct bss_parameters *params)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
u32 changed = 0; u32 changed = 0;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type != NL80211_IFTYPE_AP) if (sdata->vif.type != NL80211_IFTYPE_AP)

View file

@ -173,8 +173,7 @@ static ssize_t sta_agg_status_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos) const char __user *user_buf, size_t count, loff_t *ppos)
{ {
struct sta_info *sta = file->private_data; struct sta_info *sta = file->private_data;
struct net_device *dev = sta->sdata->dev; struct ieee80211_local *local = sta->sdata->local;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw; struct ieee80211_hw *hw = &local->hw;
u8 *da = sta->sta.addr; u8 *da = sta->sta.addr;
static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0, static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,

View file

@ -573,6 +573,10 @@ enum {
/* maximum number of hardware queues we support. */ /* maximum number of hardware queues we support. */
#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
struct ieee80211_master_priv {
struct ieee80211_local *local;
};
struct ieee80211_local { struct ieee80211_local {
/* embed the driver visible part. /* embed the driver visible part.
* don't cast (use the static inlines below), but we keep * don't cast (use the static inlines below), but we keep
@ -720,6 +724,8 @@ struct ieee80211_local {
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
struct local_debugfsdentries { struct local_debugfsdentries {
struct dentry *rcdir;
struct dentry *rcname;
struct dentry *frequency; struct dentry *frequency;
struct dentry *antenna_sel_tx; struct dentry *antenna_sel_tx;
struct dentry *antenna_sel_rx; struct dentry *antenna_sel_rx;

View file

@ -625,6 +625,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
/* and set some type-dependent values */ /* and set some type-dependent values */
sdata->vif.type = type; sdata->vif.type = type;
sdata->dev->hard_start_xmit = ieee80211_subif_start_xmit; sdata->dev->hard_start_xmit = ieee80211_subif_start_xmit;
sdata->wdev.iftype = type;
/* only monitor differs */ /* only monitor differs */
sdata->dev->type = ARPHRD_ETHER; sdata->dev->type = ARPHRD_ETHER;

View file

@ -106,7 +106,8 @@ static const struct header_ops ieee80211_header_ops = {
static int ieee80211_master_open(struct net_device *dev) static int ieee80211_master_open(struct net_device *dev)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_master_priv *mpriv = netdev_priv(dev);
struct ieee80211_local *local = mpriv->local;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int res = -EOPNOTSUPP; int res = -EOPNOTSUPP;
@ -128,7 +129,8 @@ static int ieee80211_master_open(struct net_device *dev)
static int ieee80211_master_stop(struct net_device *dev) static int ieee80211_master_stop(struct net_device *dev)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_master_priv *mpriv = netdev_priv(dev);
struct ieee80211_local *local = mpriv->local;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
/* we hold the RTNL here so can safely walk the list */ /* we hold the RTNL here so can safely walk the list */
@ -141,7 +143,8 @@ static int ieee80211_master_stop(struct net_device *dev)
static void ieee80211_master_set_multicast_list(struct net_device *dev) static void ieee80211_master_set_multicast_list(struct net_device *dev)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_master_priv *mpriv = netdev_priv(dev);
struct ieee80211_local *local = mpriv->local;
ieee80211_configure_filter(local); ieee80211_configure_filter(local);
} }
@ -539,6 +542,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u16 frag, type; u16 frag, type;
__le16 fc; __le16 fc;
struct ieee80211_supported_band *sband;
struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_tx_status_rtap_hdr *rthdr;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct net_device *prev_dev = NULL; struct net_device *prev_dev = NULL;
@ -585,7 +589,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
sta->tx_retry_count += info->status.retry_count; sta->tx_retry_count += info->status.retry_count;
} }
rate_control_tx_status(local->mdev, skb); sband = local->hw.wiphy->bands[info->band];
rate_control_tx_status(local, sband, sta, skb);
} }
rcu_read_unlock(); rcu_read_unlock();
@ -787,7 +792,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
int result; int result;
enum ieee80211_band band; enum ieee80211_band band;
struct net_device *mdev; struct net_device *mdev;
struct wireless_dev *mwdev; struct ieee80211_master_priv *mpriv;
/* /*
* generic code guarantees at least one band, * generic code guarantees at least one band,
@ -829,16 +834,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (hw->queues < 4) if (hw->queues < 4)
hw->ampdu_queues = 0; hw->ampdu_queues = 0;
mdev = alloc_netdev_mq(sizeof(struct wireless_dev), mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
"wmaster%d", ether_setup, "wmaster%d", ether_setup,
ieee80211_num_queues(hw)); ieee80211_num_queues(hw));
if (!mdev) if (!mdev)
goto fail_mdev_alloc; goto fail_mdev_alloc;
mwdev = netdev_priv(mdev); mpriv = netdev_priv(mdev);
mdev->ieee80211_ptr = mwdev; mpriv->local = local;
mwdev->wiphy = local->hw.wiphy;
local->mdev = mdev; local->mdev = mdev;
ieee80211_rx_bss_list_init(local); ieee80211_rx_bss_list_init(local);

View file

@ -351,7 +351,7 @@ static void ieee80211_mesh_path_timer(unsigned long data)
struct ieee80211_sub_if_data *sdata = struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data; (struct ieee80211_sub_if_data *) data;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = wdev_priv(&sdata->wdev); struct ieee80211_local *local = sdata->local;
queue_work(local->hw.workqueue, &ifmsh->work); queue_work(local->hw.workqueue, &ifmsh->work);
} }

View file

@ -71,6 +71,7 @@ enum mesh_path_flags {
*/ */
struct mesh_path { struct mesh_path {
u8 dst[ETH_ALEN]; u8 dst[ETH_ALEN];
u8 mpp[ETH_ALEN]; /* used for MPP or MAP */
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct sta_info *next_hop; struct sta_info *next_hop;
struct timer_list timer; struct timer_list timer;
@ -226,6 +227,9 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
struct mesh_path *mesh_path_lookup(u8 *dst, struct mesh_path *mesh_path_lookup(u8 *dst,
struct ieee80211_sub_if_data *sdata); struct ieee80211_sub_if_data *sdata);
struct mesh_path *mpp_path_lookup(u8 *dst,
struct ieee80211_sub_if_data *sdata);
int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata);
struct mesh_path *mesh_path_lookup_by_idx(int idx, struct mesh_path *mesh_path_lookup_by_idx(int idx,
struct ieee80211_sub_if_data *sdata); struct ieee80211_sub_if_data *sdata);
void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);

View file

@ -36,6 +36,7 @@ struct mpath_node {
}; };
static struct mesh_table *mesh_paths; static struct mesh_table *mesh_paths;
static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
/* This lock will have the grow table function as writer and add / delete nodes /* This lock will have the grow table function as writer and add / delete nodes
* as readers. When reading the table (i.e. doing lookups) we are well protected * as readers. When reading the table (i.e. doing lookups) we are well protected
@ -94,6 +95,34 @@ struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
return NULL; return NULL;
} }
struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
{
struct mesh_path *mpath;
struct hlist_node *n;
struct hlist_head *bucket;
struct mesh_table *tbl;
struct mpath_node *node;
tbl = rcu_dereference(mpp_paths);
bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
hlist_for_each_entry_rcu(node, n, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
if (MPATH_EXPIRED(mpath)) {
spin_lock_bh(&mpath->state_lock);
if (MPATH_EXPIRED(mpath))
mpath->flags &= ~MESH_PATH_ACTIVE;
spin_unlock_bh(&mpath->state_lock);
}
return mpath;
}
}
return NULL;
}
/** /**
* mesh_path_lookup_by_idx - look up a path in the mesh path table by its index * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
* @idx: index * @idx: index
@ -226,6 +255,91 @@ err_path_alloc:
} }
int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
{
struct mesh_path *mpath, *new_mpath;
struct mpath_node *node, *new_node;
struct hlist_head *bucket;
struct hlist_node *n;
int grow = 0;
int err = 0;
u32 hash_idx;
if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
/* never add ourselves as neighbours */
return -ENOTSUPP;
if (is_multicast_ether_addr(dst))
return -ENOTSUPP;
err = -ENOMEM;
new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
if (!new_mpath)
goto err_path_alloc;
new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
if (!new_node)
goto err_node_alloc;
read_lock(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
memcpy(new_mpath->mpp, mpp, ETH_ALEN);
new_mpath->sdata = sdata;
new_mpath->flags = 0;
skb_queue_head_init(&new_mpath->frame_queue);
new_node->mpath = new_mpath;
new_mpath->exp_time = jiffies;
spin_lock_init(&new_mpath->state_lock);
hash_idx = mesh_table_hash(dst, sdata, mpp_paths);
bucket = &mpp_paths->hash_buckets[hash_idx];
spin_lock(&mpp_paths->hashwlock[hash_idx]);
err = -EEXIST;
hlist_for_each_entry(node, n, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
goto err_exists;
}
hlist_add_head_rcu(&new_node->list, bucket);
if (atomic_inc_return(&mpp_paths->entries) >=
mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1))
grow = 1;
spin_unlock(&mpp_paths->hashwlock[hash_idx]);
read_unlock(&pathtbl_resize_lock);
if (grow) {
struct mesh_table *oldtbl, *newtbl;
write_lock(&pathtbl_resize_lock);
oldtbl = mpp_paths;
newtbl = mesh_table_grow(mpp_paths);
if (!newtbl) {
write_unlock(&pathtbl_resize_lock);
return 0;
}
rcu_assign_pointer(mpp_paths, newtbl);
write_unlock(&pathtbl_resize_lock);
synchronize_rcu();
mesh_table_free(oldtbl, false);
}
return 0;
err_exists:
spin_unlock(&mpp_paths->hashwlock[hash_idx]);
read_unlock(&pathtbl_resize_lock);
kfree(new_node);
err_node_alloc:
kfree(new_mpath);
err_path_alloc:
return err;
}
/** /**
* mesh_plink_broken - deactivates paths and sends perr when a link breaks * mesh_plink_broken - deactivates paths and sends perr when a link breaks
* *
@ -475,11 +589,21 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
int mesh_pathtbl_init(void) int mesh_pathtbl_init(void)
{ {
mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
if (!mesh_paths)
return -ENOMEM;
mesh_paths->free_node = &mesh_path_node_free; mesh_paths->free_node = &mesh_path_node_free;
mesh_paths->copy_node = &mesh_path_node_copy; mesh_paths->copy_node = &mesh_path_node_copy;
mesh_paths->mean_chain_len = MEAN_CHAIN_LEN; mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
if (!mesh_paths)
mpp_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
if (!mpp_paths) {
mesh_table_free(mesh_paths, true);
return -ENOMEM; return -ENOMEM;
}
mpp_paths->free_node = &mesh_path_node_free;
mpp_paths->copy_node = &mesh_path_node_copy;
mpp_paths->mean_chain_len = MEAN_CHAIN_LEN;
return 0; return 0;
} }
@ -511,4 +635,5 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
void mesh_pathtbl_unregister(void) void mesh_pathtbl_unregister(void)
{ {
mesh_table_free(mesh_paths, true); mesh_table_free(mesh_paths, true);
mesh_table_free(mpp_paths, true);
} }

View file

@ -942,8 +942,8 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
disassoc = 1; disassoc = 1;
} else } else
ieee80211_send_probe_req(sdata, ifsta->bssid, ieee80211_send_probe_req(sdata, ifsta->bssid,
local->scan_ssid, ifsta->ssid,
local->scan_ssid_len); ifsta->ssid_len);
ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL;
} else { } else {
ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
@ -1323,7 +1323,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info); ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info);
} }
rate_control_rate_init(sta, local); rate_control_rate_init(sta);
if (elems.wmm_param) { if (elems.wmm_param) {
set_sta_flags(sta, WLAN_STA_WME); set_sta_flags(sta, WLAN_STA_WME);
@ -1452,6 +1452,8 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED;
mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
ieee80211_led_assoc(local, true);
memset(&wrqu, 0, sizeof(wrqu)); memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN); memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
@ -2342,7 +2344,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
sta->sta.supp_rates[band] = supp_rates | sta->sta.supp_rates[band] = supp_rates |
ieee80211_mandatory_rates(local, band); ieee80211_mandatory_rates(local, band);
rate_control_rate_init(sta, local); rate_control_rate_init(sta);
if (sta_info_insert(sta)) if (sta_info_insert(sta))
return NULL; return NULL;

View file

@ -12,6 +12,7 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include "rate.h" #include "rate.h"
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "debugfs.h"
struct rate_control_alg { struct rate_control_alg {
struct list_head list; struct list_head list;
@ -127,19 +128,46 @@ static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
module_put(ops->module); module_put(ops->module);
} }
#ifdef CONFIG_MAC80211_DEBUGFS
static ssize_t rcname_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct rate_control_ref *ref = file->private_data;
int len = strlen(ref->ops->name);
return simple_read_from_buffer(userbuf, count, ppos,
ref->ops->name, len);
}
static const struct file_operations rcname_ops = {
.read = rcname_read,
.open = mac80211_open_file_generic,
};
#endif
struct rate_control_ref *rate_control_alloc(const char *name, struct rate_control_ref *rate_control_alloc(const char *name,
struct ieee80211_local *local) struct ieee80211_local *local)
{ {
struct dentry *debugfsdir = NULL;
struct rate_control_ref *ref; struct rate_control_ref *ref;
ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
if (!ref) if (!ref)
goto fail_ref; goto fail_ref;
kref_init(&ref->kref); kref_init(&ref->kref);
ref->local = local;
ref->ops = ieee80211_rate_control_ops_get(name); ref->ops = ieee80211_rate_control_ops_get(name);
if (!ref->ops) if (!ref->ops)
goto fail_ops; goto fail_ops;
ref->priv = ref->ops->alloc(local);
#ifdef CONFIG_MAC80211_DEBUGFS
debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir);
local->debugfs.rcdir = debugfsdir;
local->debugfs.rcname = debugfs_create_file("name", 0400, debugfsdir,
ref, &rcname_ops);
#endif
ref->priv = ref->ops->alloc(&local->hw, debugfsdir);
if (!ref->priv) if (!ref->priv)
goto fail_priv; goto fail_priv;
return ref; return ref;
@ -158,29 +186,46 @@ static void rate_control_release(struct kref *kref)
ctrl_ref = container_of(kref, struct rate_control_ref, kref); ctrl_ref = container_of(kref, struct rate_control_ref, kref);
ctrl_ref->ops->free(ctrl_ref->priv); ctrl_ref->ops->free(ctrl_ref->priv);
#ifdef CONFIG_MAC80211_DEBUGFS
debugfs_remove(ctrl_ref->local->debugfs.rcname);
ctrl_ref->local->debugfs.rcname = NULL;
debugfs_remove(ctrl_ref->local->debugfs.rcdir);
ctrl_ref->local->debugfs.rcdir = NULL;
#endif
ieee80211_rate_control_ops_put(ctrl_ref->ops); ieee80211_rate_control_ops_put(ctrl_ref->ops);
kfree(ctrl_ref); kfree(ctrl_ref);
} }
void rate_control_get_rate(struct net_device *dev, void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband, struct ieee80211_supported_band *sband,
struct sk_buff *skb, struct sta_info *sta, struct sk_buff *skb,
struct rate_selection *sel) struct rate_selection *sel)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct rate_control_ref *ref = sdata->local->rate_ctrl;
struct rate_control_ref *ref = local->rate_ctrl; void *priv_sta = NULL;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_sta *ista = NULL;
struct sta_info *sta;
int i; int i;
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
sel->rate_idx = -1; sel->rate_idx = -1;
sel->nonerp_idx = -1; sel->nonerp_idx = -1;
sel->probe_idx = -1; sel->probe_idx = -1;
sel->max_rate_idx = sdata->max_ratectrl_rateidx;
ref->ops->get_rate(ref->priv, dev, sband, skb, sel); if (sta) {
ista = &sta->sta;
priv_sta = sta->rate_ctrl_priv;
}
if (sta && sdata->force_unicast_rateidx > -1)
sel->rate_idx = sdata->force_unicast_rateidx;
else
ref->ops->get_rate(ref->priv, sband, ista, priv_sta, skb, sel);
if (sdata->max_ratectrl_rateidx > -1 &&
sel->rate_idx > sdata->max_ratectrl_rateidx)
sel->rate_idx = sdata->max_ratectrl_rateidx;
BUG_ON(sel->rate_idx < 0); BUG_ON(sel->rate_idx < 0);
@ -191,13 +236,11 @@ void rate_control_get_rate(struct net_device *dev,
if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate) if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
break; break;
if (rate_supported(sta, sband->band, i) && if (rate_supported(ista, sband->band, i) &&
!(rate->flags & IEEE80211_RATE_ERP_G)) !(rate->flags & IEEE80211_RATE_ERP_G))
sel->nonerp_idx = i; sel->nonerp_idx = i;
} }
} }
rcu_read_unlock();
} }
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)

View file

@ -19,77 +19,48 @@
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "sta_info.h" #include "sta_info.h"
/**
* struct rate_selection - rate selection for rate control algos
* @rate: selected transmission rate index
* @nonerp: Non-ERP rate to use instead if ERP cannot be used
* @probe: rate for probing (or -1)
*
*/
struct rate_selection {
s8 rate_idx, nonerp_idx, probe_idx;
};
struct rate_control_ops {
struct module *module;
const char *name;
void (*tx_status)(void *priv, struct net_device *dev,
struct sk_buff *skb);
void (*get_rate)(void *priv, struct net_device *dev,
struct ieee80211_supported_band *band,
struct sk_buff *skb,
struct rate_selection *sel);
void (*rate_init)(void *priv, void *priv_sta,
struct ieee80211_local *local, struct sta_info *sta);
void (*clear)(void *priv);
void *(*alloc)(struct ieee80211_local *local);
void (*free)(void *priv);
void *(*alloc_sta)(void *priv, gfp_t gfp);
void (*free_sta)(void *priv, void *priv_sta);
int (*add_attrs)(void *priv, struct kobject *kobj);
void (*remove_attrs)(void *priv, struct kobject *kobj);
void (*add_sta_debugfs)(void *priv, void *priv_sta,
struct dentry *dir);
void (*remove_sta_debugfs)(void *priv, void *priv_sta);
};
struct rate_control_ref { struct rate_control_ref {
struct ieee80211_local *local;
struct rate_control_ops *ops; struct rate_control_ops *ops;
void *priv; void *priv;
struct kref kref; struct kref kref;
}; };
int ieee80211_rate_control_register(struct rate_control_ops *ops);
void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
/* Get a reference to the rate control algorithm. If `name' is NULL, get the /* Get a reference to the rate control algorithm. If `name' is NULL, get the
* first available algorithm. */ * first available algorithm. */
struct rate_control_ref *rate_control_alloc(const char *name, struct rate_control_ref *rate_control_alloc(const char *name,
struct ieee80211_local *local); struct ieee80211_local *local);
void rate_control_get_rate(struct net_device *dev, void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband, struct ieee80211_supported_band *sband,
struct sk_buff *skb, struct sta_info *sta, struct sk_buff *skb,
struct rate_selection *sel); struct rate_selection *sel);
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
void rate_control_put(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref);
static inline void rate_control_tx_status(struct net_device *dev, static inline void rate_control_tx_status(struct ieee80211_local *local,
struct ieee80211_supported_band *sband,
struct sta_info *sta,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct rate_control_ref *ref = local->rate_ctrl; struct rate_control_ref *ref = local->rate_ctrl;
struct ieee80211_sta *ista = &sta->sta;
void *priv_sta = sta->rate_ctrl_priv;
ref->ops->tx_status(ref->priv, dev, skb); ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
} }
static inline void rate_control_rate_init(struct sta_info *sta, static inline void rate_control_rate_init(struct sta_info *sta)
struct ieee80211_local *local)
{ {
struct ieee80211_local *local = sta->sdata->local;
struct rate_control_ref *ref = sta->rate_ctrl; struct rate_control_ref *ref = sta->rate_ctrl;
ref->ops->rate_init(ref->priv, sta->rate_ctrl_priv, local, sta); struct ieee80211_sta *ista = &sta->sta;
void *priv_sta = sta->rate_ctrl_priv;
struct ieee80211_supported_band *sband;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
} }
@ -100,15 +71,19 @@ static inline void rate_control_clear(struct ieee80211_local *local)
} }
static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
struct ieee80211_sta *sta,
gfp_t gfp) gfp_t gfp)
{ {
return ref->ops->alloc_sta(ref->priv, gfp); return ref->ops->alloc_sta(ref->priv, sta, gfp);
} }
static inline void rate_control_free_sta(struct rate_control_ref *ref, static inline void rate_control_free_sta(struct sta_info *sta)
void *priv)
{ {
ref->ops->free_sta(ref->priv, priv); struct rate_control_ref *ref = sta->rate_ctrl;
struct ieee80211_sta *ista = &sta->sta;
void *priv_sta = sta->rate_ctrl_priv;
ref->ops->free_sta(ref->priv, ista, priv_sta);
} }
static inline void rate_control_add_sta_debugfs(struct sta_info *sta) static inline void rate_control_add_sta_debugfs(struct sta_info *sta)
@ -130,31 +105,6 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
#endif #endif
} }
static inline int rate_supported(struct sta_info *sta,
enum ieee80211_band band,
int index)
{
return (sta == NULL || sta->sta.supp_rates[band] & BIT(index));
}
static inline s8
rate_lowest_index(struct ieee80211_local *local,
struct ieee80211_supported_band *sband,
struct sta_info *sta)
{
int i;
for (i = 0; i < sband->n_bitrates; i++)
if (rate_supported(sta, sband->band, i))
return i;
/* warn when we cannot find a rate. */
WARN_ON(1);
return 0;
}
/* functions for rate control related to a device */ /* functions for rate control related to a device */
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
const char *name); const char *name);

View file

@ -124,7 +124,6 @@ struct rc_pid_events_file_info {
* struct rc_pid_debugfs_entries - tunable parameters * struct rc_pid_debugfs_entries - tunable parameters
* *
* Algorithm parameters, tunable via debugfs. * Algorithm parameters, tunable via debugfs.
* @dir: the debugfs directory for a specific phy
* @target: target percentage for failed frames * @target: target percentage for failed frames
* @sampling_period: error sampling interval in milliseconds * @sampling_period: error sampling interval in milliseconds
* @coeff_p: absolute value of the proportional coefficient * @coeff_p: absolute value of the proportional coefficient
@ -143,7 +142,6 @@ struct rc_pid_events_file_info {
* ordering of rates) * ordering of rates)
*/ */
struct rc_pid_debugfs_entries { struct rc_pid_debugfs_entries {
struct dentry *dir;
struct dentry *target; struct dentry *target;
struct dentry *sampling_period; struct dentry *sampling_period;
struct dentry *coeff_p; struct dentry *coeff_p;

View file

@ -68,18 +68,14 @@
* exhibited a worse failed frames behaviour and we'll choose the highest rate * exhibited a worse failed frames behaviour and we'll choose the highest rate
* whose failed frames behaviour is not worse than the one of the original rate * whose failed frames behaviour is not worse than the one of the original rate
* target. While at it, check that the new rate is valid. */ * target. While at it, check that the new rate is valid. */
static void rate_control_pid_adjust_rate(struct ieee80211_local *local, static void rate_control_pid_adjust_rate(struct ieee80211_supported_band *sband,
struct sta_info *sta, int adj, struct ieee80211_sta *sta,
struct rc_pid_sta_info *spinfo, int adj,
struct rc_pid_rateinfo *rinfo) struct rc_pid_rateinfo *rinfo)
{ {
struct ieee80211_sub_if_data *sdata;
struct ieee80211_supported_band *sband;
int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
struct rc_pid_sta_info *spinfo = (void *)sta->rate_ctrl_priv;
int cur = spinfo->txrate_idx; int cur = spinfo->txrate_idx;
sdata = sta->sdata;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
band = sband->band; band = sband->band;
n_bitrates = sband->n_bitrates; n_bitrates = sband->n_bitrates;
@ -146,13 +142,11 @@ static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l)
} }
static void rate_control_pid_sample(struct rc_pid_info *pinfo, static void rate_control_pid_sample(struct rc_pid_info *pinfo,
struct ieee80211_local *local, struct ieee80211_supported_band *sband,
struct sta_info *sta) struct ieee80211_sta *sta,
struct rc_pid_sta_info *spinfo)
{ {
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
struct rc_pid_rateinfo *rinfo = pinfo->rinfo; struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
struct ieee80211_supported_band *sband;
u32 pf; u32 pf;
s32 err_avg; s32 err_avg;
u32 err_prop; u32 err_prop;
@ -161,9 +155,6 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
int adj, i, j, tmp; int adj, i, j, tmp;
unsigned long period; unsigned long period;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
spinfo = sta->rate_ctrl_priv;
/* In case nothing happened during the previous control interval, turn /* In case nothing happened during the previous control interval, turn
* the sharpening factor on. */ * the sharpening factor on. */
period = (HZ * pinfo->sampling_period + 500) / 1000; period = (HZ * pinfo->sampling_period + 500) / 1000;
@ -179,11 +170,15 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
if (unlikely(spinfo->tx_num_xmit == 0)) if (unlikely(spinfo->tx_num_xmit == 0))
pf = spinfo->last_pf; pf = spinfo->last_pf;
else { else {
/* XXX: BAD HACK!!! */
struct sta_info *si = container_of(sta, struct sta_info, sta);
pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
if (ieee80211_vif_is_mesh(&sdata->vif) && pf == 100)
mesh_plink_broken(sta); if (ieee80211_vif_is_mesh(&si->sdata->vif) && pf == 100)
mesh_plink_broken(si);
pf <<= RC_PID_ARITH_SHIFT; pf <<= RC_PID_ARITH_SHIFT;
sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9) si->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
>> RC_PID_ARITH_SHIFT; >> RC_PID_ARITH_SHIFT;
} }
@ -229,43 +224,25 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
/* Change rate. */ /* Change rate. */
if (adj) if (adj)
rate_control_pid_adjust_rate(local, sta, adj, rinfo); rate_control_pid_adjust_rate(sband, sta, spinfo, adj, rinfo);
} }
static void rate_control_pid_tx_status(void *priv, struct net_device *dev, static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_sub_if_data *sdata;
struct rc_pid_info *pinfo = priv; struct rc_pid_info *pinfo = priv;
struct sta_info *sta; struct rc_pid_sta_info *spinfo = priv_sta;
struct rc_pid_sta_info *spinfo;
unsigned long period; unsigned long period;
struct ieee80211_supported_band *sband;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
rcu_read_lock(); if (!spinfo)
return;
sta = sta_info_get(local, hdr->addr1);
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
if (!sta)
goto unlock;
spinfo = sta->rate_ctrl_priv;
/* Don't update the state if we're not controlling the rate. */
sdata = sta->sdata;
if (sdata->force_unicast_rateidx > -1) {
spinfo->txrate_idx = sdata->max_ratectrl_rateidx;
goto unlock;
}
/* Ignore all frames that were sent with a different rate than the rate /* Ignore all frames that were sent with a different rate than the rate
* we currently advise mac80211 to use. */ * we currently advise mac80211 to use. */
if (info->tx_rate_idx != spinfo->txrate_idx) if (info->tx_rate_idx != spinfo->txrate_idx)
goto unlock; return;
spinfo->tx_num_xmit++; spinfo->tx_num_xmit++;
@ -289,78 +266,63 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
if (!period) if (!period)
period = 1; period = 1;
if (time_after(jiffies, spinfo->last_sample + period)) if (time_after(jiffies, spinfo->last_sample + period))
rate_control_pid_sample(pinfo, local, sta); rate_control_pid_sample(pinfo, sband, sta, spinfo);
unlock:
rcu_read_unlock();
} }
static void rate_control_pid_get_rate(void *priv, struct net_device *dev, static void
struct ieee80211_supported_band *sband, rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband,
struct sk_buff *skb, struct ieee80211_sta *sta, void *priv_sta,
struct rate_selection *sel) struct sk_buff *skb,
struct rate_selection *sel)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_sub_if_data *sdata; struct rc_pid_sta_info *spinfo = priv_sta;
struct rc_pid_sta_info *spinfo;
struct sta_info *sta;
int rateidx; int rateidx;
u16 fc; u16 fc;
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest /* Send management frames and broadcast/multicast data using lowest
* rate. */ * rate. */
fc = le16_to_cpu(hdr->frame_control); fc = le16_to_cpu(hdr->frame_control);
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || if (!sta || !spinfo ||
is_multicast_ether_addr(hdr->addr1) || !sta) { (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
sel->rate_idx = rate_lowest_index(local, sband, sta); is_multicast_ether_addr(hdr->addr1)) {
rcu_read_unlock(); sel->rate_idx = rate_lowest_index(sband, sta);
return; return;
} }
/* If a forced rate is in effect, select it. */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
spinfo = (struct rc_pid_sta_info *)sta->rate_ctrl_priv;
if (sdata->force_unicast_rateidx > -1)
spinfo->txrate_idx = sdata->force_unicast_rateidx;
rateidx = spinfo->txrate_idx; rateidx = spinfo->txrate_idx;
if (rateidx >= sband->n_bitrates) if (rateidx >= sband->n_bitrates)
rateidx = sband->n_bitrates - 1; rateidx = sband->n_bitrates - 1;
rcu_read_unlock();
sel->rate_idx = rateidx; sel->rate_idx = rateidx;
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
rate_control_pid_event_tx_rate( rate_control_pid_event_tx_rate(&spinfo->events,
&((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
rateidx, sband->bitrates[rateidx].bitrate); rateidx, sband->bitrates[rateidx].bitrate);
#endif #endif
} }
static void rate_control_pid_rate_init(void *priv, void *priv_sta, static void
struct ieee80211_local *local, rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct sta_info *sta) struct ieee80211_sta *sta, void *priv_sta)
{ {
struct rc_pid_sta_info *spinfo = priv_sta;
struct sta_info *si;
/* TODO: This routine should consider using RSSI from previous packets /* TODO: This routine should consider using RSSI from previous packets
* as we need to have IEEE 802.1X auth succeed immediately after assoc.. * as we need to have IEEE 802.1X auth succeed immediately after assoc..
* Until that method is implemented, we will use the lowest supported * Until that method is implemented, we will use the lowest supported
* rate as a workaround. */ * rate as a workaround. */
struct ieee80211_supported_band *sband;
struct rc_pid_sta_info *spinfo = (void *)sta->rate_ctrl_priv;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; spinfo->txrate_idx = rate_lowest_index(sband, sta);
spinfo->txrate_idx = rate_lowest_index(local, sband, sta); /* HACK */
sta->fail_avg = 0; si = container_of(sta, struct sta_info, sta);
si->fail_avg = 0;
} }
static void *rate_control_pid_alloc(struct ieee80211_local *local) static void *rate_control_pid_alloc(struct ieee80211_hw *hw,
struct dentry *debugfsdir)
{ {
struct rc_pid_info *pinfo; struct rc_pid_info *pinfo;
struct rc_pid_rateinfo *rinfo; struct rc_pid_rateinfo *rinfo;
@ -371,7 +333,7 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
struct rc_pid_debugfs_entries *de; struct rc_pid_debugfs_entries *de;
#endif #endif
sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; sband = hw->wiphy->bands[hw->conf.channel->band];
pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC); pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC);
if (!pinfo) if (!pinfo)
@ -426,30 +388,28 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
de = &pinfo->dentries; de = &pinfo->dentries;
de->dir = debugfs_create_dir("rc80211_pid",
local->hw.wiphy->debugfsdir);
de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR, de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR,
de->dir, &pinfo->target); debugfsdir, &pinfo->target);
de->sampling_period = debugfs_create_u32("sampling_period", de->sampling_period = debugfs_create_u32("sampling_period",
S_IRUSR | S_IWUSR, de->dir, S_IRUSR | S_IWUSR, debugfsdir,
&pinfo->sampling_period); &pinfo->sampling_period);
de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR, de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR,
de->dir, &pinfo->coeff_p); debugfsdir, &pinfo->coeff_p);
de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR, de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR,
de->dir, &pinfo->coeff_i); debugfsdir, &pinfo->coeff_i);
de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR, de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR,
de->dir, &pinfo->coeff_d); debugfsdir, &pinfo->coeff_d);
de->smoothing_shift = debugfs_create_u32("smoothing_shift", de->smoothing_shift = debugfs_create_u32("smoothing_shift",
S_IRUSR | S_IWUSR, de->dir, S_IRUSR | S_IWUSR, debugfsdir,
&pinfo->smoothing_shift); &pinfo->smoothing_shift);
de->sharpen_factor = debugfs_create_u32("sharpen_factor", de->sharpen_factor = debugfs_create_u32("sharpen_factor",
S_IRUSR | S_IWUSR, de->dir, S_IRUSR | S_IWUSR, debugfsdir,
&pinfo->sharpen_factor); &pinfo->sharpen_factor);
de->sharpen_duration = debugfs_create_u32("sharpen_duration", de->sharpen_duration = debugfs_create_u32("sharpen_duration",
S_IRUSR | S_IWUSR, de->dir, S_IRUSR | S_IWUSR, debugfsdir,
&pinfo->sharpen_duration); &pinfo->sharpen_duration);
de->norm_offset = debugfs_create_u32("norm_offset", de->norm_offset = debugfs_create_u32("norm_offset",
S_IRUSR | S_IWUSR, de->dir, S_IRUSR | S_IWUSR, debugfsdir,
&pinfo->norm_offset); &pinfo->norm_offset);
#endif #endif
@ -471,7 +431,6 @@ static void rate_control_pid_free(void *priv)
debugfs_remove(de->coeff_p); debugfs_remove(de->coeff_p);
debugfs_remove(de->sampling_period); debugfs_remove(de->sampling_period);
debugfs_remove(de->target); debugfs_remove(de->target);
debugfs_remove(de->dir);
#endif #endif
kfree(pinfo->rinfo); kfree(pinfo->rinfo);
@ -482,7 +441,8 @@ static void rate_control_pid_clear(void *priv)
{ {
} }
static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp) static void *rate_control_pid_alloc_sta(void *priv, struct ieee80211_sta *sta,
gfp_t gfp)
{ {
struct rc_pid_sta_info *spinfo; struct rc_pid_sta_info *spinfo;
@ -500,10 +460,10 @@ static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp)
return spinfo; return spinfo;
} }
static void rate_control_pid_free_sta(void *priv, void *priv_sta) static void rate_control_pid_free_sta(void *priv, struct ieee80211_sta *sta,
void *priv_sta)
{ {
struct rc_pid_sta_info *spinfo = priv_sta; kfree(priv_sta);
kfree(spinfo);
} }
static struct rate_control_ops mac80211_rcpid = { static struct rate_control_ops mac80211_rcpid = {

View file

@ -650,32 +650,28 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
return result; return result;
} }
static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) static void ap_sta_ps_start(struct sta_info *sta)
{ {
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
sdata = sta->sdata;
atomic_inc(&sdata->bss->num_sta_ps); atomic_inc(&sdata->bss->num_sta_ps);
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid); sdata->dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
} }
static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) static int ap_sta_ps_end(struct sta_info *sta)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb; struct sk_buff *skb;
int sent = 0; int sent = 0;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
sdata = sta->sdata;
atomic_dec(&sdata->bss->num_sta_ps); atomic_dec(&sdata->bss->num_sta_ps);
clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
@ -685,7 +681,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n", printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid); sdata->dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
/* Send all buffered frames to the station */ /* Send all buffered frames to the station */
@ -701,7 +697,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
sent++; sent++;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d send PS frame " printk(KERN_DEBUG "%s: STA %s aid %d send PS frame "
"since STA not sleeping anymore\n", dev->name, "since STA not sleeping anymore\n", sdata->dev->name,
print_mac(mac, sta->sta.addr), sta->sta.aid); print_mac(mac, sta->sta.addr), sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
info->flags |= IEEE80211_TX_CTL_REQUEUE; info->flags |= IEEE80211_TX_CTL_REQUEUE;
@ -715,7 +711,6 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
{ {
struct sta_info *sta = rx->sta; struct sta_info *sta = rx->sta;
struct net_device *dev = rx->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
if (!sta) if (!sta)
@ -757,10 +752,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
* exchange sequence */ * exchange sequence */
if (test_sta_flags(sta, WLAN_STA_PS) && if (test_sta_flags(sta, WLAN_STA_PS) &&
!ieee80211_has_pm(hdr->frame_control)) !ieee80211_has_pm(hdr->frame_control))
rx->sent_ps_buffered += ap_sta_ps_end(dev, sta); rx->sent_ps_buffered += ap_sta_ps_end(sta);
else if (!test_sta_flags(sta, WLAN_STA_PS) && else if (!test_sta_flags(sta, WLAN_STA_PS) &&
ieee80211_has_pm(hdr->frame_control)) ieee80211_has_pm(hdr->frame_control))
ap_sta_ps_start(dev, sta); ap_sta_ps_start(sta);
} }
/* Drop data::nullfunc frames silently, since they are used only to /* Drop data::nullfunc frames silently, since they are used only to
@ -1112,10 +1107,6 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
hdrlen = ieee80211_hdrlen(hdr->frame_control); hdrlen = ieee80211_hdrlen(hdr->frame_control);
if (ieee80211_vif_is_mesh(&sdata->vif))
hdrlen += ieee80211_get_mesh_hdrlen(
(struct ieee80211s_hdr *) (skb->data + hdrlen));
/* convert IEEE 802.11 header + possible LLC headers into Ethernet /* convert IEEE 802.11 header + possible LLC headers into Ethernet
* header * header
* IEEE 802.11 address fields: * IEEE 802.11 address fields:
@ -1139,6 +1130,15 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS && if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
return -1; return -1;
if (ieee80211_vif_is_mesh(&sdata->vif)) {
struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *)
(skb->data + hdrlen);
hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
memcpy(dst, meshdr->eaddr1, ETH_ALEN);
memcpy(src, meshdr->eaddr2, ETH_ALEN);
}
}
break; break;
case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS): case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
if (sdata->vif.type != NL80211_IFTYPE_STATION || if (sdata->vif.type != NL80211_IFTYPE_STATION ||
@ -1398,6 +1398,25 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
/* illegal frame */ /* illegal frame */
return RX_DROP_MONITOR; return RX_DROP_MONITOR;
if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
struct ieee80211_sub_if_data *sdata;
struct mesh_path *mppath;
sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
rcu_read_lock();
mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
if (!mppath) {
mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata);
} else {
spin_lock_bh(&mppath->state_lock);
mppath->exp_time = jiffies;
if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0)
memcpy(mppath->mpp, hdr->addr4, ETH_ALEN);
spin_unlock_bh(&mppath->state_lock);
}
rcu_read_unlock();
}
if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
return RX_CONTINUE; return RX_CONTINUE;
@ -1538,7 +1557,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
*/ */
if (sdata->vif.type != NL80211_IFTYPE_STATION && if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_ADHOC) sdata->vif.type != NL80211_IFTYPE_ADHOC)
return RX_DROP_MONITOR; return RX_CONTINUE;
switch (mgmt->u.action.category) { switch (mgmt->u.action.category) {
case WLAN_CATEGORY_BACK: case WLAN_CATEGORY_BACK:

View file

@ -93,8 +93,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
} }
/* protected by RCU */ /* protected by RCU */
static struct sta_info *__sta_info_find(struct ieee80211_local *local, struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr)
const u8 *addr)
{ {
struct sta_info *sta; struct sta_info *sta;
@ -107,12 +106,6 @@ static struct sta_info *__sta_info_find(struct ieee80211_local *local,
return sta; return sta;
} }
struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
{
return __sta_info_find(local, addr);
}
EXPORT_SYMBOL(sta_info_get);
struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
struct net_device *dev) struct net_device *dev)
{ {
@ -146,7 +139,7 @@ static void __sta_info_free(struct ieee80211_local *local,
{ {
DECLARE_MAC_BUF(mbuf); DECLARE_MAC_BUF(mbuf);
rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_free_sta(sta);
rate_control_put(sta->rate_ctrl); rate_control_put(sta->rate_ctrl);
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@ -244,7 +237,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->rate_ctrl = rate_control_get(local->rate_ctrl); sta->rate_ctrl = rate_control_get(local->rate_ctrl);
sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
gfp); &sta->sta, gfp);
if (!sta->rate_ctrl_priv) { if (!sta->rate_ctrl_priv) {
rate_control_put(sta->rate_ctrl); rate_control_put(sta->rate_ctrl);
kfree(sta); kfree(sta);
@ -308,7 +301,7 @@ int sta_info_insert(struct sta_info *sta)
spin_lock_irqsave(&local->sta_lock, flags); spin_lock_irqsave(&local->sta_lock, flags);
/* check if STA exists already */ /* check if STA exists already */
if (__sta_info_find(local, sta->sta.addr)) { if (sta_info_get(local, sta->sta.addr)) {
spin_unlock_irqrestore(&local->sta_lock, flags); spin_unlock_irqrestore(&local->sta_lock, flags);
err = -EEXIST; err = -EEXIST;
goto out_free; goto out_free;
@ -834,7 +827,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
const u8 *addr) const u8 *addr)
{ {
struct sta_info *sta = __sta_info_find(hw_to_local(hw), addr); struct sta_info *sta = sta_info_get(hw_to_local(hw), addr);
if (!sta) if (!sta)
return NULL; return NULL;

View file

@ -416,7 +416,7 @@ static inline u32 get_sta_flags(struct sta_info *sta)
/* /*
* Get a STA info, must have be under RCU read lock. * Get a STA info, must have be under RCU read lock.
*/ */
struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr); struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr);
/* /*
* Get STA info by index, BROKEN! * Get STA info by index, BROKEN!
*/ */

View file

@ -165,11 +165,10 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
return cpu_to_le16(dur); return cpu_to_le16(dur);
} }
static int inline is_ieee80211_device(struct net_device *dev, static int inline is_ieee80211_device(struct ieee80211_local *local,
struct net_device *master) struct net_device *dev)
{ {
return (wdev_priv(dev->ieee80211_ptr) == return local == wdev_priv(dev->ieee80211_ptr);
wdev_priv(master->ieee80211_ptr));
} }
/* tx handlers */ /* tx handlers */
@ -447,7 +446,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
sband = tx->local->hw.wiphy->bands[tx->channel->band]; sband = tx->local->hw.wiphy->bands[tx->channel->band];
if (likely(tx->rate_idx < 0)) { if (likely(tx->rate_idx < 0)) {
rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); rate_control_get_rate(tx->sdata, sband, tx->sta,
tx->skb, &rsel);
if (tx->sta) if (tx->sta)
tx->sta->last_txrate_idx = rsel.rate_idx; tx->sta->last_txrate_idx = rsel.rate_idx;
tx->rate_idx = rsel.rate_idx; tx->rate_idx = rsel.rate_idx;
@ -1001,14 +1001,14 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
/* /*
* NB: @tx is uninitialised when passed in here * NB: @tx is uninitialised when passed in here
*/ */
static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, static int ieee80211_tx_prepare(struct ieee80211_local *local,
struct sk_buff *skb, struct ieee80211_tx_data *tx,
struct net_device *mdev) struct sk_buff *skb)
{ {
struct net_device *dev; struct net_device *dev;
dev = dev_get_by_index(&init_net, skb->iif); dev = dev_get_by_index(&init_net, skb->iif);
if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { if (unlikely(dev && !is_ieee80211_device(local, dev))) {
dev_put(dev); dev_put(dev);
dev = NULL; dev = NULL;
} }
@ -1258,6 +1258,8 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
int ieee80211_master_start_xmit(struct sk_buff *skb, int ieee80211_master_start_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
struct ieee80211_master_priv *mpriv = netdev_priv(dev);
struct ieee80211_local *local = mpriv->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct net_device *odev = NULL; struct net_device *odev = NULL;
@ -1273,7 +1275,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
if (skb->iif) if (skb->iif)
odev = dev_get_by_index(&init_net, skb->iif); odev = dev_get_by_index(&init_net, skb->iif);
if (unlikely(odev && !is_ieee80211_device(odev, dev))) { if (unlikely(odev && !is_ieee80211_device(local, odev))) {
dev_put(odev); dev_put(odev);
odev = NULL; odev = NULL;
} }
@ -1449,8 +1451,8 @@ fail:
int ieee80211_subif_start_xmit(struct sk_buff *skb, int ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = sdata->local;
int ret = 1, head_need; int ret = 1, head_need;
u16 ethertype, hdrlen, meshhdrlen = 0; u16 ethertype, hdrlen, meshhdrlen = 0;
__le16 fc; __le16 fc;
@ -1462,7 +1464,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
struct sta_info *sta; struct sta_info *sta;
u32 sta_flags = 0; u32 sta_flags = 0;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (unlikely(skb->len < ETH_HLEN)) { if (unlikely(skb->len < ETH_HLEN)) {
ret = 0; ret = 0;
goto fail; goto fail;
@ -1498,18 +1499,50 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
#ifdef CONFIG_MAC80211_MESH #ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
/* RA TA DA SA */
memset(hdr.addr1, 0, ETH_ALEN);
memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
memcpy(hdr.addr3, skb->data, ETH_ALEN);
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
/* Do not send frames with mesh_ttl == 0 */ /* Do not send frames with mesh_ttl == 0 */
sdata->u.mesh.mshstats.dropped_frames_ttl++; sdata->u.mesh.mshstats.dropped_frames_ttl++;
ret = 0; ret = 0;
goto fail; goto fail;
} }
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata); memset(&mesh_hdr, 0, sizeof(mesh_hdr));
if (compare_ether_addr(dev->dev_addr,
skb->data + ETH_ALEN) == 0) {
/* RA TA DA SA */
memset(hdr.addr1, 0, ETH_ALEN);
memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
memcpy(hdr.addr3, skb->data, ETH_ALEN);
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
} else {
/* packet from other interface */
struct mesh_path *mppath;
memset(hdr.addr1, 0, ETH_ALEN);
memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN);
if (is_multicast_ether_addr(skb->data))
memcpy(hdr.addr3, skb->data, ETH_ALEN);
else {
rcu_read_lock();
mppath = mpp_path_lookup(skb->data, sdata);
if (mppath)
memcpy(hdr.addr3, mppath->mpp, ETH_ALEN);
else
memset(hdr.addr3, 0xff, ETH_ALEN);
rcu_read_unlock();
}
mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6;
mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum);
memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN);
memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN);
sdata->u.mesh.mesh_seqnum++;
meshhdrlen = 18;
}
hdrlen = 30; hdrlen = 30;
break; break;
#endif #endif
@ -1923,7 +1956,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
skb->do_not_encrypt = 1; skb->do_not_encrypt = 1;
info->band = band; info->band = band;
rate_control_get_rate(local->mdev, sband, skb, &rsel); rate_control_get_rate(sdata, sband, NULL, skb, &rsel);
if (unlikely(rsel.rate_idx < 0)) { if (unlikely(rsel.rate_idx < 0)) {
if (net_ratelimit()) { if (net_ratelimit()) {
@ -2032,7 +2065,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
cpu_to_le16(IEEE80211_FCTL_MOREDATA); cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} }
if (!ieee80211_tx_prepare(&tx, skb, local->mdev)) if (!ieee80211_tx_prepare(local, &tx, skb))
break; break;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }

View file

@ -29,113 +29,11 @@ MODULE_AUTHOR("Johannes Berg");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("wireless configuration support"); MODULE_DESCRIPTION("wireless configuration support");
struct list_head regulatory_requests;
/* Central wireless core regulatory domains, we only need two,
* the current one and a world regulatory domain in case we have no
* information to give us an alpha2 */
struct ieee80211_regdomain *cfg80211_regdomain;
/* We keep a static world regulatory domain in case of the absence of CRDA */
const struct ieee80211_regdomain world_regdom = {
.n_reg_rules = 1,
.alpha2 = "00",
.reg_rules = {
REG_RULE(2402, 2472, 40, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
}
};
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
/* All this fucking static junk will be removed soon, so
* don't fucking count on it !@#$ */
static char *ieee80211_regdom = "US";
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
/* We assume 40 MHz bandwidth for the old regulatory work.
* We make emphasis we are using the exact same frequencies
* as before */
const struct ieee80211_regdomain us_regdom = {
.n_reg_rules = 6,
.alpha2 = "US",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..11 */
REG_RULE(2412-20, 2462+20, 40, 6, 27, 0),
/* IEEE 802.11a, channel 36 */
REG_RULE(5180-20, 5180+20, 40, 6, 23, 0),
/* IEEE 802.11a, channel 40 */
REG_RULE(5200-20, 5200+20, 40, 6, 23, 0),
/* IEEE 802.11a, channel 44 */
REG_RULE(5220-20, 5220+20, 40, 6, 23, 0),
/* IEEE 802.11a, channels 48..64 */
REG_RULE(5240-20, 5320+20, 40, 6, 23, 0),
/* IEEE 802.11a, channels 149..165, outdoor */
REG_RULE(5745-20, 5825+20, 40, 6, 30, 0),
}
};
const struct ieee80211_regdomain jp_regdom = {
.n_reg_rules = 3,
.alpha2 = "JP",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..14 */
REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
/* IEEE 802.11a, channels 34..48 */
REG_RULE(5170-20, 5240+20, 40, 6, 20,
NL80211_RRF_PASSIVE_SCAN),
/* IEEE 802.11a, channels 52..64 */
REG_RULE(5260-20, 5320+20, 40, 6, 20,
NL80211_RRF_NO_IBSS |
NL80211_RRF_DFS),
}
};
const struct ieee80211_regdomain eu_regdom = {
.n_reg_rules = 6,
/* This alpha2 is bogus, we leave it here just for stupid
* backward compatibility */
.alpha2 = "EU",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..13 */
REG_RULE(2412-20, 2472+20, 40, 6, 20, 0),
/* IEEE 802.11a, channel 36 */
REG_RULE(5180-20, 5180+20, 40, 6, 23,
NL80211_RRF_PASSIVE_SCAN),
/* IEEE 802.11a, channel 40 */
REG_RULE(5200-20, 5200+20, 40, 6, 23,
NL80211_RRF_PASSIVE_SCAN),
/* IEEE 802.11a, channel 44 */
REG_RULE(5220-20, 5220+20, 40, 6, 23,
NL80211_RRF_PASSIVE_SCAN),
/* IEEE 802.11a, channels 48..64 */
REG_RULE(5240-20, 5320+20, 40, 6, 20,
NL80211_RRF_NO_IBSS |
NL80211_RRF_DFS),
/* IEEE 802.11a, channels 100..140 */
REG_RULE(5500-20, 5700+20, 40, 6, 30,
NL80211_RRF_NO_IBSS |
NL80211_RRF_DFS),
}
};
#endif
struct ieee80211_regdomain *cfg80211_world_regdom =
(struct ieee80211_regdomain *) &world_regdom;
LIST_HEAD(regulatory_requests);
DEFINE_MUTEX(cfg80211_reg_mutex);
/* RCU might be appropriate here since we usually /* RCU might be appropriate here since we usually
* only read the list, and that can happen quite * only read the list, and that can happen quite
* often because we need to do it for each command */ * often because we need to do it for each command */
LIST_HEAD(cfg80211_drv_list); LIST_HEAD(cfg80211_drv_list);
DEFINE_MUTEX(cfg80211_drv_mutex); DEFINE_MUTEX(cfg80211_drv_mutex);
static int wiphy_counter;
/* for debugfs */ /* for debugfs */
static struct dentry *ieee80211_debugfs_dir; static struct dentry *ieee80211_debugfs_dir;
@ -307,6 +205,8 @@ out_unlock:
struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
{ {
static int wiphy_counter;
struct cfg80211_registered_device *drv; struct cfg80211_registered_device *drv;
int alloc_size; int alloc_size;
@ -323,21 +223,18 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
mutex_lock(&cfg80211_drv_mutex); mutex_lock(&cfg80211_drv_mutex);
drv->idx = wiphy_counter; drv->idx = wiphy_counter++;
/* now increase counter for the next device unless
* it has wrapped previously */
if (wiphy_counter >= 0)
wiphy_counter++;
mutex_unlock(&cfg80211_drv_mutex);
if (unlikely(drv->idx < 0)) { if (unlikely(drv->idx < 0)) {
wiphy_counter--;
mutex_unlock(&cfg80211_drv_mutex);
/* ugh, wrapped! */ /* ugh, wrapped! */
kfree(drv); kfree(drv);
return NULL; return NULL;
} }
mutex_unlock(&cfg80211_drv_mutex);
/* give it a proper name */ /* give it a proper name */
snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE, snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE,
PHY_NAME "%d", drv->idx); PHY_NAME "%d", drv->idx);
@ -485,6 +382,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
WARN_ON(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_UNSPECIFIED);
switch (state) { switch (state) {
case NETDEV_REGISTER: case NETDEV_REGISTER:
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
@ -514,34 +413,10 @@ static struct notifier_block cfg80211_netdev_notifier = {
.notifier_call = cfg80211_netdev_notifier_call, .notifier_call = cfg80211_netdev_notifier_call,
}; };
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
const struct ieee80211_regdomain *static_regdom(char *alpha2)
{
if (alpha2[0] == 'U' && alpha2[1] == 'S')
return &us_regdom;
if (alpha2[0] == 'J' && alpha2[1] == 'P')
return &jp_regdom;
if (alpha2[0] == 'E' && alpha2[1] == 'U')
return &eu_regdom;
/* Default, as per the old rules */
return &us_regdom;
}
#endif
static int cfg80211_init(void) static int cfg80211_init(void)
{ {
int err; int err;
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
cfg80211_regdomain =
(struct ieee80211_regdomain *) static_regdom(ieee80211_regdom);
/* Used during reset_regdomains_static() */
cfg80211_world_regdom = cfg80211_regdomain;
#else
cfg80211_regdomain =
(struct ieee80211_regdomain *) cfg80211_world_regdom;
#endif
err = wiphy_sysfs_init(); err = wiphy_sysfs_init();
if (err) if (err)
goto out_fail_sysfs; goto out_fail_sysfs;
@ -560,25 +435,6 @@ static int cfg80211_init(void)
if (err) if (err)
goto out_fail_reg; goto out_fail_reg;
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
printk(KERN_INFO "cfg80211: Using old static regulatory domain:\n");
print_regdomain_info(cfg80211_regdomain);
/* The old code still requests for a new regdomain and if
* you have CRDA you get it updated, otherwise you get
* stuck with the static values. We ignore "EU" code as
* that is not a valid ISO / IEC 3166 alpha2 */
if (ieee80211_regdom[0] != 'E' &&
ieee80211_regdom[1] != 'U')
err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
ieee80211_regdom, NULL);
#else
err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL);
if (err)
printk(KERN_ERR "cfg80211: calling CRDA failed - "
"unable to update world regulatory domain, "
"using static definition\n");
#endif
return 0; return 0;
out_fail_reg: out_fail_reg:

View file

@ -299,7 +299,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
/* TODO: interface type */ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype);
return genlmsg_end(msg, hdr); return genlmsg_end(msg, hdr);
nla_put_failure: nla_put_failure:
@ -418,41 +418,56 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
int err, ifindex; int err, ifindex;
enum nl80211_iftype type; enum nl80211_iftype type;
struct net_device *dev; struct net_device *dev;
u32 flags; u32 _flags, *flags = NULL;
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
if (info->attrs[NL80211_ATTR_IFTYPE]) {
type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
if (type > NL80211_IFTYPE_MAX)
return -EINVAL;
} else
return -EINVAL;
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; return err;
ifindex = dev->ifindex; ifindex = dev->ifindex;
type = dev->ieee80211_ptr->iftype;
dev_put(dev); dev_put(dev);
err = -EINVAL;
if (info->attrs[NL80211_ATTR_IFTYPE]) {
type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
if (type > NL80211_IFTYPE_MAX)
goto unlock;
}
if (!drv->ops->change_virtual_intf || if (!drv->ops->change_virtual_intf ||
!(drv->wiphy.interface_modes & (1 << type))) { !(drv->wiphy.interface_modes & (1 << type))) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unlock; goto unlock;
} }
if (type == NL80211_IFTYPE_MESH_POINT && if (info->attrs[NL80211_ATTR_MESH_ID]) {
info->attrs[NL80211_ATTR_MESH_ID]) { if (type != NL80211_IFTYPE_MESH_POINT) {
err = -EINVAL;
goto unlock;
}
params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
} }
if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
if (type != NL80211_IFTYPE_MONITOR) {
err = -EINVAL;
goto unlock;
}
err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
&_flags);
if (!err)
flags = &_flags;
}
rtnl_lock(); rtnl_lock();
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
type, err ? NULL : &flags, &params); type, flags, &params);
dev = __dev_get_by_index(&init_net, ifindex);
WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type));
rtnl_unlock(); rtnl_unlock();
unlock: unlock:

View file

@ -42,6 +42,18 @@
#include "core.h" #include "core.h"
#include "reg.h" #include "reg.h"
/* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */
struct regulatory_request {
struct list_head list;
struct wiphy *wiphy;
int granted;
enum reg_set_by initiator;
char alpha2[2];
};
static LIST_HEAD(regulatory_requests);
DEFINE_MUTEX(cfg80211_reg_mutex);
/* To trigger userspace events */ /* To trigger userspace events */
static struct platform_device *reg_pdev; static struct platform_device *reg_pdev;
@ -51,7 +63,156 @@ static u32 supported_bandwidths[] = {
MHZ_TO_KHZ(20), MHZ_TO_KHZ(20),
}; };
bool is_world_regdom(char *alpha2) static struct list_head regulatory_requests;
/* Central wireless core regulatory domains, we only need two,
* the current one and a world regulatory domain in case we have no
* information to give us an alpha2 */
static const struct ieee80211_regdomain *cfg80211_regdomain;
/* We keep a static world regulatory domain in case of the absence of CRDA */
static const struct ieee80211_regdomain world_regdom = {
.n_reg_rules = 1,
.alpha2 = "00",
.reg_rules = {
REG_RULE(2412-10, 2462+10, 40, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
}
};
static const struct ieee80211_regdomain *cfg80211_world_regdom =
&world_regdom;
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
static char *ieee80211_regdom = "US";
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
/* We assume 40 MHz bandwidth for the old regulatory work.
* We make emphasis we are using the exact same frequencies
* as before */
static const struct ieee80211_regdomain us_regdom = {
.n_reg_rules = 6,
.alpha2 = "US",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..11 */
REG_RULE(2412-10, 2462+10, 40, 6, 27, 0),
/* IEEE 802.11a, channel 36 */
REG_RULE(5180-10, 5180+10, 40, 6, 23, 0),
/* IEEE 802.11a, channel 40 */
REG_RULE(5200-10, 5200+10, 40, 6, 23, 0),
/* IEEE 802.11a, channel 44 */
REG_RULE(5220-10, 5220+10, 40, 6, 23, 0),
/* IEEE 802.11a, channels 48..64 */
REG_RULE(5240-10, 5320+10, 40, 6, 23, 0),
/* IEEE 802.11a, channels 149..165, outdoor */
REG_RULE(5745-10, 5825+10, 40, 6, 30, 0),
}
};
static const struct ieee80211_regdomain jp_regdom = {
.n_reg_rules = 3,
.alpha2 = "JP",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..14 */
REG_RULE(2412-10, 2484+10, 40, 6, 20, 0),
/* IEEE 802.11a, channels 34..48 */
REG_RULE(5170-10, 5240+10, 40, 6, 20,
NL80211_RRF_PASSIVE_SCAN),
/* IEEE 802.11a, channels 52..64 */
REG_RULE(5260-10, 5320+10, 40, 6, 20,
NL80211_RRF_NO_IBSS |
NL80211_RRF_DFS),
}
};
static const struct ieee80211_regdomain eu_regdom = {
.n_reg_rules = 6,
/* This alpha2 is bogus, we leave it here just for stupid
* backward compatibility */
.alpha2 = "EU",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..13 */
REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
/* IEEE 802.11a, channel 36 */
REG_RULE(5180-10, 5180+10, 40, 6, 23,
NL80211_RRF_PASSIVE_SCAN),
/* IEEE 802.11a, channel 40 */
REG_RULE(5200-10, 5200+10, 40, 6, 23,
NL80211_RRF_PASSIVE_SCAN),
/* IEEE 802.11a, channel 44 */
REG_RULE(5220-10, 5220+10, 40, 6, 23,
NL80211_RRF_PASSIVE_SCAN),
/* IEEE 802.11a, channels 48..64 */
REG_RULE(5240-10, 5320+10, 40, 6, 20,
NL80211_RRF_NO_IBSS |
NL80211_RRF_DFS),
/* IEEE 802.11a, channels 100..140 */
REG_RULE(5500-10, 5700+10, 40, 6, 30,
NL80211_RRF_NO_IBSS |
NL80211_RRF_DFS),
}
};
static const struct ieee80211_regdomain *static_regdom(char *alpha2)
{
if (alpha2[0] == 'U' && alpha2[1] == 'S')
return &us_regdom;
if (alpha2[0] == 'J' && alpha2[1] == 'P')
return &jp_regdom;
if (alpha2[0] == 'E' && alpha2[1] == 'U')
return &eu_regdom;
/* Default, as per the old rules */
return &us_regdom;
}
static bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
{
if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom)
return true;
return false;
}
#else
static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
{
return false;
}
#endif
static void reset_regdomains(void)
{
/* avoid freeing static information or freeing something twice */
if (cfg80211_regdomain == cfg80211_world_regdom)
cfg80211_regdomain = NULL;
if (cfg80211_world_regdom == &world_regdom)
cfg80211_world_regdom = NULL;
if (cfg80211_regdomain == &world_regdom)
cfg80211_regdomain = NULL;
if (is_old_static_regdom(cfg80211_regdomain))
cfg80211_regdomain = NULL;
kfree(cfg80211_regdomain);
kfree(cfg80211_world_regdom);
cfg80211_world_regdom = &world_regdom;
cfg80211_regdomain = NULL;
}
/* Dynamic world regulatory domain requested by the wireless
* core upon initialization */
static void update_world_regdomain(const struct ieee80211_regdomain *rd)
{
BUG_ON(list_empty(&regulatory_requests));
reset_regdomains();
cfg80211_world_regdom = rd;
cfg80211_regdomain = rd;
}
bool is_world_regdom(const char *alpha2)
{ {
if (!alpha2) if (!alpha2)
return false; return false;
@ -60,7 +221,7 @@ bool is_world_regdom(char *alpha2)
return false; return false;
} }
static bool is_alpha2_set(char *alpha2) static bool is_alpha2_set(const char *alpha2)
{ {
if (!alpha2) if (!alpha2)
return false; return false;
@ -77,7 +238,7 @@ static bool is_alpha_upper(char letter)
return false; return false;
} }
static bool is_unknown_alpha2(char *alpha2) static bool is_unknown_alpha2(const char *alpha2)
{ {
if (!alpha2) if (!alpha2)
return false; return false;
@ -88,7 +249,7 @@ static bool is_unknown_alpha2(char *alpha2)
return false; return false;
} }
static bool is_an_alpha2(char *alpha2) static bool is_an_alpha2(const char *alpha2)
{ {
if (!alpha2) if (!alpha2)
return false; return false;
@ -97,7 +258,7 @@ static bool is_an_alpha2(char *alpha2)
return false; return false;
} }
static bool alpha2_equal(char *alpha2_x, char *alpha2_y) static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y)
{ {
if (!alpha2_x || !alpha2_y) if (!alpha2_x || !alpha2_y)
return false; return false;
@ -107,7 +268,7 @@ static bool alpha2_equal(char *alpha2_x, char *alpha2_y)
return false; return false;
} }
static bool regdom_changed(char *alpha2) static bool regdom_changed(const char *alpha2)
{ {
if (!cfg80211_regdomain) if (!cfg80211_regdomain)
return true; return true;
@ -130,12 +291,8 @@ static int call_crda(const char *alpha2)
printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n", printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n",
alpha2[0], alpha2[1]); alpha2[0], alpha2[1]);
else else
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
return -EINVAL;
#else
printk(KERN_INFO "cfg80211: Calling CRDA to update world " printk(KERN_INFO "cfg80211: Calling CRDA to update world "
"regulatory domain\n"); "regulatory domain\n");
#endif
country_env[8] = alpha2[0]; country_env[8] = alpha2[0];
country_env[9] = alpha2[1]; country_env[9] = alpha2[1];
@ -238,7 +395,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
} }
} }
static bool __reg_is_valid_request(char *alpha2, static bool __reg_is_valid_request(const char *alpha2,
struct regulatory_request **request) struct regulatory_request **request)
{ {
struct regulatory_request *req; struct regulatory_request *req;
@ -254,16 +411,16 @@ static bool __reg_is_valid_request(char *alpha2,
} }
/* Used by nl80211 before kmalloc'ing our regulatory domain */ /* Used by nl80211 before kmalloc'ing our regulatory domain */
bool reg_is_valid_request(char *alpha2) bool reg_is_valid_request(const char *alpha2)
{ {
struct regulatory_request *request = NULL; struct regulatory_request *request = NULL;
return __reg_is_valid_request(alpha2, &request); return __reg_is_valid_request(alpha2, &request);
} }
/* Sanity check on a regulatory rule */ /* Sanity check on a regulatory rule */
static bool is_valid_reg_rule(struct ieee80211_reg_rule *rule) static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
{ {
struct ieee80211_freq_range *freq_range = &rule->freq_range; const struct ieee80211_freq_range *freq_range = &rule->freq_range;
u32 freq_diff; u32 freq_diff;
if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0) if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
@ -280,9 +437,9 @@ static bool is_valid_reg_rule(struct ieee80211_reg_rule *rule)
return true; return true;
} }
static bool is_valid_rd(struct ieee80211_regdomain *rd) static bool is_valid_rd(const struct ieee80211_regdomain *rd)
{ {
struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_reg_rule *reg_rule = NULL;
unsigned int i; unsigned int i;
if (!rd->n_reg_rules) if (!rd->n_reg_rules)
@ -494,12 +651,12 @@ unlock_and_exit:
EXPORT_SYMBOL(regulatory_hint); EXPORT_SYMBOL(regulatory_hint);
static void print_rd_rules(struct ieee80211_regdomain *rd) static void print_rd_rules(const struct ieee80211_regdomain *rd)
{ {
unsigned int i; unsigned int i;
struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_reg_rule *reg_rule = NULL;
struct ieee80211_freq_range *freq_range = NULL; const struct ieee80211_freq_range *freq_range = NULL;
struct ieee80211_power_rule *power_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL;
printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), " printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), "
"(max_antenna_gain, max_eirp)\n"); "(max_antenna_gain, max_eirp)\n");
@ -529,7 +686,7 @@ static void print_rd_rules(struct ieee80211_regdomain *rd)
} }
} }
static void print_regdomain(struct ieee80211_regdomain *rd) static void print_regdomain(const struct ieee80211_regdomain *rd)
{ {
if (is_world_regdom(rd->alpha2)) if (is_world_regdom(rd->alpha2))
@ -548,85 +705,25 @@ static void print_regdomain(struct ieee80211_regdomain *rd)
print_rd_rules(rd); print_rd_rules(rd);
} }
void print_regdomain_info(struct ieee80211_regdomain *rd) void print_regdomain_info(const struct ieee80211_regdomain *rd)
{ {
printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n",
rd->alpha2[0], rd->alpha2[1]); rd->alpha2[0], rd->alpha2[1]);
print_rd_rules(rd); print_rd_rules(rd);
} }
#ifdef CONFIG_WIRELESS_OLD_REGULATORY static int __set_regdom(const struct ieee80211_regdomain *rd)
static bool is_old_static_regdom(struct ieee80211_regdomain *rd)
{
if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom)
return true;
return false;
}
/* The old crap never deals with a world regulatory domain, it only
* deals with the static regulatory domain passed and if possible
* an updated "US" or "JP" regulatory domain. We do however store the
* old static regulatory domain in cfg80211_world_regdom for convenience
* of use here */
static void reset_regdomains_static(void)
{
if (!is_old_static_regdom(cfg80211_regdomain))
kfree(cfg80211_regdomain);
/* This is setting the regdom to the old static regdom */
cfg80211_regdomain =
(struct ieee80211_regdomain *) cfg80211_world_regdom;
}
#else
static void reset_regdomains(void)
{
if (cfg80211_world_regdom && cfg80211_world_regdom != &world_regdom) {
if (cfg80211_world_regdom == cfg80211_regdomain) {
kfree(cfg80211_regdomain);
} else {
kfree(cfg80211_world_regdom);
kfree(cfg80211_regdomain);
}
} else if (cfg80211_regdomain && cfg80211_regdomain != &world_regdom)
kfree(cfg80211_regdomain);
cfg80211_world_regdom = (struct ieee80211_regdomain *) &world_regdom;
cfg80211_regdomain = NULL;
}
/* Dynamic world regulatory domain requested by the wireless
* core upon initialization */
static void update_world_regdomain(struct ieee80211_regdomain *rd)
{
BUG_ON(list_empty(&regulatory_requests));
reset_regdomains();
cfg80211_world_regdom = rd;
cfg80211_regdomain = rd;
}
#endif
static int __set_regdom(struct ieee80211_regdomain *rd)
{ {
struct regulatory_request *request = NULL; struct regulatory_request *request = NULL;
/* Some basic sanity checks first */ /* Some basic sanity checks first */
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
/* We ignore the world regdom with the old static regdomains setup
* as there is no point to it with satic regulatory definitions :(
* Don't worry this shit will be removed soon... */
if (is_world_regdom(rd->alpha2))
return -EINVAL;
#else
if (is_world_regdom(rd->alpha2)) { if (is_world_regdom(rd->alpha2)) {
if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
return -EINVAL; return -EINVAL;
update_world_regdomain(rd); update_world_regdomain(rd);
return 0; return 0;
} }
#endif
if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
!is_unknown_alpha2(rd->alpha2)) !is_unknown_alpha2(rd->alpha2))
@ -635,15 +732,10 @@ static int __set_regdom(struct ieee80211_regdomain *rd)
if (list_empty(&regulatory_requests)) if (list_empty(&regulatory_requests))
return -EINVAL; return -EINVAL;
#ifdef CONFIG_WIRELESS_OLD_REGULATORY /* allow overriding the static definitions if CRDA is present */
/* Static "US" and "JP" will be overridden, but just once */
if (!is_old_static_regdom(cfg80211_regdomain) && if (!is_old_static_regdom(cfg80211_regdomain) &&
!regdom_changed(rd->alpha2)) !regdom_changed(rd->alpha2))
return -EINVAL; return -EINVAL;
#else
if (!regdom_changed(rd->alpha2))
return -EINVAL;
#endif
/* Now lets set the regulatory domain, update all driver channels /* Now lets set the regulatory domain, update all driver channels
* and finally inform them of what we have done, in case they want * and finally inform them of what we have done, in case they want
@ -653,11 +745,7 @@ static int __set_regdom(struct ieee80211_regdomain *rd)
if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
return -EINVAL; return -EINVAL;
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
reset_regdomains_static();
#else
reset_regdomains(); reset_regdomains();
#endif
/* Country IE parsing coming soon */ /* Country IE parsing coming soon */
switch (request->initiator) { switch (request->initiator) {
@ -689,7 +777,7 @@ static int __set_regdom(struct ieee80211_regdomain *rd)
* multiple drivers can be ironed out later. Caller must've already * multiple drivers can be ironed out later. Caller must've already
* kmalloc'd the rd structure. If this calls fails you should kfree() * kmalloc'd the rd structure. If this calls fails you should kfree()
* the passed rd. Caller must hold cfg80211_drv_mutex */ * the passed rd. Caller must hold cfg80211_drv_mutex */
int set_regdom(struct ieee80211_regdomain *rd) int set_regdom(const struct ieee80211_regdomain *rd)
{ {
struct regulatory_request *this_request = NULL, *prev_request = NULL; struct regulatory_request *this_request = NULL, *prev_request = NULL;
int r; int r;
@ -735,25 +823,50 @@ int set_regdom(struct ieee80211_regdomain *rd)
int regulatory_init(void) int regulatory_init(void)
{ {
int err;
reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
if (IS_ERR(reg_pdev)) if (IS_ERR(reg_pdev))
return PTR_ERR(reg_pdev); return PTR_ERR(reg_pdev);
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
cfg80211_regdomain = static_regdom(ieee80211_regdom);
printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
print_regdomain_info(cfg80211_regdomain);
/* The old code still requests for a new regdomain and if
* you have CRDA you get it updated, otherwise you get
* stuck with the static values. We ignore "EU" code as
* that is not a valid ISO / IEC 3166 alpha2 */
if (ieee80211_regdom[0] != 'E' && ieee80211_regdom[1] != 'U')
err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
ieee80211_regdom, NULL);
#else
cfg80211_regdomain = cfg80211_world_regdom;
err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL);
if (err)
printk(KERN_ERR "cfg80211: calling CRDA failed - "
"unable to update world regulatory domain, "
"using static definition\n");
#endif
return 0; return 0;
} }
void regulatory_exit(void) void regulatory_exit(void)
{ {
struct regulatory_request *req, *req_tmp; struct regulatory_request *req, *req_tmp;
mutex_lock(&cfg80211_drv_mutex); mutex_lock(&cfg80211_drv_mutex);
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
reset_regdomains_static();
#else
reset_regdomains(); reset_regdomains();
#endif
list_for_each_entry_safe(req, req_tmp, &regulatory_requests, list) { list_for_each_entry_safe(req, req_tmp, &regulatory_requests, list) {
list_del(&req->list); list_del(&req->list);
kfree(req); kfree(req);
} }
platform_device_unregister(reg_pdev); platform_device_unregister(reg_pdev);
mutex_unlock(&cfg80211_drv_mutex); mutex_unlock(&cfg80211_drv_mutex);
} }

View file

@ -1,44 +1,13 @@
#ifndef __NET_WIRELESS_REG_H #ifndef __NET_WIRELESS_REG_H
#define __NET_WIRELESS_REG_H #define __NET_WIRELESS_REG_H
extern const struct ieee80211_regdomain world_regdom; extern struct mutex cfg80211_reg_mutex;
#ifdef CONFIG_WIRELESS_OLD_REGULATORY bool is_world_regdom(const char *alpha2);
extern const struct ieee80211_regdomain us_regdom; bool reg_is_valid_request(const char *alpha2);
extern const struct ieee80211_regdomain jp_regdom;
extern const struct ieee80211_regdomain eu_regdom;
#endif
extern struct ieee80211_regdomain *cfg80211_regdomain;
extern struct ieee80211_regdomain *cfg80211_world_regdom;
extern struct list_head regulatory_requests;
struct regdom_last_setby {
struct wiphy *wiphy;
u8 initiator;
};
/* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */
struct regulatory_request {
struct list_head list;
struct wiphy *wiphy;
int granted;
enum reg_set_by initiator;
char alpha2[2];
};
bool is_world_regdom(char *alpha2);
bool reg_is_valid_request(char *alpha2);
int set_regdom(struct ieee80211_regdomain *rd);
int __regulatory_hint_alpha2(struct wiphy *wiphy, enum reg_set_by set_by,
const char *alpha2);
int regulatory_init(void); int regulatory_init(void);
void regulatory_exit(void); void regulatory_exit(void);
void print_regdomain_info(struct ieee80211_regdomain *); int set_regdom(const struct ieee80211_regdomain *rd);
/* If a char is A-Z */
#define IS_ALPHA(letter) (letter >= 65 && letter <= 90)
#endif /* __NET_WIRELESS_REG_H */ #endif /* __NET_WIRELESS_REG_H */