mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 05:33:09 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
db4148da2c
@ -7107,7 +7107,7 @@ static int airo_get_aplist(struct net_device *dev,
|
||||
*/
|
||||
static int airo_set_scan(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *vwrq,
|
||||
struct iw_point *dwrq,
|
||||
char *extra)
|
||||
{
|
||||
struct airo_info *ai = dev->priv;
|
||||
|
@ -147,7 +147,7 @@ static int airo_probe(struct pcmcia_device *p_dev)
|
||||
DEBUG(0, "airo_attach()\n");
|
||||
|
||||
/* 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.Handler = NULL;
|
||||
|
||||
|
@ -2124,7 +2124,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
|
||||
beacon = ath5k_hw_reg_read(ah, 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)
|
||||
|
@ -820,8 +820,6 @@
|
||||
#define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [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_CHIP (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA | \
|
||||
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY)
|
||||
|
||||
/*
|
||||
* Sleep control register
|
||||
|
@ -173,8 +173,10 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
|
||||
udelay(15);
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
val &= AR5K_RESET_CTL_CHIP;
|
||||
mask &= AR5K_RESET_CTL_CHIP;
|
||||
val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
|
||||
| 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 {
|
||||
val &= 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;
|
||||
|
||||
/* Reset chipset */
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_BASEBAND | bus_flags);
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
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) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
udelay(2300);
|
||||
|
||||
/* ...wakeup again!*/
|
||||
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
||||
if (ret) {
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
/* Implementation of beacon processing. */
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include "core.h"
|
||||
|
||||
/*
|
||||
@ -26,7 +25,6 @@
|
||||
* the operating mode of the station (AP or AdHoc). Parameters are AIFS
|
||||
* settings and channel width min/max
|
||||
*/
|
||||
|
||||
static int ath_beaconq_config(struct ath_softc *sc)
|
||||
{
|
||||
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.
|
||||
* Beacons are always sent out at the lowest rate, and are not retried.
|
||||
*/
|
||||
|
||||
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 ath_hal *ah = sc->sc_ah;
|
||||
struct ath_desc *ds;
|
||||
int flags, antenna;
|
||||
struct ath9k_11n_rate_series series[4];
|
||||
const struct ath9k_rate_table *rt;
|
||||
int flags, antenna;
|
||||
u8 rix, rate;
|
||||
int ctsrate = 0;
|
||||
int ctsduration = 0;
|
||||
struct ath9k_11n_rate_series series[4];
|
||||
|
||||
DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n",
|
||||
__func__, skb, skb->len);
|
||||
@ -115,20 +112,21 @@ static void ath_beacon_setup(struct ath_softc *sc,
|
||||
rate |= rt->info[rix].shortPreamble;
|
||||
|
||||
ath9k_hw_set11n_txdesc(ah, ds,
|
||||
skb->len + FCS_LEN, /* frame length */
|
||||
ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */
|
||||
skb->len + FCS_LEN, /* frame length */
|
||||
ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */
|
||||
avp->av_btxctl.txpower, /* txpower XXX */
|
||||
ATH9K_TXKEYIX_INVALID, /* no encryption */
|
||||
ATH9K_KEY_TYPE_CLEAR, /* no encryption */
|
||||
flags /* no ack, veol for beacons */
|
||||
ATH9K_TXKEYIX_INVALID, /* no encryption */
|
||||
ATH9K_KEY_TYPE_CLEAR, /* no encryption */
|
||||
flags /* no ack,
|
||||
veol for beacons */
|
||||
);
|
||||
|
||||
/* NB: beacon's BufLen must be a multiple of 4 bytes */
|
||||
ath9k_hw_filltxdesc(ah, ds,
|
||||
roundup(skb->len, 4), /* buffer length */
|
||||
true, /* first segment */
|
||||
true, /* last segment */
|
||||
ds /* first descriptor */
|
||||
true, /* first segment */
|
||||
true, /* last segment */
|
||||
ds /* first descriptor */
|
||||
);
|
||||
|
||||
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_vap *avp;
|
||||
struct sk_buff *skb;
|
||||
int cabq_depth;
|
||||
struct ath_txq *cabq;
|
||||
struct ieee80211_tx_info *info;
|
||||
int cabq_depth;
|
||||
|
||||
avp = sc->sc_vaps[if_id];
|
||||
ASSERT(avp);
|
||||
|
||||
cabq = sc->sc_cabq;
|
||||
|
||||
ASSERT(avp);
|
||||
|
||||
if (avp->av_bcbuf == NULL) {
|
||||
DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
|
||||
__func__, avp, avp->av_bcbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bf = avp->av_bcbuf;
|
||||
skb = (struct sk_buff *) bf->bf_mpdu;
|
||||
skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
if (skb) {
|
||||
pci_unmap_single(sc->pdev, bf->bf_dmacontext,
|
||||
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;
|
||||
if (skb == NULL)
|
||||
return NULL;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
|
||||
/*
|
||||
* TODO: make sure the seq# gets assigned properly (vs. other
|
||||
* TX frames)
|
||||
*/
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
sc->seq_no += 0x10;
|
||||
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
|
||||
hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
|
||||
}
|
||||
|
||||
bf->bf_buf_addr = bf->bf_dmacontext =
|
||||
pci_map_single(sc->pdev, skb->data,
|
||||
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
|
||||
* by the hardware using the self-linked descriptor + veol trick.
|
||||
*/
|
||||
|
||||
static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
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
|
||||
* persistant.
|
||||
*/
|
||||
|
||||
int ath_beaconq_setup(struct ath_hal *ah)
|
||||
{
|
||||
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
|
||||
* staggared beacons in the mBSSID case.
|
||||
*/
|
||||
|
||||
int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
struct ath_vap *avp;
|
||||
struct ieee80211_hdr *wh;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ath_buf *bf;
|
||||
struct sk_buff *skb;
|
||||
__le64 tstamp;
|
||||
|
||||
avp = sc->sc_vaps[if_id];
|
||||
ASSERT(avp);
|
||||
|
||||
/* Allocate a beacon descriptor if we haven't done so. */
|
||||
if (!avp->av_bcbuf) {
|
||||
/*
|
||||
* Allocate beacon state for hostap/ibss. We know
|
||||
* a buffer is available.
|
||||
*/
|
||||
/* Allocate beacon state for hostap/ibss. We know
|
||||
* a buffer is available. */
|
||||
|
||||
avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
|
||||
struct ath_buf, list);
|
||||
struct ath_buf, list);
|
||||
list_del(&avp->av_bcbuf->list);
|
||||
|
||||
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;
|
||||
* we assume the wbuf routines will return us something
|
||||
* with this alignment (perhaps should assert).
|
||||
* NB: the beacon data buffer must be 32-bit aligned.
|
||||
* FIXME: Fill avp->av_btxctl.txpower and
|
||||
* avp->av_btxctl.shortPreamble
|
||||
*/
|
||||
@ -375,6 +370,9 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
||||
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
|
||||
* 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",
|
||||
avp->av_bslot, intval, (unsigned long long)tsfadjust);
|
||||
|
||||
wh = (struct ieee80211_hdr *)skb->data;
|
||||
memcpy(&wh[1], &val, sizeof(val));
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
memcpy(&hdr[1], &val, sizeof(val));
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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
|
||||
* contents are done as needed and the slot time is also adjusted based on
|
||||
* current state.
|
||||
*
|
||||
* This tasklet is not scheduled, it's called in ISR context.
|
||||
*/
|
||||
|
||||
void ath9k_beacon_tasklet(unsigned long 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
|
||||
* a problem and should not occur. If we miss too
|
||||
* many consecutive beacons reset the device.
|
||||
*
|
||||
* FIXME: Clean up this mess !!
|
||||
*/
|
||||
if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) {
|
||||
sc->sc_bmisscount++;
|
||||
@ -505,19 +501,16 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
__func__, sc->sc_bmisscount);
|
||||
if (show_cycles) {
|
||||
/*
|
||||
* Display cycle counter stats
|
||||
* from HW to aide in debug of
|
||||
* stickiness.
|
||||
* Display cycle counter stats from HW
|
||||
* to aide in debug of stickiness.
|
||||
*/
|
||||
DPRINTF(sc,
|
||||
ATH_DBG_BEACON,
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"%s: busy times: rx_clear=%d, "
|
||||
"rx_frame=%d, tx_frame=%d\n",
|
||||
__func__, rx_clear, rx_frame,
|
||||
tx_frame);
|
||||
} else {
|
||||
DPRINTF(sc,
|
||||
ATH_DBG_BEACON,
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"%s: unable to obtain "
|
||||
"busy times\n", __func__);
|
||||
}
|
||||
@ -529,8 +522,7 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
} else if (sc->sc_bmisscount >= BSTUCK_THRESH) {
|
||||
if (sc->sc_flags & SC_OP_NO_RESET) {
|
||||
if (sc->sc_bmisscount == BSTUCK_THRESH) {
|
||||
DPRINTF(sc,
|
||||
ATH_DBG_BEACON,
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"%s: beacon is officially "
|
||||
"stuck\n", __func__);
|
||||
ath9k_hw_dmaRegDump(ah);
|
||||
@ -542,13 +534,12 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
ath_bstuck_process(sc);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc->sc_bmisscount != 0) {
|
||||
if (sc->sc_flags & SC_OP_NO_RESET) {
|
||||
DPRINTF(sc,
|
||||
ATH_DBG_BEACON,
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"%s: resume beacon xmit after %u misses\n",
|
||||
__func__, sc->sc_bmisscount);
|
||||
} else {
|
||||
@ -572,10 +563,12 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
tsftu = TSF_TO_TU(tsf>>32, tsf);
|
||||
slot = ((tsftu % intval) * ATH_BCBUF) / intval;
|
||||
if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF];
|
||||
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
|
||||
__func__, slot, (unsigned long long) tsf, tsftu,
|
||||
intval, if_id);
|
||||
"%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
|
||||
__func__, slot, (unsigned long long)tsf, tsftu,
|
||||
intval, if_id);
|
||||
|
||||
bfaddr = 0;
|
||||
if (if_id != ATH_IF_ID_ANY) {
|
||||
bf = ath_beacon_generate(sc, if_id);
|
||||
@ -632,9 +625,8 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
* Tasklet for Beacon Stuck processing
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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
|
||||
* we've associated with.
|
||||
*/
|
||||
|
||||
void ath_beacon_config(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
u32 nexttbtt, intval;
|
||||
struct ath_beacon_config conf;
|
||||
enum ath9k_opmode av_opmode;
|
||||
u32 nexttbtt, intval;
|
||||
|
||||
if (if_id != ATH_IF_ID_ANY)
|
||||
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));
|
||||
|
||||
/* 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 ?
|
||||
sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
|
||||
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;
|
||||
|
||||
/* extract tstamp from last beacon and convert to TU */
|
||||
nexttbtt = TSF_TO_TU(get_unaligned_le32(conf.u.last_tstamp + 4),
|
||||
get_unaligned_le32(conf.u.last_tstamp));
|
||||
nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp);
|
||||
|
||||
/* XXX conditionalize multi-bss support? */
|
||||
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;
|
||||
}
|
||||
|
||||
if (nexttbtt == 0) /* e.g. for ap mode */
|
||||
if (nexttbtt == 0) /* e.g. for ap mode */
|
||||
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);
|
||||
|
||||
DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
|
||||
__func__, nexttbtt, intval, conf.beacon_interval);
|
||||
|
||||
/* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */
|
||||
if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
|
||||
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).
|
||||
*/
|
||||
dtimperiod = conf.dtim_period;
|
||||
if (dtimperiod <= 0) /* NB: 0 if not known */
|
||||
if (dtimperiod <= 0) /* NB: 0 if not known */
|
||||
dtimperiod = 1;
|
||||
dtimcount = conf.dtim_count;
|
||||
if (dtimcount >= dtimperiod) /* NB: sanity check */
|
||||
dtimcount = 0; /* XXX? */
|
||||
cfpperiod = 1; /* NB: no PCF support yet */
|
||||
if (dtimcount >= dtimperiod) /* NB: sanity check */
|
||||
dtimcount = 0;
|
||||
cfpperiod = 1; /* NB: no PCF support yet */
|
||||
cfpcount = 0;
|
||||
|
||||
sleepduration = conf.listen_interval * intval;
|
||||
if (sleepduration <= 0)
|
||||
sleepduration = intval;
|
||||
|
||||
#define FUDGE 2
|
||||
#define FUDGE 2
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
* 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_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
|
||||
bs.bs_cfpmaxduration = 0;
|
||||
|
||||
/*
|
||||
* Calculate the number of consecutive beacons to miss
|
||||
* 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.
|
||||
*/
|
||||
if (sleepduration > intval) {
|
||||
bs.bs_bmissthreshold =
|
||||
conf.listen_interval *
|
||||
ATH_DEFAULT_BMISS_LIMIT / 2;
|
||||
bs.bs_bmissthreshold = conf.listen_interval *
|
||||
ATH_DEFAULT_BMISS_LIMIT / 2;
|
||||
} else {
|
||||
bs.bs_bmissthreshold =
|
||||
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
|
||||
*/
|
||||
|
||||
bs.bs_sleepduration =
|
||||
roundup(IEEE80211_MS_TO_TU(100), sleepduration);
|
||||
bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100),
|
||||
sleepduration);
|
||||
if (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) {
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
* TSF .
|
||||
* TSF
|
||||
*/
|
||||
#define FUDGE 2
|
||||
#define FUDGE 2
|
||||
if (!(intval & ATH9K_BEACON_RESET_TSF)) {
|
||||
tsf = ath9k_hw_gettsf64(ah);
|
||||
tsftu = TSF_TO_TU((u32)(tsf>>32),
|
||||
|
@ -534,7 +534,8 @@ int ath_vap_attach(struct ath_softc *sc,
|
||||
avp->av_opmode = opmode;
|
||||
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_nvaps++;
|
||||
|
@ -1001,6 +1001,7 @@ struct ath_softc {
|
||||
u32 sc_bhalq;
|
||||
u32 sc_bmisscount;
|
||||
u32 ast_be_xmit; /* beacons transmitted */
|
||||
u64 bc_tstamp;
|
||||
|
||||
/* Rate */
|
||||
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
|
||||
|
@ -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,
|
||||
const struct ath9k_node_stats *stats)
|
||||
{
|
||||
@ -2533,18 +2538,20 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
|
||||
u32 phyCnt1, phyCnt2;
|
||||
|
||||
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_CCK, 0);
|
||||
if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
|
||||
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);
|
||||
ahp->ah_stats.ast_nodestats = *stats;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
return;
|
||||
|
||||
/* NB: these are not reset-on-read */
|
||||
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
|
||||
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
|
||||
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;
|
||||
u32 ofdmPhyErrCnt, cckPhyErrCnt;
|
||||
|
||||
/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
|
||||
ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
|
||||
ahp->ah_stats.ast_ani_ofdmerrs +=
|
||||
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
|
||||
@ -2562,11 +2570,17 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
|
||||
cckPhyErrCnt - aniState->cckPhyErrCount;
|
||||
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)
|
||||
ath9k_hw_ani_ofdm_err_trigger(ah);
|
||||
if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
|
||||
ath9k_hw_ani_cck_err_trigger(ah);
|
||||
|
||||
/* NB: always restart to insure the h/w counters are reset */
|
||||
ath9k_ani_restart(ah);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
/* FIXME: remove this include! */
|
||||
#include "../net/mac80211/rate.h"
|
||||
|
||||
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;
|
||||
|
||||
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++) {
|
||||
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]
|
||||
= (sband->bitrates[i].bitrate * 2) / 10;
|
||||
j++;
|
||||
@ -1852,19 +1851,17 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
|
||||
}
|
||||
|
||||
/* 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 ath_softc *sc = priv;
|
||||
struct ath_tx_info_priv *tx_info_priv;
|
||||
struct ath_node *an;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_local *local;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr;
|
||||
__le16 fc;
|
||||
|
||||
local = hw_to_local(sc->hw);
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = hdr->frame_control;
|
||||
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);
|
||||
spin_unlock_bh(&sc->node_lock);
|
||||
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
if (!an || !sta || !ieee80211_is_data(fc)) {
|
||||
if (!an || !priv_sta || !ieee80211_is_data(fc)) {
|
||||
if (tx_info->driver_data[0] != NULL) {
|
||||
kfree(tx_info->driver_data[0]);
|
||||
tx_info->driver_data[0] = NULL;
|
||||
@ -1882,24 +1878,22 @@ static void ath_tx_status(void *priv, struct net_device *dev,
|
||||
return;
|
||||
}
|
||||
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]);
|
||||
tx_info->driver_data[0] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
u8 tidno)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_local *local;
|
||||
struct ath_atx_tid *txtid;
|
||||
struct ieee80211_supported_band *sband;
|
||||
u16 buffersize = 0;
|
||||
int state;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
struct sta_info *si;
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_TXAGGR))
|
||||
return;
|
||||
@ -1908,11 +1902,16 @@ static void ath_tx_aggr_resp(struct ath_softc *sc,
|
||||
if (!txtid->paused)
|
||||
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 <<
|
||||
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) {
|
||||
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,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct sk_buff *skb,
|
||||
struct rate_selection *sel)
|
||||
static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb, struct rate_selection *sel)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sta_info *sta;
|
||||
struct ath_softc *sc = (struct ath_softc *)priv;
|
||||
struct ath_softc *sc = priv;
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
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 ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
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);
|
||||
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(local, sband, sta);
|
||||
lowest_idx = rate_lowest_index(sband, sta);
|
||||
tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
|
||||
/* lowest rate for management and multicast/broadcast frames */
|
||||
if (!ieee80211_is_data(fc) ||
|
||||
@ -1965,8 +1960,6 @@ static void ath_get_rate(void *priv, struct net_device *dev,
|
||||
return;
|
||||
}
|
||||
|
||||
ath_rc_priv = sta->rate_ctrl_priv;
|
||||
|
||||
/* Find tx rate for unicast frames */
|
||||
ath_rate_findrate(sc, ath_rc_priv,
|
||||
ATH_11N_TXMAXTRY, 4,
|
||||
@ -1975,8 +1968,7 @@ static void ath_get_rate(void *priv, struct net_device *dev,
|
||||
&is_probe,
|
||||
false);
|
||||
if (is_probe)
|
||||
sel->probe_idx = ((struct ath_tx_ratectrl *)
|
||||
sta->rate_ctrl_priv)->probe_rate;
|
||||
sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
|
||||
|
||||
/* Ratecontrol sometimes returns invalid rate index */
|
||||
if (tx_info_priv->rcs[0].rix != 0xff)
|
||||
@ -2020,37 +2012,31 @@ static void ath_get_rate(void *priv, struct net_device *dev,
|
||||
__func__,
|
||||
print_mac(mac, hdr->addr1));
|
||||
} 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,
|
||||
struct ieee80211_local *local,
|
||||
struct sta_info *sta)
|
||||
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_hw *hw = local_to_hw(local);
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_softc *sc = priv;
|
||||
struct ath_rate_node *ath_rc_priv = priv_sta;
|
||||
int i, j = 0;
|
||||
|
||||
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
ath_setup_rates(local, sta);
|
||||
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
|
||||
ath_setup_rates(sc, sband, sta, ath_rc_priv);
|
||||
if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
|
||||
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;
|
||||
if (j == ATH_RATE_MAX)
|
||||
break;
|
||||
}
|
||||
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)
|
||||
@ -2058,13 +2044,12 @@ static void ath_rate_clear(void *priv)
|
||||
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;
|
||||
|
||||
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
|
||||
return local->hw.priv;
|
||||
return hw->priv;
|
||||
}
|
||||
|
||||
static void ath_rate_free(void *priv)
|
||||
@ -2072,7 +2057,7 @@ static void ath_rate_free(void *priv)
|
||||
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_vap *avp = sc->sc_vaps[0];
|
||||
@ -2092,7 +2077,8 @@ static void *ath_rate_alloc_sta(void *priv, gfp_t gfp)
|
||||
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_softc *sc = priv;
|
||||
@ -2111,7 +2097,7 @@ static struct rate_control_ops ath_rate_ops = {
|
||||
.alloc = ath_rate_alloc,
|
||||
.free = ath_rate_free,
|
||||
.alloc_sta = ath_rate_alloc_sta,
|
||||
.free_sta = ath_rate_free_sta
|
||||
.free_sta = ath_rate_free_sta,
|
||||
};
|
||||
|
||||
int ath_rate_control_register(void)
|
||||
|
@ -2258,7 +2258,7 @@ static int atmel_get_freq(struct net_device *dev,
|
||||
|
||||
static int atmel_set_scan(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *vwrq,
|
||||
struct iw_point *dwrq,
|
||||
char *extra)
|
||||
{
|
||||
struct atmel_private *priv = netdev_priv(dev);
|
||||
|
@ -158,7 +158,7 @@ static int atmel_probe(struct pcmcia_device *p_dev)
|
||||
DEBUG(0, "atmel_attach()\n");
|
||||
|
||||
/* 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.Handler = NULL;
|
||||
|
||||
|
@ -188,6 +188,11 @@ void b43_rfkill_init(struct b43_wldev *dev)
|
||||
"The built-in radio LED will not work.\n");
|
||||
#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);
|
||||
if (err)
|
||||
goto err_unreg_rfk;
|
||||
|
@ -36,8 +36,6 @@
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "../net/mac80211/rate.h"
|
||||
|
||||
#include "iwl-3945.h"
|
||||
|
||||
#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,
|
||||
struct ieee80211_local *local, struct sta_info *sta)
|
||||
static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband,
|
||||
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;
|
||||
|
||||
IWL_DEBUG_RATE("enter\n");
|
||||
@ -333,22 +331,22 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
|
||||
* after assoc.. */
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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 */
|
||||
@ -356,17 +354,24 @@ static void rs_free(void *priv)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void rs_clear(void *priv)
|
||||
{
|
||||
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_sta_priv *psta = (void *) sta->drv_priv;
|
||||
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");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
psta->rs_sta = rs_sta;
|
||||
|
||||
spin_lock_init(&rs_sta->lock);
|
||||
|
||||
rs_sta->start_rate = IWL_RATE_INVALID;
|
||||
@ -400,10 +407,14 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp)
|
||||
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;
|
||||
|
||||
psta->rs_sta = NULL;
|
||||
|
||||
IWL_DEBUG_RATE("enter\n");
|
||||
del_timer_sync(&rs_sta->rate_scale_flush);
|
||||
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
|
||||
* the hardware for each rate.
|
||||
*/
|
||||
static void rs_tx_status(void *priv_rate,
|
||||
struct net_device *dev,
|
||||
static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u8 retries, current_count;
|
||||
int scale_rate_index, first_index, last_index;
|
||||
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 ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct iwl3945_rs_sta *rs_sta;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct iwl3945_rs_sta *rs_sta = priv_sta;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
IWL_DEBUG_RATE("enter\n");
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
|
||||
retries = info->status.retry_count;
|
||||
first_index = sband->bitrates[info->tx_rate_idx].hw_value;
|
||||
if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
|
||||
@ -472,17 +476,11 @@ static void rs_tx_status(void *priv_rate,
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
if (!sta || !sta->rate_ctrl_priv) {
|
||||
rcu_read_unlock();
|
||||
if (!priv_sta) {
|
||||
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
rs_sta = (void *)sta->rate_ctrl_priv;
|
||||
|
||||
rs_sta->tx_packets++;
|
||||
|
||||
scale_rate_index = first_index;
|
||||
@ -549,8 +547,6 @@ static void rs_tx_status(void *priv_rate,
|
||||
|
||||
spin_unlock_irqrestore(&rs_sta->lock, flags);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
IWL_DEBUG_RATE("leave\n");
|
||||
|
||||
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
|
||||
*
|
||||
*/
|
||||
static void rs_get_rate(void *priv_rate, struct net_device *dev,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct sk_buff *skb,
|
||||
struct rate_selection *sel)
|
||||
static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb, struct rate_selection *sel)
|
||||
{
|
||||
u8 low = IWL_RATE_INVALID;
|
||||
u8 high = IWL_RATE_INVALID;
|
||||
u16 high_low;
|
||||
int index;
|
||||
struct iwl3945_rs_sta *rs_sta;
|
||||
struct iwl3945_rs_sta *rs_sta = priv_sta;
|
||||
struct iwl3945_rate_scale_data *window = NULL;
|
||||
int current_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;
|
||||
s8 scale_action = 0;
|
||||
unsigned long flags;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct sta_info *sta;
|
||||
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);
|
||||
|
||||
IWL_DEBUG_RATE("enter\n");
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
|
||||
/* Send management frames and broadcast/multicast data using lowest
|
||||
* rate. */
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
|
||||
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");
|
||||
sel->rate_idx = rate_lowest_index(local, sband, sta);
|
||||
rcu_read_unlock();
|
||||
sel->rate_idx = rate_lowest_index(sband, sta);
|
||||
return;
|
||||
}
|
||||
|
||||
rs_sta = (void *)sta->rate_ctrl_priv;
|
||||
|
||||
rate_mask = sta->sta.supp_rates[sband->band];
|
||||
rate_mask = sta->supp_rates[sband->band];
|
||||
index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
|
||||
|
||||
if (sband->band == IEEE80211_BAND_5GHZ)
|
||||
@ -811,8 +797,6 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
|
||||
else
|
||||
sel->rate_idx = rs_sta->last_txrate_idx;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
IWL_DEBUG_RATE("leave: %d\n", index);
|
||||
}
|
||||
|
||||
@ -829,114 +813,28 @@ static struct rate_control_ops rs_ops = {
|
||||
.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)
|
||||
{
|
||||
struct iwl3945_priv *priv = hw->priv;
|
||||
s32 rssi = 0;
|
||||
unsigned long flags;
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct iwl3945_rs_sta *rs_sta;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl3945_sta_priv *psta;
|
||||
|
||||
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();
|
||||
|
||||
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
|
||||
if (!sta || !sta->rate_ctrl_priv) {
|
||||
sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
|
||||
psta = (void *) sta->drv_priv;
|
||||
if (!sta || !psta) {
|
||||
IWL_DEBUG_RATE("leave - no private rate data!\n");
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
rs_sta = (void *)sta->rate_ctrl_priv;
|
||||
rs_sta = psta->rs_sta;
|
||||
|
||||
spin_lock_irqsave(&rs_sta->lock, flags);
|
||||
|
||||
|
@ -175,15 +175,6 @@ static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
|
||||
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
|
||||
*
|
||||
|
@ -73,6 +73,10 @@ extern struct pci_device_id iwl3945_hw_card_ids[];
|
||||
extern int iwl3945_param_hwcrypto;
|
||||
extern int iwl3945_param_queues_num;
|
||||
|
||||
struct iwl3945_sta_priv {
|
||||
struct iwl3945_rs_sta *rs_sta;
|
||||
};
|
||||
|
||||
enum iwl3945_antenna {
|
||||
IWL_ANTENNA_DIVERSITY,
|
||||
IWL_ANTENNA_MAIN,
|
||||
|
@ -35,8 +35,6 @@
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "../net/mac80211/rate.h"
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-sta.h"
|
||||
#include "iwl-core.h"
|
||||
@ -169,9 +167,9 @@ struct iwl_lq_sta {
|
||||
};
|
||||
|
||||
static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
struct net_device *dev,
|
||||
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,
|
||||
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,
|
||||
struct iwl_lq_sta *lq_data, u8 tid,
|
||||
struct sta_info *sta)
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
|
||||
IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n",
|
||||
print_mac(mac, sta->sta.addr), tid);
|
||||
ieee80211_start_tx_ba_session(priv->hw, sta->sta.addr, tid);
|
||||
print_mac(mac, 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,
|
||||
struct iwl_lq_sta *lq_data,
|
||||
struct sta_info *sta)
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
if ((tid < TID_MAX_LOAD_COUNT))
|
||||
rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
|
||||
@ -770,7 +768,8 @@ out:
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
int status;
|
||||
@ -778,11 +777,9 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
|
||||
int rs_index, index = 0;
|
||||
struct iwl_lq_sta *lq_sta;
|
||||
struct iwl_link_quality_cmd *table;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_hw *hw = local_to_hw(local);
|
||||
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
|
||||
struct ieee80211_hw *hw = priv->hw;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct iwl_rate_scale_data *window = 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)
|
||||
retries = 15;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
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;
|
||||
lq_sta = (struct iwl_lq_sta *)priv_sta;
|
||||
|
||||
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
|
||||
!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. */
|
||||
rs_rate_scale_perform(priv, dev, hdr, sta);
|
||||
rs_rate_scale_perform(priv, hdr, sta, lq_sta);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
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,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
struct ieee80211_conf *conf,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_scale_tbl_info *tbl, int index)
|
||||
{
|
||||
u16 rate_mask;
|
||||
@ -1148,10 +1136,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
|
||||
s8 is_green = lq_sta->is_green;
|
||||
|
||||
if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
|
||||
!sta->sta.ht_info.ht_supported)
|
||||
!sta->ht_info.ht_supported)
|
||||
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)
|
||||
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,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
struct ieee80211_conf *conf,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_scale_tbl_info *tbl, int index)
|
||||
{
|
||||
u16 rate_mask;
|
||||
@ -1216,7 +1204,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
|
||||
s32 rate;
|
||||
|
||||
if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
|
||||
!sta->sta.ht_info.ht_supported)
|
||||
!sta->ht_info.ht_supported)
|
||||
return -1;
|
||||
|
||||
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,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
struct ieee80211_conf *conf,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_sta *sta,
|
||||
int index)
|
||||
{
|
||||
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,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
struct ieee80211_conf *conf,
|
||||
struct sta_info *sta, int index)
|
||||
struct ieee80211_sta *sta, int index)
|
||||
{
|
||||
u8 is_green = lq_sta->is_green;
|
||||
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,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
struct ieee80211_conf *conf,
|
||||
struct sta_info *sta, int index)
|
||||
struct ieee80211_sta *sta, int index)
|
||||
{
|
||||
s8 is_green = lq_sta->is_green;
|
||||
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.
|
||||
*/
|
||||
static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
struct net_device *dev,
|
||||
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 = local_to_hw(local);
|
||||
struct ieee80211_hw *hw = priv->hw;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
int low = IWL_RATE_INVALID;
|
||||
int high = IWL_RATE_INVALID;
|
||||
@ -1700,7 +1687,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
__le16 fc;
|
||||
u16 rate_mask;
|
||||
u8 update_lq = 0;
|
||||
struct iwl_lq_sta *lq_sta;
|
||||
struct iwl_scale_tbl_info *tbl, *tbl1;
|
||||
u16 rate_scale_index_msk = 0;
|
||||
u32 rate;
|
||||
@ -1721,11 +1707,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sta || !sta->rate_ctrl_priv)
|
||||
if (!sta || !lq_sta)
|
||||
return;
|
||||
|
||||
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
|
||||
lq_sta->supp_rates = sta->sta.supp_rates[lq_sta->band];
|
||||
lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
|
||||
|
||||
tid = rs_tl_add_packet(lq_sta, hdr);
|
||||
|
||||
@ -2064,9 +2049,9 @@ out:
|
||||
|
||||
static void rs_initialize_lq(struct iwl_priv *priv,
|
||||
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;
|
||||
int rate_idx;
|
||||
int i;
|
||||
@ -2075,10 +2060,9 @@ static void rs_initialize_lq(struct iwl_priv *priv,
|
||||
u8 active_tbl = 0;
|
||||
u8 valid_tx_ant;
|
||||
|
||||
if (!sta || !sta->rate_ctrl_priv)
|
||||
if (!sta || !lq_sta)
|
||||
goto out;
|
||||
|
||||
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
|
||||
i = lq_sta->last_txrate_idx;
|
||||
|
||||
if ((lq_sta->lq.sta_id == 0xff) &&
|
||||
@ -2119,37 +2103,30 @@ static void rs_initialize_lq(struct iwl_priv *priv,
|
||||
return;
|
||||
}
|
||||
|
||||
static void rs_get_rate(void *priv_rate, struct net_device *dev,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct sk_buff *skb,
|
||||
struct rate_selection *sel)
|
||||
static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb, struct rate_selection *sel)
|
||||
{
|
||||
|
||||
int i;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
|
||||
struct ieee80211_conf *conf = &priv->hw->conf;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct sta_info *sta;
|
||||
__le16 fc;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
|
||||
struct iwl_lq_sta *lq_sta;
|
||||
|
||||
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
|
||||
* rate. */
|
||||
fc = hdr->frame_control;
|
||||
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
|
||||
!sta || !sta->rate_ctrl_priv) {
|
||||
sel->rate_idx = rate_lowest_index(local, sband, sta);
|
||||
goto out;
|
||||
!sta || !priv_sta) {
|
||||
sel->rate_idx = rate_lowest_index(sband, sta);
|
||||
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;
|
||||
|
||||
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.rs_table[0].rate_n_flags = 0;
|
||||
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)) {
|
||||
sel->rate_idx = rate_lowest_index(local, sband, sta);
|
||||
goto out;
|
||||
sel->rate_idx = rate_lowest_index(sband, sta);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sband->band == IEEE80211_BAND_5GHZ)
|
||||
i -= IWL_FIRST_OFDM_RATE;
|
||||
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_priv *priv;
|
||||
@ -2206,20 +2182,16 @@ static void *rs_alloc_sta(void *priv_rate, gfp_t gfp)
|
||||
return lq_sta;
|
||||
}
|
||||
|
||||
static void rs_rate_init(void *priv_rate, void *priv_sta,
|
||||
struct ieee80211_local *local,
|
||||
struct sta_info *sta)
|
||||
static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta)
|
||||
{
|
||||
int i, j;
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
|
||||
struct ieee80211_conf *conf = &priv->hw->conf;
|
||||
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->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 (i = 0; i < IWL_RATE_COUNT; 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;
|
||||
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);
|
||||
|
||||
/* for IBSS the call are from tasklet */
|
||||
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) {
|
||||
IWL_DEBUG_RATE("LQ: ADD station %s\n",
|
||||
print_mac(mac, sta->sta.addr));
|
||||
sta_id = iwl_add_station_flags(priv, sta->sta.addr,
|
||||
print_mac(mac, sta->addr));
|
||||
sta_id = iwl_add_station_flags(priv, sta->addr,
|
||||
0, CMD_ASYNC, NULL);
|
||||
}
|
||||
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 */
|
||||
lq_sta->last_txrate_idx = 3;
|
||||
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;
|
||||
|
||||
/* 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->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->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,
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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 */
|
||||
static void rs_free(void *priv_rate)
|
||||
@ -2446,12 +2418,12 @@ static void rs_clear(void *priv_rate)
|
||||
#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_priv *priv;
|
||||
struct iwl_priv *priv = priv_r;
|
||||
|
||||
priv = (struct iwl_priv *)priv_rate;
|
||||
IWL_DEBUG_RATE("enter\n");
|
||||
kfree(lq_sta);
|
||||
IWL_DEBUG_RATE("leave\n");
|
||||
|
@ -2504,8 +2504,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
@ -3171,6 +3168,10 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
|
||||
priv->power_data.dtim_period = bss_conf->dtim_period;
|
||||
priv->timestamp = bss_conf->timestamp;
|
||||
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 +
|
||||
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 &&
|
||||
time_after(priv->next_scan_jiffies, jiffies)) {
|
||||
IWL_DEBUG_SCAN("scan rejected: within next scan period\n");
|
||||
ret = -EAGAIN;
|
||||
queue_work(priv->workqueue, &priv->scan_completed);
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* if we just finished scan ask for delay */
|
||||
if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
|
||||
time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
|
||||
IWL_DEBUG_SCAN("scan rejected: within previous scan period\n");
|
||||
ret = -EAGAIN;
|
||||
queue_work(priv->workqueue, &priv->scan_completed);
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (ssid_len) {
|
||||
priv->one_direct_scan = 1;
|
||||
priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE);
|
||||
|
@ -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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */
|
||||
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);
|
||||
|
||||
/*
|
||||
* Determine how many receiver/antenna chains to use.
|
||||
#define IWL_NUM_RX_CHAINS_MULTIPLE 3
|
||||
#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.
|
||||
* MIMO (dual stream) requires at least 2, but works better with 3.
|
||||
* 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. */
|
||||
if (is_single || (!is_cam && (priv->current_ht_config.sm_ps ==
|
||||
WLAN_HT_CAP_SM_PS_STATIC)))
|
||||
return 2;
|
||||
return IWL_NUM_RX_CHAINS_SINGLE;
|
||||
else
|
||||
return 3;
|
||||
return IWL_NUM_RX_CHAINS_MULTIPLE;
|
||||
}
|
||||
|
||||
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) {
|
||||
case WLAN_HT_CAP_SM_PS_STATIC:
|
||||
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;
|
||||
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;
|
||||
case WLAN_HT_CAP_SM_PS_INVALID:
|
||||
default:
|
||||
@ -796,7 +807,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
|
||||
|
||||
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;
|
||||
else
|
||||
priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
|
||||
|
@ -463,11 +463,6 @@ void iwl_init_scan_params(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)) {
|
||||
IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
|
||||
return -EIO;
|
||||
@ -479,8 +474,7 @@ int iwl_scan_initiate(struct iwl_priv *priv)
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN("Scan request while abort pending. "
|
||||
"Queuing.\n");
|
||||
IWL_DEBUG_SCAN("Scan request while abort pending\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* command queue then there a command routing bug has been introduced
|
||||
* in the queue management code. */
|
||||
if (txq_id != IWL_CMD_QUEUE_NUM)
|
||||
IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
|
||||
txq_id, pkt->hdr.cmd);
|
||||
BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
|
||||
if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
|
||||
"wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd))
|
||||
return;
|
||||
|
||||
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
|
||||
cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
|
||||
|
@ -7370,15 +7370,6 @@ static ssize_t show_temperature(struct device *d,
|
||||
|
||||
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,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -7840,7 +7831,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
|
||||
#endif
|
||||
&dev_attr_power_level.attr,
|
||||
&dev_attr_retry_rate.attr,
|
||||
&dev_attr_rs_window.attr,
|
||||
&dev_attr_statistics.attr,
|
||||
&dev_attr_status.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);
|
||||
|
||||
hw->rate_control_algorithm = "iwl-3945-rs";
|
||||
hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
|
||||
|
||||
IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
|
||||
priv = hw->priv;
|
||||
|
@ -58,6 +58,7 @@ struct lbs_802_11_security {
|
||||
u8 WPA2enabled;
|
||||
u8 wep_enabled;
|
||||
u8 auth_mode;
|
||||
u32 key_mgmt;
|
||||
};
|
||||
|
||||
/** Current Basic Service Set State Structure */
|
||||
|
@ -1598,8 +1598,20 @@ static int lbs_set_encodeext(struct net_device *dev,
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret == 0) { /* key installation is time critical: postpone not! */
|
||||
lbs_do_association_work(priv);
|
||||
if (ret == 0) {
|
||||
/* 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 {
|
||||
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_CIPHER_PAIRWISE:
|
||||
case IW_AUTH_CIPHER_GROUP:
|
||||
case IW_AUTH_KEY_MGMT:
|
||||
case IW_AUTH_DROP_UNENCRYPTED:
|
||||
/*
|
||||
* libertas does not use these parameters
|
||||
*/
|
||||
break;
|
||||
|
||||
case IW_AUTH_KEY_MGMT:
|
||||
assoc_req->secinfo.key_mgmt = dwrq->value;
|
||||
updated = 1;
|
||||
break;
|
||||
|
||||
case IW_AUTH_WPA_VERSION:
|
||||
if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
|
||||
assoc_req->secinfo.WPAenabled = 0;
|
||||
@ -1793,6 +1809,10 @@ static int lbs_get_auth(struct net_device *dev,
|
||||
lbs_deb_enter(LBS_DEB_WEXT);
|
||||
|
||||
switch (dwrq->flags & IW_AUTH_INDEX) {
|
||||
case IW_AUTH_KEY_MGMT:
|
||||
dwrq->value = priv->secinfo.key_mgmt;
|
||||
break;
|
||||
|
||||
case IW_AUTH_WPA_VERSION:
|
||||
dwrq->value = 0;
|
||||
if (priv->secinfo.WPAenabled)
|
||||
|
@ -398,7 +398,7 @@ static int netwave_probe(struct pcmcia_device *link)
|
||||
link->io.IOAddrLines = 5;
|
||||
|
||||
/* 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.Handler = &netwave_interrupt;
|
||||
|
||||
|
@ -5291,7 +5291,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
|
||||
/* Trigger a scan (look for other cells in the vicinity) */
|
||||
static int orinoco_ioctl_setscan(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *srq,
|
||||
struct iw_point *srq,
|
||||
char *extra)
|
||||
{
|
||||
struct orinoco_private *priv = netdev_priv(dev);
|
||||
|
@ -121,7 +121,7 @@ orinoco_cs_probe(struct pcmcia_device *link)
|
||||
link->priv = dev;
|
||||
|
||||
/* 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.Handler = orinoco_interrupt;
|
||||
link->irq.Instance = dev;
|
||||
|
@ -325,7 +325,7 @@ static int ray_probe(struct pcmcia_device *p_dev)
|
||||
p_dev->io.IOAddrLines = 5;
|
||||
|
||||
/* 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.Handler = &ray_interrupt;
|
||||
|
||||
|
@ -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,
|
||||
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
|
||||
{
|
||||
struct iw_param *param = &wrqu->param;
|
||||
struct usbnet *usbdev = dev->priv;
|
||||
union iwreq_data evt;
|
||||
int ret = -EINVAL;
|
||||
@ -1635,7 +1634,7 @@ static int rndis_iw_set_scan(struct net_device *dev,
|
||||
|
||||
devdbg(usbdev, "SIOCSIWSCAN");
|
||||
|
||||
if (param->flags == 0) {
|
||||
if (wrqu->data.flags == 0) {
|
||||
tmp = ccpu2(1);
|
||||
ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
|
||||
sizeof(tmp));
|
||||
|
@ -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
|
||||
* 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)
|
||||
set_key = rt2x00dev->ops->lib->config_pairwise_key;
|
||||
|
@ -381,7 +381,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
|
||||
if (reg && reg == mask)
|
||||
return -ENOSPC;
|
||||
|
||||
key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
|
||||
key->hw_key_idx += reg ? ffz(reg) : 0;
|
||||
|
||||
/*
|
||||
* Upload key to hardware
|
||||
@ -477,7 +477,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
|
||||
key->hw_key_idx += reg ? ffz(reg) : 0;
|
||||
|
||||
/*
|
||||
* Upload key to hardware
|
||||
|
@ -393,7 +393,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
|
||||
if (reg && reg == mask)
|
||||
return -ENOSPC;
|
||||
|
||||
key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
|
||||
key->hw_key_idx += reg ? ffz(reg) : 0;
|
||||
|
||||
/*
|
||||
* Upload key to hardware
|
||||
@ -494,7 +494,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
|
||||
key->hw_key_idx += reg ? ffz(reg) : 0;
|
||||
|
||||
/*
|
||||
* Upload key to hardware
|
||||
|
@ -195,7 +195,7 @@ spectrum_cs_probe(struct pcmcia_device *link)
|
||||
link->priv = dev;
|
||||
|
||||
/* 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.Handler = orinoco_interrupt;
|
||||
link->irq.Instance = dev;
|
||||
|
@ -4496,7 +4496,7 @@ wavelan_probe(struct pcmcia_device *p_dev)
|
||||
p_dev->io.IOAddrLines = 3;
|
||||
|
||||
/* 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.Handler = wavelan_interrupt;
|
||||
|
||||
|
@ -1917,7 +1917,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
|
||||
p_dev->io.IOAddrLines = 5;
|
||||
|
||||
/* 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.Handler = wl3501_interrupt;
|
||||
|
||||
|
@ -471,6 +471,11 @@ struct ieee80211s_hdr {
|
||||
u8 eaddr3[6];
|
||||
} __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
|
||||
*
|
||||
|
@ -363,11 +363,13 @@ struct wiphy;
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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
|
||||
* when adding a group key.
|
||||
|
@ -1800,4 +1800,72 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
|
||||
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 */
|
||||
|
@ -223,9 +223,11 @@ struct wiphy {
|
||||
* the netdev.)
|
||||
*
|
||||
* @wiphy: pointer to hardware description
|
||||
* @iftype: interface type
|
||||
*/
|
||||
struct wireless_dev {
|
||||
struct wiphy *wiphy;
|
||||
enum nl80211_iftype iftype;
|
||||
|
||||
/* private to the generic wireless code */
|
||||
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,
|
||||
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
|
||||
* @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,
|
||||
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 */
|
||||
|
@ -82,7 +82,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct net_device *dev;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int ret;
|
||||
@ -95,15 +94,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
|
||||
if (!nl80211_type_check(type))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
ret = ieee80211_if_change_type(sdata, type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (netif_running(sdata->dev))
|
||||
return -EBUSY;
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
|
||||
ieee80211_sdata_set_mesh_id(sdata,
|
||||
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,
|
||||
struct key_params *params)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta = NULL;
|
||||
enum ieee80211_key_alg alg;
|
||||
struct ieee80211_key *key;
|
||||
int err;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
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,
|
||||
u8 key_idx, u8 *mac_addr)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
int ret;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
rcu_read_lock();
|
||||
@ -222,7 +213,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
void (*callback)(void *cookie,
|
||||
struct key_params *params))
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta = NULL;
|
||||
u8 seq[6] = {0};
|
||||
@ -232,9 +222,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u16 iv16;
|
||||
int err = -ENOENT;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
rcu_read_lock();
|
||||
@ -310,12 +297,8 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u8 key_idx)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
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,
|
||||
struct beacon_parameters *params)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct beacon_data *old;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
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,
|
||||
struct beacon_parameters *params)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct beacon_data *old;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
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)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct beacon_data *old;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
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;
|
||||
int err;
|
||||
|
||||
if (dev == local->mdev || params->vlan == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Prevent a race with changing the rate control algorithm */
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
@ -725,7 +693,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
sta_apply_parameters(local, sta, params);
|
||||
|
||||
rate_control_rate_init(sta, local);
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
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 sta_info *sta;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (mac) {
|
||||
@ -786,9 +751,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *vlansdata;
|
||||
|
||||
if (dev == local->mdev || params->vlan == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* 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;
|
||||
int err;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
|
||||
@ -884,9 +843,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
|
||||
struct mesh_path *mpath;
|
||||
struct sta_info *sta;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!netif_running(dev))
|
||||
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)
|
||||
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct mesh_path *mpath;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
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,
|
||||
struct mpath_info *pinfo)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct mesh_path *mpath;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
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 bss_parameters *params)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
u32 changed = 0;
|
||||
|
||||
if (dev == local->mdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
|
@ -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)
|
||||
{
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct net_device *dev = sta->sdata->dev;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_local *local = sta->sdata->local;
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
u8 *da = sta->sta.addr;
|
||||
static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -573,6 +573,10 @@ enum {
|
||||
/* maximum number of hardware queues we support. */
|
||||
#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
|
||||
|
||||
struct ieee80211_master_priv {
|
||||
struct ieee80211_local *local;
|
||||
};
|
||||
|
||||
struct ieee80211_local {
|
||||
/* embed the driver visible part.
|
||||
* don't cast (use the static inlines below), but we keep
|
||||
@ -720,6 +724,8 @@ struct ieee80211_local {
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
struct local_debugfsdentries {
|
||||
struct dentry *rcdir;
|
||||
struct dentry *rcname;
|
||||
struct dentry *frequency;
|
||||
struct dentry *antenna_sel_tx;
|
||||
struct dentry *antenna_sel_rx;
|
||||
|
@ -625,6 +625,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
||||
/* and set some type-dependent values */
|
||||
sdata->vif.type = type;
|
||||
sdata->dev->hard_start_xmit = ieee80211_subif_start_xmit;
|
||||
sdata->wdev.iftype = type;
|
||||
|
||||
/* only monitor differs */
|
||||
sdata->dev->type = ARPHRD_ETHER;
|
||||
|
@ -106,7 +106,8 @@ static const struct header_ops ieee80211_header_ops = {
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -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);
|
||||
u16 frag, type;
|
||||
__le16 fc;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_tx_status_rtap_hdr *rthdr;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
@ -787,7 +792,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
int result;
|
||||
enum ieee80211_band band;
|
||||
struct net_device *mdev;
|
||||
struct wireless_dev *mwdev;
|
||||
struct ieee80211_master_priv *mpriv;
|
||||
|
||||
/*
|
||||
* generic code guarantees at least one band,
|
||||
@ -829,16 +834,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
if (hw->queues < 4)
|
||||
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,
|
||||
ieee80211_num_queues(hw));
|
||||
if (!mdev)
|
||||
goto fail_mdev_alloc;
|
||||
|
||||
mwdev = netdev_priv(mdev);
|
||||
mdev->ieee80211_ptr = mwdev;
|
||||
mwdev->wiphy = local->hw.wiphy;
|
||||
|
||||
mpriv = netdev_priv(mdev);
|
||||
mpriv->local = local;
|
||||
local->mdev = mdev;
|
||||
|
||||
ieee80211_rx_bss_list_init(local);
|
||||
|
@ -351,7 +351,7 @@ static void ieee80211_mesh_path_timer(unsigned long data)
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
(struct ieee80211_sub_if_data *) data;
|
||||
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);
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ enum mesh_path_flags {
|
||||
*/
|
||||
struct mesh_path {
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 mpp[ETH_ALEN]; /* used for MPP or MAP */
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *next_hop;
|
||||
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);
|
||||
struct mesh_path *mesh_path_lookup(u8 *dst,
|
||||
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 ieee80211_sub_if_data *sdata);
|
||||
void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
|
||||
|
@ -36,6 +36,7 @@ struct mpath_node {
|
||||
};
|
||||
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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
|
||||
* @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
|
||||
*
|
||||
@ -475,11 +589,21 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
|
||||
int mesh_pathtbl_init(void)
|
||||
{
|
||||
mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
|
||||
if (!mesh_paths)
|
||||
return -ENOMEM;
|
||||
mesh_paths->free_node = &mesh_path_node_free;
|
||||
mesh_paths->copy_node = &mesh_path_node_copy;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -511,4 +635,5 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
|
||||
void mesh_pathtbl_unregister(void)
|
||||
{
|
||||
mesh_table_free(mesh_paths, true);
|
||||
mesh_table_free(mpp_paths, true);
|
||||
}
|
||||
|
@ -942,8 +942,8 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
|
||||
disassoc = 1;
|
||||
} else
|
||||
ieee80211_send_probe_req(sdata, ifsta->bssid,
|
||||
local->scan_ssid,
|
||||
local->scan_ssid_len);
|
||||
ifsta->ssid,
|
||||
ifsta->ssid_len);
|
||||
ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
rate_control_rate_init(sta, local);
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
if (elems.wmm_param) {
|
||||
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;
|
||||
mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
|
||||
|
||||
ieee80211_led_assoc(local, true);
|
||||
|
||||
memset(&wrqu, 0, sizeof(wrqu));
|
||||
memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
|
||||
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 |
|
||||
ieee80211_mandatory_rates(local, band);
|
||||
|
||||
rate_control_rate_init(sta, local);
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
if (sta_info_insert(sta))
|
||||
return NULL;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/rtnetlink.h>
|
||||
#include "rate.h"
|
||||
#include "ieee80211_i.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
struct rate_control_alg {
|
||||
struct list_head list;
|
||||
@ -127,19 +128,46 @@ static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
|
||||
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 ieee80211_local *local)
|
||||
{
|
||||
struct dentry *debugfsdir = NULL;
|
||||
struct rate_control_ref *ref;
|
||||
|
||||
ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
|
||||
if (!ref)
|
||||
goto fail_ref;
|
||||
kref_init(&ref->kref);
|
||||
ref->local = local;
|
||||
ref->ops = ieee80211_rate_control_ops_get(name);
|
||||
if (!ref->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)
|
||||
goto fail_priv;
|
||||
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->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);
|
||||
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 sk_buff *skb,
|
||||
struct sta_info *sta, struct sk_buff *skb,
|
||||
struct rate_selection *sel)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct rate_control_ref *ref = local->rate_ctrl;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct sta_info *sta;
|
||||
struct rate_control_ref *ref = sdata->local->rate_ctrl;
|
||||
void *priv_sta = NULL;
|
||||
struct ieee80211_sta *ista = NULL;
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
|
||||
sel->rate_idx = -1;
|
||||
sel->nonerp_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);
|
||||
|
||||
@ -191,13 +236,11 @@ void rate_control_get_rate(struct net_device *dev,
|
||||
if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
|
||||
break;
|
||||
|
||||
if (rate_supported(sta, sband->band, i) &&
|
||||
if (rate_supported(ista, sband->band, i) &&
|
||||
!(rate->flags & IEEE80211_RATE_ERP_G))
|
||||
sel->nonerp_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
|
||||
|
@ -19,77 +19,48 @@
|
||||
#include "ieee80211_i.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 ieee80211_local *local;
|
||||
struct rate_control_ops *ops;
|
||||
void *priv;
|
||||
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
|
||||
* first available algorithm. */
|
||||
struct rate_control_ref *rate_control_alloc(const char *name,
|
||||
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 sk_buff *skb,
|
||||
struct sta_info *sta, struct sk_buff *skb,
|
||||
struct rate_selection *sel);
|
||||
struct rate_control_ref *rate_control_get(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 ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
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,
|
||||
struct ieee80211_local *local)
|
||||
static inline void rate_control_rate_init(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_local *local = sta->sdata->local;
|
||||
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,
|
||||
struct ieee80211_sta *sta,
|
||||
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,
|
||||
void *priv)
|
||||
static inline void rate_control_free_sta(struct sta_info *sta)
|
||||
{
|
||||
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)
|
||||
@ -130,31 +105,6 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
|
||||
#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 */
|
||||
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
|
||||
const char *name);
|
||||
|
@ -124,7 +124,6 @@ struct rc_pid_events_file_info {
|
||||
* struct rc_pid_debugfs_entries - tunable parameters
|
||||
*
|
||||
* Algorithm parameters, tunable via debugfs.
|
||||
* @dir: the debugfs directory for a specific phy
|
||||
* @target: target percentage for failed frames
|
||||
* @sampling_period: error sampling interval in milliseconds
|
||||
* @coeff_p: absolute value of the proportional coefficient
|
||||
@ -143,7 +142,6 @@ struct rc_pid_events_file_info {
|
||||
* ordering of rates)
|
||||
*/
|
||||
struct rc_pid_debugfs_entries {
|
||||
struct dentry *dir;
|
||||
struct dentry *target;
|
||||
struct dentry *sampling_period;
|
||||
struct dentry *coeff_p;
|
||||
|
@ -68,18 +68,14 @@
|
||||
* 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
|
||||
* target. While at it, check that the new rate is valid. */
|
||||
static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
|
||||
struct sta_info *sta, int adj,
|
||||
static void rate_control_pid_adjust_rate(struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta,
|
||||
struct rc_pid_sta_info *spinfo, int adj,
|
||||
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;
|
||||
struct rc_pid_sta_info *spinfo = (void *)sta->rate_ctrl_priv;
|
||||
int cur = spinfo->txrate_idx;
|
||||
|
||||
sdata = sta->sdata;
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
band = sband->band;
|
||||
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,
|
||||
struct ieee80211_local *local,
|
||||
struct sta_info *sta)
|
||||
struct ieee80211_supported_band *sband,
|
||||
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 ieee80211_supported_band *sband;
|
||||
u32 pf;
|
||||
s32 err_avg;
|
||||
u32 err_prop;
|
||||
@ -161,9 +155,6 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
|
||||
int adj, i, j, tmp;
|
||||
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
|
||||
* the sharpening factor on. */
|
||||
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))
|
||||
pf = spinfo->last_pf;
|
||||
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;
|
||||
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;
|
||||
sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
|
||||
si->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
|
||||
>> RC_PID_ARITH_SHIFT;
|
||||
}
|
||||
|
||||
@ -229,43 +224,25 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
|
||||
|
||||
/* Change rate. */
|
||||
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 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 sta_info *sta;
|
||||
struct rc_pid_sta_info *spinfo;
|
||||
struct rc_pid_sta_info *spinfo = priv_sta;
|
||||
unsigned long period;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
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;
|
||||
}
|
||||
if (!spinfo)
|
||||
return;
|
||||
|
||||
/* Ignore all frames that were sent with a different rate than the rate
|
||||
* we currently advise mac80211 to use. */
|
||||
if (info->tx_rate_idx != spinfo->txrate_idx)
|
||||
goto unlock;
|
||||
return;
|
||||
|
||||
spinfo->tx_num_xmit++;
|
||||
|
||||
@ -289,78 +266,63 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
|
||||
if (!period)
|
||||
period = 1;
|
||||
if (time_after(jiffies, spinfo->last_sample + period))
|
||||
rate_control_pid_sample(pinfo, local, sta);
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
rate_control_pid_sample(pinfo, sband, sta, spinfo);
|
||||
}
|
||||
|
||||
static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct sk_buff *skb,
|
||||
struct rate_selection *sel)
|
||||
static void
|
||||
rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
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_sub_if_data *sdata;
|
||||
struct rc_pid_sta_info *spinfo;
|
||||
struct sta_info *sta;
|
||||
struct rc_pid_sta_info *spinfo = priv_sta;
|
||||
int rateidx;
|
||||
u16 fc;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
|
||||
/* Send management frames and broadcast/multicast data using lowest
|
||||
* rate. */
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
|
||||
is_multicast_ether_addr(hdr->addr1) || !sta) {
|
||||
sel->rate_idx = rate_lowest_index(local, sband, sta);
|
||||
rcu_read_unlock();
|
||||
if (!sta || !spinfo ||
|
||||
(fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
|
||||
is_multicast_ether_addr(hdr->addr1)) {
|
||||
sel->rate_idx = rate_lowest_index(sband, sta);
|
||||
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;
|
||||
|
||||
if (rateidx >= sband->n_bitrates)
|
||||
rateidx = sband->n_bitrates - 1;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
sel->rate_idx = rateidx;
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
rate_control_pid_event_tx_rate(
|
||||
&((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
|
||||
rate_control_pid_event_tx_rate(&spinfo->events,
|
||||
rateidx, sband->bitrates[rateidx].bitrate);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void rate_control_pid_rate_init(void *priv, void *priv_sta,
|
||||
struct ieee80211_local *local,
|
||||
struct sta_info *sta)
|
||||
static void
|
||||
rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
|
||||
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
|
||||
* as we need to have IEEE 802.1X auth succeed immediately after assoc..
|
||||
* Until that method is implemented, we will use the lowest supported
|
||||
* 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(local, sband, sta);
|
||||
sta->fail_avg = 0;
|
||||
spinfo->txrate_idx = rate_lowest_index(sband, sta);
|
||||
/* HACK */
|
||||
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_rateinfo *rinfo;
|
||||
@ -371,7 +333,7 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
|
||||
struct rc_pid_debugfs_entries *de;
|
||||
#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);
|
||||
if (!pinfo)
|
||||
@ -426,30 +388,28 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
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->dir, &pinfo->target);
|
||||
debugfsdir, &pinfo->target);
|
||||
de->sampling_period = debugfs_create_u32("sampling_period",
|
||||
S_IRUSR | S_IWUSR, de->dir,
|
||||
S_IRUSR | S_IWUSR, debugfsdir,
|
||||
&pinfo->sampling_period);
|
||||
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->dir, &pinfo->coeff_i);
|
||||
debugfsdir, &pinfo->coeff_i);
|
||||
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",
|
||||
S_IRUSR | S_IWUSR, de->dir,
|
||||
S_IRUSR | S_IWUSR, debugfsdir,
|
||||
&pinfo->smoothing_shift);
|
||||
de->sharpen_factor = debugfs_create_u32("sharpen_factor",
|
||||
S_IRUSR | S_IWUSR, de->dir,
|
||||
S_IRUSR | S_IWUSR, debugfsdir,
|
||||
&pinfo->sharpen_factor);
|
||||
de->sharpen_duration = debugfs_create_u32("sharpen_duration",
|
||||
S_IRUSR | S_IWUSR, de->dir,
|
||||
S_IRUSR | S_IWUSR, debugfsdir,
|
||||
&pinfo->sharpen_duration);
|
||||
de->norm_offset = debugfs_create_u32("norm_offset",
|
||||
S_IRUSR | S_IWUSR, de->dir,
|
||||
S_IRUSR | S_IWUSR, debugfsdir,
|
||||
&pinfo->norm_offset);
|
||||
#endif
|
||||
|
||||
@ -471,7 +431,6 @@ static void rate_control_pid_free(void *priv)
|
||||
debugfs_remove(de->coeff_p);
|
||||
debugfs_remove(de->sampling_period);
|
||||
debugfs_remove(de->target);
|
||||
debugfs_remove(de->dir);
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
@ -500,10 +460,10 @@ static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp)
|
||||
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(spinfo);
|
||||
kfree(priv_sta);
|
||||
}
|
||||
|
||||
static struct rate_control_ops mac80211_rcpid = {
|
||||
|
@ -650,32 +650,28 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
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);
|
||||
|
||||
sdata = sta->sdata;
|
||||
|
||||
atomic_inc(&sdata->bss->num_sta_ps);
|
||||
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
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 */
|
||||
}
|
||||
|
||||
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;
|
||||
int sent = 0;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_tx_info *info;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
sdata = sta->sdata;
|
||||
|
||||
atomic_dec(&sdata->bss->num_sta_ps);
|
||||
|
||||
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
|
||||
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 */
|
||||
|
||||
/* 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++;
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
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);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
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)
|
||||
{
|
||||
struct sta_info *sta = rx->sta;
|
||||
struct net_device *dev = rx->dev;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
|
||||
if (!sta)
|
||||
@ -757,10 +752,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
||||
* exchange sequence */
|
||||
if (test_sta_flags(sta, WLAN_STA_PS) &&
|
||||
!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) &&
|
||||
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
|
||||
@ -1112,10 +1107,6 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
|
||||
|
||||
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
|
||||
* header
|
||||
* 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 &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
|
||||
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;
|
||||
case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION ||
|
||||
@ -1398,6 +1398,25 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
/* illegal frame */
|
||||
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)
|
||||
return RX_CONTINUE;
|
||||
|
||||
@ -1538,7 +1557,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
*/
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||
return RX_DROP_MONITOR;
|
||||
return RX_CONTINUE;
|
||||
|
||||
switch (mgmt->u.action.category) {
|
||||
case WLAN_CATEGORY_BACK:
|
||||
|
@ -93,8 +93,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
/* protected by RCU */
|
||||
static struct sta_info *__sta_info_find(struct ieee80211_local *local,
|
||||
const u8 *addr)
|
||||
struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
@ -107,12 +106,6 @@ static struct sta_info *__sta_info_find(struct ieee80211_local *local,
|
||||
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 net_device *dev)
|
||||
{
|
||||
@ -146,7 +139,7 @@ static void __sta_info_free(struct ieee80211_local *local,
|
||||
{
|
||||
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);
|
||||
|
||||
#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_priv = rate_control_alloc_sta(sta->rate_ctrl,
|
||||
gfp);
|
||||
&sta->sta, gfp);
|
||||
if (!sta->rate_ctrl_priv) {
|
||||
rate_control_put(sta->rate_ctrl);
|
||||
kfree(sta);
|
||||
@ -308,7 +301,7 @@ int sta_info_insert(struct sta_info *sta)
|
||||
|
||||
spin_lock_irqsave(&local->sta_lock, flags);
|
||||
/* 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);
|
||||
err = -EEXIST;
|
||||
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,
|
||||
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)
|
||||
return NULL;
|
||||
|
@ -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.
|
||||
*/
|
||||
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!
|
||||
*/
|
||||
|
@ -165,11 +165,10 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
||||
return cpu_to_le16(dur);
|
||||
}
|
||||
|
||||
static int inline is_ieee80211_device(struct net_device *dev,
|
||||
struct net_device *master)
|
||||
static int inline is_ieee80211_device(struct ieee80211_local *local,
|
||||
struct net_device *dev)
|
||||
{
|
||||
return (wdev_priv(dev->ieee80211_ptr) ==
|
||||
wdev_priv(master->ieee80211_ptr));
|
||||
return local == wdev_priv(dev->ieee80211_ptr);
|
||||
}
|
||||
|
||||
/* 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];
|
||||
|
||||
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)
|
||||
tx->sta->last_txrate_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
|
||||
*/
|
||||
static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
|
||||
struct sk_buff *skb,
|
||||
struct net_device *mdev)
|
||||
static int ieee80211_tx_prepare(struct ieee80211_local *local,
|
||||
struct ieee80211_tx_data *tx,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev;
|
||||
|
||||
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 = NULL;
|
||||
}
|
||||
@ -1258,6 +1258,8 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
|
||||
int ieee80211_master_start_xmit(struct sk_buff *skb,
|
||||
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_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct net_device *odev = NULL;
|
||||
@ -1273,7 +1275,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
|
||||
|
||||
if (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);
|
||||
odev = NULL;
|
||||
}
|
||||
@ -1449,8 +1451,8 @@ fail:
|
||||
int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int ret = 1, head_need;
|
||||
u16 ethertype, hdrlen, meshhdrlen = 0;
|
||||
__le16 fc;
|
||||
@ -1462,7 +1464,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct sta_info *sta;
|
||||
u32 sta_flags = 0;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (unlikely(skb->len < ETH_HLEN)) {
|
||||
ret = 0;
|
||||
goto fail;
|
||||
@ -1498,18 +1499,50 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
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) {
|
||||
/* Do not send frames with mesh_ttl == 0 */
|
||||
sdata->u.mesh.mshstats.dropped_frames_ttl++;
|
||||
ret = 0;
|
||||
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;
|
||||
break;
|
||||
#endif
|
||||
@ -1923,7 +1956,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
||||
skb->do_not_encrypt = 1;
|
||||
|
||||
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 (net_ratelimit()) {
|
||||
@ -2032,7 +2065,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
|
||||
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
}
|
||||
|
||||
if (!ieee80211_tx_prepare(&tx, skb, local->mdev))
|
||||
if (!ieee80211_tx_prepare(local, &tx, skb))
|
||||
break;
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
@ -29,113 +29,11 @@ MODULE_AUTHOR("Johannes Berg");
|
||||
MODULE_LICENSE("GPL");
|
||||
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
|
||||
* only read the list, and that can happen quite
|
||||
* often because we need to do it for each command */
|
||||
LIST_HEAD(cfg80211_drv_list);
|
||||
DEFINE_MUTEX(cfg80211_drv_mutex);
|
||||
static int wiphy_counter;
|
||||
|
||||
/* for debugfs */
|
||||
static struct dentry *ieee80211_debugfs_dir;
|
||||
@ -307,6 +205,8 @@ out_unlock:
|
||||
|
||||
struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
|
||||
{
|
||||
static int wiphy_counter;
|
||||
|
||||
struct cfg80211_registered_device *drv;
|
||||
int alloc_size;
|
||||
|
||||
@ -323,21 +223,18 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
|
||||
|
||||
mutex_lock(&cfg80211_drv_mutex);
|
||||
|
||||
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);
|
||||
drv->idx = wiphy_counter++;
|
||||
|
||||
if (unlikely(drv->idx < 0)) {
|
||||
wiphy_counter--;
|
||||
mutex_unlock(&cfg80211_drv_mutex);
|
||||
/* ugh, wrapped! */
|
||||
kfree(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&cfg80211_drv_mutex);
|
||||
|
||||
/* give it a proper name */
|
||||
snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE,
|
||||
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);
|
||||
|
||||
WARN_ON(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_UNSPECIFIED);
|
||||
|
||||
switch (state) {
|
||||
case NETDEV_REGISTER:
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
@ -514,34 +413,10 @@ static struct notifier_block cfg80211_netdev_notifier = {
|
||||
.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)
|
||||
{
|
||||
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();
|
||||
if (err)
|
||||
goto out_fail_sysfs;
|
||||
@ -560,25 +435,6 @@ static int cfg80211_init(void)
|
||||
if (err)
|
||||
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;
|
||||
|
||||
out_fail_reg:
|
||||
|
@ -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_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);
|
||||
|
||||
nla_put_failure:
|
||||
@ -418,41 +418,56 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
int err, ifindex;
|
||||
enum nl80211_iftype type;
|
||||
struct net_device *dev;
|
||||
u32 flags;
|
||||
u32 _flags, *flags = NULL;
|
||||
|
||||
memset(¶ms, 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);
|
||||
if (err)
|
||||
return err;
|
||||
ifindex = dev->ifindex;
|
||||
type = dev->ieee80211_ptr->iftype;
|
||||
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 ||
|
||||
!(drv->wiphy.interface_modes & (1 << type))) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (type == NL80211_IFTYPE_MESH_POINT &&
|
||||
info->attrs[NL80211_ATTR_MESH_ID]) {
|
||||
if (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_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();
|
||||
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,
|
||||
type, err ? NULL : &flags, ¶ms);
|
||||
type, flags, ¶ms);
|
||||
|
||||
dev = __dev_get_by_index(&init_net, ifindex);
|
||||
WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type));
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
unlock:
|
||||
|
@ -42,6 +42,18 @@
|
||||
#include "core.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 */
|
||||
static struct platform_device *reg_pdev;
|
||||
|
||||
@ -51,7 +63,156 @@ static u32 supported_bandwidths[] = {
|
||||
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(®ulatory_requests));
|
||||
|
||||
reset_regdomains();
|
||||
|
||||
cfg80211_world_regdom = rd;
|
||||
cfg80211_regdomain = rd;
|
||||
}
|
||||
|
||||
bool is_world_regdom(const char *alpha2)
|
||||
{
|
||||
if (!alpha2)
|
||||
return false;
|
||||
@ -60,7 +221,7 @@ bool is_world_regdom(char *alpha2)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_alpha2_set(char *alpha2)
|
||||
static bool is_alpha2_set(const char *alpha2)
|
||||
{
|
||||
if (!alpha2)
|
||||
return false;
|
||||
@ -77,7 +238,7 @@ static bool is_alpha_upper(char letter)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_unknown_alpha2(char *alpha2)
|
||||
static bool is_unknown_alpha2(const char *alpha2)
|
||||
{
|
||||
if (!alpha2)
|
||||
return false;
|
||||
@ -88,7 +249,7 @@ static bool is_unknown_alpha2(char *alpha2)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_an_alpha2(char *alpha2)
|
||||
static bool is_an_alpha2(const char *alpha2)
|
||||
{
|
||||
if (!alpha2)
|
||||
return false;
|
||||
@ -97,7 +258,7 @@ static bool is_an_alpha2(char *alpha2)
|
||||
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)
|
||||
return false;
|
||||
@ -107,7 +268,7 @@ static bool alpha2_equal(char *alpha2_x, char *alpha2_y)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool regdom_changed(char *alpha2)
|
||||
static bool regdom_changed(const char *alpha2)
|
||||
{
|
||||
if (!cfg80211_regdomain)
|
||||
return true;
|
||||
@ -130,12 +291,8 @@ static int call_crda(const char *alpha2)
|
||||
printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n",
|
||||
alpha2[0], alpha2[1]);
|
||||
else
|
||||
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
|
||||
return -EINVAL;
|
||||
#else
|
||||
printk(KERN_INFO "cfg80211: Calling CRDA to update world "
|
||||
"regulatory domain\n");
|
||||
#endif
|
||||
|
||||
country_env[8] = alpha2[0];
|
||||
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 *req;
|
||||
@ -254,16 +411,16 @@ static bool __reg_is_valid_request(char *alpha2,
|
||||
}
|
||||
|
||||
/* 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;
|
||||
return __reg_is_valid_request(alpha2, &request);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!rd->n_reg_rules)
|
||||
@ -494,12 +651,12 @@ unlock_and_exit:
|
||||
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;
|
||||
struct ieee80211_reg_rule *reg_rule = NULL;
|
||||
struct ieee80211_freq_range *freq_range = NULL;
|
||||
struct ieee80211_power_rule *power_rule = NULL;
|
||||
const struct ieee80211_reg_rule *reg_rule = NULL;
|
||||
const struct ieee80211_freq_range *freq_range = NULL;
|
||||
const struct ieee80211_power_rule *power_rule = NULL;
|
||||
|
||||
printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), "
|
||||
"(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))
|
||||
@ -548,85 +705,25 @@ static void print_regdomain(struct ieee80211_regdomain *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",
|
||||
rd->alpha2[0], rd->alpha2[1]);
|
||||
print_rd_rules(rd);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
|
||||
|
||||
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(®ulatory_requests));
|
||||
|
||||
reset_regdomains();
|
||||
|
||||
cfg80211_world_regdom = rd;
|
||||
cfg80211_regdomain = rd;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __set_regdom(struct ieee80211_regdomain *rd)
|
||||
static int __set_regdom(const struct ieee80211_regdomain *rd)
|
||||
{
|
||||
struct regulatory_request *request = NULL;
|
||||
|
||||
/* 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 (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
|
||||
return -EINVAL;
|
||||
update_world_regdomain(rd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
|
||||
!is_unknown_alpha2(rd->alpha2))
|
||||
@ -635,15 +732,10 @@ static int __set_regdom(struct ieee80211_regdomain *rd)
|
||||
if (list_empty(®ulatory_requests))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
|
||||
/* Static "US" and "JP" will be overridden, but just once */
|
||||
/* allow overriding the static definitions if CRDA is present */
|
||||
if (!is_old_static_regdom(cfg80211_regdomain) &&
|
||||
!regdom_changed(rd->alpha2))
|
||||
!regdom_changed(rd->alpha2))
|
||||
return -EINVAL;
|
||||
#else
|
||||
if (!regdom_changed(rd->alpha2))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
/* Now lets set the regulatory domain, update all driver channels
|
||||
* 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)))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
|
||||
reset_regdomains_static();
|
||||
#else
|
||||
reset_regdomains();
|
||||
#endif
|
||||
|
||||
/* Country IE parsing coming soon */
|
||||
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
|
||||
* kmalloc'd the rd structure. If this calls fails you should kfree()
|
||||
* 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;
|
||||
int r;
|
||||
@ -735,25 +823,50 @@ int set_regdom(struct ieee80211_regdomain *rd)
|
||||
|
||||
int regulatory_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
|
||||
if (IS_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;
|
||||
}
|
||||
|
||||
void regulatory_exit(void)
|
||||
{
|
||||
struct regulatory_request *req, *req_tmp;
|
||||
|
||||
mutex_lock(&cfg80211_drv_mutex);
|
||||
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
|
||||
reset_regdomains_static();
|
||||
#else
|
||||
|
||||
reset_regdomains();
|
||||
#endif
|
||||
|
||||
list_for_each_entry_safe(req, req_tmp, ®ulatory_requests, list) {
|
||||
list_del(&req->list);
|
||||
kfree(req);
|
||||
}
|
||||
platform_device_unregister(reg_pdev);
|
||||
|
||||
mutex_unlock(&cfg80211_drv_mutex);
|
||||
}
|
||||
|
@ -1,44 +1,13 @@
|
||||
#ifndef __NET_WIRELESS_REG_H
|
||||
#define __NET_WIRELESS_REG_H
|
||||
|
||||
extern const struct ieee80211_regdomain world_regdom;
|
||||
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
|
||||
extern const struct ieee80211_regdomain us_regdom;
|
||||
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);
|
||||
extern struct mutex cfg80211_reg_mutex;
|
||||
bool is_world_regdom(const char *alpha2);
|
||||
bool reg_is_valid_request(const char *alpha2);
|
||||
|
||||
int regulatory_init(void);
|
||||
void regulatory_exit(void);
|
||||
|
||||
void print_regdomain_info(struct ieee80211_regdomain *);
|
||||
|
||||
/* If a char is A-Z */
|
||||
#define IS_ALPHA(letter) (letter >= 65 && letter <= 90)
|
||||
int set_regdom(const struct ieee80211_regdomain *rd);
|
||||
|
||||
#endif /* __NET_WIRELESS_REG_H */
|
||||
|
Loading…
Reference in New Issue
Block a user