forked from Minki/linux
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
d346f49d0b
@ -188,3 +188,27 @@ Then in some part of your code after your wiphy has been registered:
|
||||
&mydriver_jp_regdom.reg_rules[i],
|
||||
sizeof(struct ieee80211_reg_rule));
|
||||
regulatory_struct_hint(rd);
|
||||
|
||||
Statically compiled regulatory database
|
||||
---------------------------------------
|
||||
|
||||
In most situations the userland solution using CRDA as described
|
||||
above is the preferred solution. However in some cases a set of
|
||||
rules built into the kernel itself may be desirable. To account
|
||||
for this situation, a configuration option has been provided
|
||||
(i.e. CONFIG_CFG80211_INTERNAL_REGDB). With this option enabled,
|
||||
the wireless database information contained in net/wireless/db.txt is
|
||||
used to generate a data structure encoded in net/wireless/regdb.c.
|
||||
That option also enables code in net/wireless/reg.c which queries
|
||||
the data in regdb.c as an alternative to using CRDA.
|
||||
|
||||
The file net/wireless/db.txt should be kept up-to-date with the db.txt
|
||||
file available in the git repository here:
|
||||
|
||||
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
|
||||
|
||||
Again, most users in most situations should be using the CRDA package
|
||||
provided with their distribution, and in most other situations users
|
||||
should be building and using CRDA on their own rather than using
|
||||
this option. If you are not absolutely sure that you should be using
|
||||
CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_.
|
||||
|
@ -109,7 +109,6 @@ struct ar9170_rxstream_mpdu_merge {
|
||||
bool has_plcp;
|
||||
};
|
||||
|
||||
#define AR9170_NUM_MAX_BA_RETRY 5
|
||||
#define AR9170_NUM_TID 16
|
||||
#define WME_BA_BMP_SIZE 64
|
||||
#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
|
||||
@ -143,7 +142,6 @@ struct ar9170_sta_tid {
|
||||
u16 tid;
|
||||
enum ar9170_tid_state state;
|
||||
bool active;
|
||||
u8 retry;
|
||||
};
|
||||
|
||||
#define AR9170_QUEUE_TIMEOUT 64
|
||||
@ -154,6 +152,8 @@ struct ar9170_sta_tid {
|
||||
|
||||
#define AR9170_NUM_TX_STATUS 128
|
||||
#define AR9170_NUM_TX_AGG_MAX 30
|
||||
#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH
|
||||
#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10)
|
||||
|
||||
struct ar9170 {
|
||||
struct ieee80211_hw *hw;
|
||||
@ -248,13 +248,8 @@ struct ar9170_sta_info {
|
||||
unsigned int ampdu_max_len;
|
||||
};
|
||||
|
||||
#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)
|
||||
#define AR9170_TX_FLAG_NO_ACK BIT(1)
|
||||
#define AR9170_TX_FLAG_BLOCK_ACK BIT(2)
|
||||
|
||||
struct ar9170_tx_info {
|
||||
unsigned long timeout;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED)
|
||||
|
@ -276,6 +276,7 @@ struct ar9170_tx_control {
|
||||
#define AR9170_TX_MAC_RATE_PROBE 0x8000
|
||||
|
||||
/* either-or */
|
||||
#define AR9170_TX_PHY_MOD_MASK 0x00000003
|
||||
#define AR9170_TX_PHY_MOD_CCK 0x00000000
|
||||
#define AR9170_TX_PHY_MOD_OFDM 0x00000001
|
||||
#define AR9170_TX_PHY_MOD_HT 0x00000002
|
||||
|
@ -117,7 +117,7 @@ int ar9170_set_qos(struct ar9170 *ar)
|
||||
ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,
|
||||
ar->edcf[0].txop | ar->edcf[1].txop << 16);
|
||||
ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP,
|
||||
ar->edcf[1].txop | ar->edcf[3].txop << 16);
|
||||
ar->edcf[2].txop | ar->edcf[3].txop << 16);
|
||||
|
||||
ar9170_regwrite_finish();
|
||||
|
||||
|
@ -194,12 +194,15 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb)
|
||||
return ar9170_get_seq_h((void *) txc->frame_data);
|
||||
}
|
||||
|
||||
static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr)
|
||||
{
|
||||
return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||||
}
|
||||
|
||||
static inline u16 ar9170_get_tid(struct sk_buff *skb)
|
||||
{
|
||||
struct ar9170_tx_control *txc = (void *) skb->data;
|
||||
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
|
||||
|
||||
return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||||
return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);
|
||||
}
|
||||
|
||||
#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff)
|
||||
@ -213,10 +216,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
|
||||
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
|
||||
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
|
||||
|
||||
printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
|
||||
printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
|
||||
"mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
|
||||
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
|
||||
ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
|
||||
ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
|
||||
le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
|
||||
jiffies_to_msecs(arinfo->timeout - jiffies));
|
||||
}
|
||||
@ -430,7 +433,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
|
||||
spin_lock_irqsave(&ar->tx_stats_lock, flags);
|
||||
ar->tx_stats[queue].len--;
|
||||
|
||||
if (skb_queue_empty(&ar->tx_pending[queue])) {
|
||||
if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {
|
||||
#ifdef AR9170_QUEUE_STOP_DEBUG
|
||||
printk(KERN_DEBUG "%s: wake queue %d\n",
|
||||
wiphy_name(ar->hw->wiphy), queue);
|
||||
@ -440,22 +443,17 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
|
||||
}
|
||||
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
|
||||
|
||||
if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
|
||||
ar9170_tx_ampdu_callback(ar, skb);
|
||||
} else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
|
||||
arinfo->timeout = jiffies +
|
||||
msecs_to_jiffies(AR9170_TX_TIMEOUT);
|
||||
|
||||
skb_queue_tail(&ar->tx_status[queue], skb);
|
||||
} else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) {
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
|
||||
ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
|
||||
} else {
|
||||
#ifdef AR9170_QUEUE_DEBUG
|
||||
printk(KERN_DEBUG "%s: unsupported frame flags!\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
ar9170_print_txheader(ar, skb);
|
||||
#endif /* AR9170_QUEUE_DEBUG */
|
||||
dev_kfree_skb_any(skb);
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
|
||||
ar9170_tx_ampdu_callback(ar, skb);
|
||||
} else {
|
||||
arinfo->timeout = jiffies +
|
||||
msecs_to_jiffies(AR9170_TX_TIMEOUT);
|
||||
|
||||
skb_queue_tail(&ar->tx_status[queue], skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ar->tx_stats[queue].len &&
|
||||
@ -1407,17 +1405,6 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
|
||||
(is_valid_ether_addr(ieee80211_get_DA(hdr)))) {
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
|
||||
if (unlikely(!info->control.sta))
|
||||
goto err_out;
|
||||
|
||||
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
|
||||
arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
|
||||
/*
|
||||
* WARNING:
|
||||
* Putting the QoS queue bits into an unexplored territory is
|
||||
@ -1431,12 +1418,17 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
|
||||
|
||||
txc->phy_control |=
|
||||
cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
|
||||
arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK;
|
||||
} else {
|
||||
arinfo->flags = AR9170_TX_FLAG_NO_ACK;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
|
||||
if (unlikely(!info->control.sta))
|
||||
goto err_out;
|
||||
|
||||
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
|
||||
} else {
|
||||
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
@ -1671,8 +1663,7 @@ static bool ar9170_tx_ampdu(struct ar9170 *ar)
|
||||
* tell the FW/HW that this is the last frame,
|
||||
* that way it will wait for the immediate block ack.
|
||||
*/
|
||||
if (likely(skb_peek_tail(&agg)))
|
||||
ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
|
||||
ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
|
||||
|
||||
#ifdef AR9170_TXAGG_DEBUG
|
||||
printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
|
||||
@ -1716,6 +1707,21 @@ static void ar9170_tx(struct ar9170 *ar)
|
||||
|
||||
for (i = 0; i < __AR9170_NUM_TXQ; i++) {
|
||||
spin_lock_irqsave(&ar->tx_stats_lock, flags);
|
||||
frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
|
||||
skb_queue_len(&ar->tx_pending[i]));
|
||||
|
||||
if (remaining_space < frames) {
|
||||
#ifdef AR9170_QUEUE_DEBUG
|
||||
printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
|
||||
"remaining slots:%d, needed:%d\n",
|
||||
wiphy_name(ar->hw->wiphy), i, remaining_space,
|
||||
frames);
|
||||
#endif /* AR9170_QUEUE_DEBUG */
|
||||
frames = remaining_space;
|
||||
}
|
||||
|
||||
ar->tx_stats[i].len += frames;
|
||||
ar->tx_stats[i].count += frames;
|
||||
if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
|
||||
#ifdef AR9170_QUEUE_DEBUG
|
||||
printk(KERN_DEBUG "%s: queue %d full\n",
|
||||
@ -1733,25 +1739,8 @@ static void ar9170_tx(struct ar9170 *ar)
|
||||
__ar9170_dump_txstats(ar);
|
||||
#endif /* AR9170_QUEUE_STOP_DEBUG */
|
||||
ieee80211_stop_queue(ar->hw, i);
|
||||
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
|
||||
continue;
|
||||
}
|
||||
|
||||
frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
|
||||
skb_queue_len(&ar->tx_pending[i]));
|
||||
|
||||
if (remaining_space < frames) {
|
||||
#ifdef AR9170_QUEUE_DEBUG
|
||||
printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
|
||||
"remaining slots:%d, needed:%d\n",
|
||||
wiphy_name(ar->hw->wiphy), i, remaining_space,
|
||||
frames);
|
||||
#endif /* AR9170_QUEUE_DEBUG */
|
||||
frames = remaining_space;
|
||||
}
|
||||
|
||||
ar->tx_stats[i].len += frames;
|
||||
ar->tx_stats[i].count += frames;
|
||||
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
|
||||
|
||||
if (!frames)
|
||||
@ -1773,7 +1762,7 @@ static void ar9170_tx(struct ar9170 *ar)
|
||||
arinfo->timeout = jiffies +
|
||||
msecs_to_jiffies(AR9170_TX_TIMEOUT);
|
||||
|
||||
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
atomic_inc(&ar->tx_ampdu_pending);
|
||||
|
||||
#ifdef AR9170_QUEUE_DEBUG
|
||||
@ -1784,7 +1773,7 @@ static void ar9170_tx(struct ar9170 *ar)
|
||||
|
||||
err = ar->tx(ar, skb);
|
||||
if (unlikely(err)) {
|
||||
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
atomic_dec(&ar->tx_ampdu_pending);
|
||||
|
||||
frames_failed++;
|
||||
@ -2366,7 +2355,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
|
||||
sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
|
||||
sta_info->agg[i].active = false;
|
||||
sta_info->agg[i].ssn = 0;
|
||||
sta_info->agg[i].retry = 0;
|
||||
sta_info->agg[i].tid = i;
|
||||
INIT_LIST_HEAD(&sta_info->agg[i].list);
|
||||
skb_queue_head_init(&sta_info->agg[i].queue);
|
||||
|
@ -84,6 +84,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
|
||||
{ USB_DEVICE(0x0cde, 0x0023) },
|
||||
/* Z-Com UB82 ABG */
|
||||
{ USB_DEVICE(0x0cde, 0x0026) },
|
||||
/* Sphairon Homelink 1202 */
|
||||
{ USB_DEVICE(0x0cde, 0x0027) },
|
||||
/* Arcadyan WN7512 */
|
||||
{ USB_DEVICE(0x083a, 0xf522) },
|
||||
/* Planex GWUS300 */
|
||||
|
@ -453,7 +453,6 @@ struct ath_softc {
|
||||
int irq;
|
||||
spinlock_t sc_resetlock;
|
||||
spinlock_t sc_serial_rw;
|
||||
spinlock_t ani_lock;
|
||||
spinlock_t sc_pm_lock;
|
||||
struct mutex mutex;
|
||||
|
||||
|
@ -289,23 +289,49 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
|
||||
if (sc->cur_rate_table == NULL)
|
||||
return 0;
|
||||
|
||||
max = 80 + sc->cur_rate_table->rate_cnt * 64;
|
||||
max = 80 + sc->cur_rate_table->rate_cnt * 1024;
|
||||
buf = kmalloc(max + 1, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
buf[max] = 0;
|
||||
|
||||
len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success",
|
||||
"Retries", "XRetries", "PER");
|
||||
len += sprintf(buf, "%6s %6s %6s "
|
||||
"%10s %10s %10s %10s\n",
|
||||
"HT", "MCS", "Rate",
|
||||
"Success", "Retries", "XRetries", "PER");
|
||||
|
||||
for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
|
||||
u32 ratekbps = sc->cur_rate_table->info[i].ratekbps;
|
||||
struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i];
|
||||
char mcs[5];
|
||||
char htmode[5];
|
||||
int used_mcs = 0, used_htmode = 0;
|
||||
|
||||
if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) {
|
||||
used_mcs = snprintf(mcs, 5, "%d",
|
||||
sc->cur_rate_table->info[i].ratecode);
|
||||
|
||||
if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy))
|
||||
used_htmode = snprintf(htmode, 5, "HT40");
|
||||
else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy))
|
||||
used_htmode = snprintf(htmode, 5, "HT20");
|
||||
else
|
||||
used_htmode = snprintf(htmode, 5, "????");
|
||||
}
|
||||
|
||||
mcs[used_mcs] = '\0';
|
||||
htmode[used_htmode] = '\0';
|
||||
|
||||
len += snprintf(buf + len, max - len,
|
||||
"%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000,
|
||||
(ratekbps % 1000) / 100, stats->success,
|
||||
stats->retries, stats->xretries,
|
||||
"%6s %6s %3u.%d: "
|
||||
"%10u %10u %10u %10u\n",
|
||||
htmode,
|
||||
mcs,
|
||||
ratekbps / 1000,
|
||||
(ratekbps % 1000) / 100,
|
||||
stats->success,
|
||||
stats->retries,
|
||||
stats->xretries,
|
||||
stats->per);
|
||||
}
|
||||
|
||||
|
@ -343,30 +343,6 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *ath9k_hw_devname(u16 devid)
|
||||
{
|
||||
switch (devid) {
|
||||
case AR5416_DEVID_PCI:
|
||||
return "Atheros 5416";
|
||||
case AR5416_DEVID_PCIE:
|
||||
return "Atheros 5418";
|
||||
case AR9160_DEVID_PCI:
|
||||
return "Atheros 9160";
|
||||
case AR5416_AR9100_DEVID:
|
||||
return "Atheros 9100";
|
||||
case AR9280_DEVID_PCI:
|
||||
case AR9280_DEVID_PCIE:
|
||||
return "Atheros 9280";
|
||||
case AR9285_DEVID_PCIE:
|
||||
return "Atheros 9285";
|
||||
case AR5416_DEVID_AR9287_PCI:
|
||||
case AR5416_DEVID_AR9287_PCIE:
|
||||
return "Atheros 9287";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ath9k_hw_init_config(struct ath_hw *ah)
|
||||
{
|
||||
int i;
|
||||
@ -392,7 +368,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
|
||||
ah->config.spurchans[i][1] = AR_NO_SPUR;
|
||||
}
|
||||
|
||||
ah->config.intr_mitigation = true;
|
||||
ah->config.rx_intr_mitigation = true;
|
||||
|
||||
/*
|
||||
* We need this for PCI devices only (Cardbus, PCI, miniPCI)
|
||||
@ -1184,7 +1160,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
|
||||
AR_IMR_RXORN |
|
||||
AR_IMR_BCNMISC;
|
||||
|
||||
if (ah->config.intr_mitigation)
|
||||
if (ah->config.rx_intr_mitigation)
|
||||
ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
|
||||
else
|
||||
ah->mask_reg |= AR_IMR_RXOK;
|
||||
@ -1266,12 +1242,6 @@ static void ath9k_hw_init_user_settings(struct ath_hw *ah)
|
||||
ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
|
||||
}
|
||||
|
||||
const char *ath9k_hw_probe(u16 vendorid, u16 devid)
|
||||
{
|
||||
return vendorid == ATHEROS_VENDOR_ID ?
|
||||
ath9k_hw_devname(devid) : NULL;
|
||||
}
|
||||
|
||||
void ath9k_hw_detach(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
@ -2121,7 +2091,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
|
||||
REG_WRITE(ah, AR_OBS, 8);
|
||||
|
||||
if (ah->config.intr_mitigation) {
|
||||
if (ah->config.rx_intr_mitigation) {
|
||||
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
|
||||
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
|
||||
}
|
||||
@ -2781,7 +2751,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
|
||||
|
||||
*masked = isr & ATH9K_INT_COMMON;
|
||||
|
||||
if (ah->config.intr_mitigation) {
|
||||
if (ah->config.rx_intr_mitigation) {
|
||||
if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
|
||||
*masked |= ATH9K_INT_RX;
|
||||
}
|
||||
@ -2914,7 +2884,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
|
||||
}
|
||||
if (ints & ATH9K_INT_RX) {
|
||||
mask |= AR_IMR_RXERR;
|
||||
if (ah->config.intr_mitigation)
|
||||
if (ah->config.rx_intr_mitigation)
|
||||
mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
|
||||
else
|
||||
mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
|
||||
|
@ -212,7 +212,7 @@ struct ath9k_ops_config {
|
||||
u32 cck_trig_low;
|
||||
u32 enable_ani;
|
||||
int serialize_regmode;
|
||||
bool intr_mitigation;
|
||||
bool rx_intr_mitigation;
|
||||
#define SPUR_DISABLE 0
|
||||
#define SPUR_ENABLE_IOCTL 1
|
||||
#define SPUR_ENABLE_EEPROM 2
|
||||
|
@ -363,14 +363,6 @@ static void ath_ani_calibrate(unsigned long data)
|
||||
short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
|
||||
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
|
||||
|
||||
/*
|
||||
* don't calibrate when we're scanning.
|
||||
* we are most likely not on our home channel.
|
||||
*/
|
||||
spin_lock(&sc->ani_lock);
|
||||
if (sc->sc_flags & SC_OP_SCANNING)
|
||||
goto set_timer;
|
||||
|
||||
/* Only calibrate if awake */
|
||||
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
|
||||
goto set_timer;
|
||||
@ -437,7 +429,6 @@ static void ath_ani_calibrate(unsigned long data)
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
set_timer:
|
||||
spin_unlock(&sc->ani_lock);
|
||||
/*
|
||||
* Set timer interval based on previous results.
|
||||
* The interval must be the shortest necessary to satisfy ANI,
|
||||
@ -1610,7 +1601,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
spin_lock_init(&sc->wiphy_lock);
|
||||
spin_lock_init(&sc->sc_resetlock);
|
||||
spin_lock_init(&sc->sc_serial_rw);
|
||||
spin_lock_init(&sc->ani_lock);
|
||||
spin_lock_init(&sc->sc_pm_lock);
|
||||
mutex_init(&sc->mutex);
|
||||
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
|
||||
@ -3119,6 +3109,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
if (ath9k_wiphy_scanning(sc)) {
|
||||
@ -3134,10 +3125,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
|
||||
|
||||
aphy->state = ATH_WIPHY_SCAN;
|
||||
ath9k_wiphy_pause_all_forced(sc, aphy);
|
||||
|
||||
spin_lock_bh(&sc->ani_lock);
|
||||
sc->sc_flags |= SC_OP_SCANNING;
|
||||
spin_unlock_bh(&sc->ani_lock);
|
||||
del_timer_sync(&common->ani.timer);
|
||||
cancel_delayed_work_sync(&sc->tx_complete_work);
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
@ -3145,13 +3135,14 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
spin_lock_bh(&sc->ani_lock);
|
||||
aphy->state = ATH_WIPHY_ACTIVE;
|
||||
sc->sc_flags &= ~SC_OP_SCANNING;
|
||||
sc->sc_flags |= SC_OP_FULL_RESET;
|
||||
spin_unlock_bh(&sc->ani_lock);
|
||||
ath_start_ani(common);
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
||||
ath_beacon_config(sc, NULL);
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
@ -57,6 +57,10 @@ enum {
|
||||
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|
||||
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|
||||
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
|
||||
#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \
|
||||
|| (_phy == WLAN_RC_PHY_HT_20_DS) \
|
||||
|| (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
|
||||
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI))
|
||||
#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \
|
||||
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|
||||
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
|
||||
|
@ -2618,6 +2618,15 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
|
||||
int events = 0;
|
||||
u16 ev;
|
||||
|
||||
/* Detect early interrupt before driver is fully configued */
|
||||
if (!dev->base_addr) {
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
|
||||
dev->name);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
|
@ -105,6 +105,7 @@ static struct iwl_lib_ops iwl1000_lib = {
|
||||
.load_ucode = iwl5000_load_ucode,
|
||||
.dump_nic_event_log = iwl_dump_nic_event_log,
|
||||
.dump_nic_error_log = iwl_dump_nic_error_log,
|
||||
.dump_csr = iwl_dump_csr,
|
||||
.init_alive_start = iwl5000_init_alive_start,
|
||||
.alive_notify = iwl5000_alive_notify,
|
||||
.send_tx_power = iwl5000_send_tx_power,
|
||||
@ -140,7 +141,7 @@ static struct iwl_lib_ops iwl1000_lib = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct iwl_ops iwl1000_ops = {
|
||||
static const struct iwl_ops iwl1000_ops = {
|
||||
.ucode = &iwl5000_ucode,
|
||||
.lib = &iwl1000_lib,
|
||||
.hcmd = &iwl5000_hcmd,
|
||||
@ -173,7 +174,6 @@ struct iwl_cfg iwl1000_bgn_cfg = {
|
||||
.use_rts_for_ht = true, /* use rts/cts protection */
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.support_ct_kill_exit = true,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl1000_bg_cfg = {
|
||||
|
@ -2810,7 +2810,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
|
||||
.rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
|
||||
};
|
||||
|
||||
static struct iwl_ops iwl3945_ops = {
|
||||
static const struct iwl_ops iwl3945_ops = {
|
||||
.ucode = &iwl3945_ucode,
|
||||
.lib = &iwl3945_lib,
|
||||
.hcmd = &iwl3945_hcmd,
|
||||
|
@ -227,7 +227,8 @@ extern void iwl3945_rx_replenish(void *data);
|
||||
extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
|
||||
extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
|
||||
struct ieee80211_hdr *hdr,int left);
|
||||
extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
|
||||
extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
||||
char **buf, bool display);
|
||||
extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
|
||||
|
||||
/*
|
||||
|
@ -2208,7 +2208,7 @@ static struct iwl_lib_ops iwl4965_lib = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct iwl_ops iwl4965_ops = {
|
||||
static const struct iwl_ops iwl4965_ops = {
|
||||
.ucode = &iwl4965_ucode,
|
||||
.lib = &iwl4965_lib,
|
||||
.hcmd = &iwl4965_hcmd,
|
||||
@ -2239,7 +2239,6 @@ struct iwl_cfg iwl4965_agn_cfg = {
|
||||
.broken_powersave = true,
|
||||
.led_compensation = 61,
|
||||
.chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
/* Module firmware */
|
||||
|
@ -1466,6 +1466,7 @@ struct iwl_lib_ops iwl5000_lib = {
|
||||
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
|
||||
.dump_nic_event_log = iwl_dump_nic_event_log,
|
||||
.dump_nic_error_log = iwl_dump_nic_error_log,
|
||||
.dump_csr = iwl_dump_csr,
|
||||
.load_ucode = iwl5000_load_ucode,
|
||||
.init_alive_start = iwl5000_init_alive_start,
|
||||
.alive_notify = iwl5000_alive_notify,
|
||||
@ -1518,6 +1519,7 @@ static struct iwl_lib_ops iwl5150_lib = {
|
||||
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
|
||||
.dump_nic_event_log = iwl_dump_nic_event_log,
|
||||
.dump_nic_error_log = iwl_dump_nic_error_log,
|
||||
.dump_csr = iwl_dump_csr,
|
||||
.load_ucode = iwl5000_load_ucode,
|
||||
.init_alive_start = iwl5000_init_alive_start,
|
||||
.alive_notify = iwl5000_alive_notify,
|
||||
@ -1555,7 +1557,7 @@ static struct iwl_lib_ops iwl5150_lib = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct iwl_ops iwl5000_ops = {
|
||||
static const struct iwl_ops iwl5000_ops = {
|
||||
.ucode = &iwl5000_ucode,
|
||||
.lib = &iwl5000_lib,
|
||||
.hcmd = &iwl5000_hcmd,
|
||||
@ -1563,7 +1565,7 @@ static struct iwl_ops iwl5000_ops = {
|
||||
.led = &iwlagn_led_ops,
|
||||
};
|
||||
|
||||
static struct iwl_ops iwl5150_ops = {
|
||||
static const struct iwl_ops iwl5150_ops = {
|
||||
.ucode = &iwl5000_ucode,
|
||||
.lib = &iwl5150_lib,
|
||||
.hcmd = &iwl5000_hcmd,
|
||||
@ -1599,7 +1601,6 @@ struct iwl_cfg iwl5300_agn_cfg = {
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5100_bgn_cfg = {
|
||||
@ -1668,7 +1669,6 @@ struct iwl_cfg iwl5100_agn_cfg = {
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5350_agn_cfg = {
|
||||
@ -1692,7 +1692,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5150_agn_cfg = {
|
||||
@ -1716,7 +1715,6 @@ struct iwl_cfg iwl5150_agn_cfg = {
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5150_abg_cfg = {
|
||||
|
@ -215,6 +215,7 @@ static struct iwl_lib_ops iwl6000_lib = {
|
||||
.load_ucode = iwl5000_load_ucode,
|
||||
.dump_nic_event_log = iwl_dump_nic_event_log,
|
||||
.dump_nic_error_log = iwl_dump_nic_error_log,
|
||||
.dump_csr = iwl_dump_csr,
|
||||
.init_alive_start = iwl5000_init_alive_start,
|
||||
.alive_notify = iwl5000_alive_notify,
|
||||
.send_tx_power = iwl5000_send_tx_power,
|
||||
@ -252,7 +253,7 @@ static struct iwl_lib_ops iwl6000_lib = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct iwl_ops iwl6000_ops = {
|
||||
static const struct iwl_ops iwl6000_ops = {
|
||||
.ucode = &iwl5000_ucode,
|
||||
.lib = &iwl6000_lib,
|
||||
.hcmd = &iwl5000_hcmd,
|
||||
@ -267,7 +268,7 @@ static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = {
|
||||
.calc_rssi = iwl5000_calc_rssi,
|
||||
};
|
||||
|
||||
static struct iwl_ops iwl6050_ops = {
|
||||
static const struct iwl_ops iwl6050_ops = {
|
||||
.ucode = &iwl5000_ucode,
|
||||
.lib = &iwl6000_lib,
|
||||
.hcmd = &iwl5000_hcmd,
|
||||
@ -306,7 +307,6 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
|
||||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6000i_2abg_cfg = {
|
||||
@ -395,7 +395,6 @@ struct iwl_cfg iwl6050_2agn_cfg = {
|
||||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6050_2abg_cfg = {
|
||||
@ -455,7 +454,6 @@ struct iwl_cfg iwl6000_3agn_cfg = {
|
||||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
|
||||
|
@ -657,6 +657,131 @@ static void iwl_bg_statistics_periodic(unsigned long data)
|
||||
iwl_send_statistics_request(priv, CMD_ASYNC, false);
|
||||
}
|
||||
|
||||
|
||||
static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
|
||||
u32 start_idx, u32 num_events,
|
||||
u32 mode)
|
||||
{
|
||||
u32 i;
|
||||
u32 ptr; /* SRAM byte address of log data */
|
||||
u32 ev, time, data; /* event log data */
|
||||
unsigned long reg_flags;
|
||||
|
||||
if (mode == 0)
|
||||
ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
|
||||
else
|
||||
ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
|
||||
|
||||
/* Make sure device is powered up for SRAM reads */
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
if (iwl_grab_nic_access(priv)) {
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set starting address; reads will auto-increment */
|
||||
_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
|
||||
rmb();
|
||||
|
||||
/*
|
||||
* "time" is actually "data" for mode 0 (no timestamp).
|
||||
* place event id # at far right for easier visual parsing.
|
||||
*/
|
||||
for (i = 0; i < num_events; i++) {
|
||||
ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
if (mode == 0) {
|
||||
trace_iwlwifi_dev_ucode_cont_event(priv,
|
||||
0, time, ev);
|
||||
} else {
|
||||
data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
trace_iwlwifi_dev_ucode_cont_event(priv,
|
||||
time, data, ev);
|
||||
}
|
||||
}
|
||||
/* Allow device to power down */
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
void iwl_continuous_event_trace(struct iwl_priv *priv)
|
||||
{
|
||||
u32 capacity; /* event log capacity in # entries */
|
||||
u32 base; /* SRAM byte address of event log header */
|
||||
u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
|
||||
u32 num_wraps; /* # times uCode wrapped to top of log */
|
||||
u32 next_entry; /* index of next entry to be written by uCode */
|
||||
|
||||
if (priv->ucode_type == UCODE_INIT)
|
||||
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
|
||||
else
|
||||
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
||||
if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
|
||||
capacity = iwl_read_targ_mem(priv, base);
|
||||
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
|
||||
mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
|
||||
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
|
||||
} else
|
||||
return;
|
||||
|
||||
if (num_wraps == priv->event_log.num_wraps) {
|
||||
iwl_print_cont_event_trace(priv,
|
||||
base, priv->event_log.next_entry,
|
||||
next_entry - priv->event_log.next_entry,
|
||||
mode);
|
||||
priv->event_log.non_wraps_count++;
|
||||
} else {
|
||||
if ((num_wraps - priv->event_log.num_wraps) > 1)
|
||||
priv->event_log.wraps_more_count++;
|
||||
else
|
||||
priv->event_log.wraps_once_count++;
|
||||
trace_iwlwifi_dev_ucode_wrap_event(priv,
|
||||
num_wraps - priv->event_log.num_wraps,
|
||||
next_entry, priv->event_log.next_entry);
|
||||
if (next_entry < priv->event_log.next_entry) {
|
||||
iwl_print_cont_event_trace(priv, base,
|
||||
priv->event_log.next_entry,
|
||||
capacity - priv->event_log.next_entry,
|
||||
mode);
|
||||
|
||||
iwl_print_cont_event_trace(priv, base, 0,
|
||||
next_entry, mode);
|
||||
} else {
|
||||
iwl_print_cont_event_trace(priv, base,
|
||||
next_entry, capacity - next_entry,
|
||||
mode);
|
||||
|
||||
iwl_print_cont_event_trace(priv, base, 0,
|
||||
next_entry, mode);
|
||||
}
|
||||
}
|
||||
priv->event_log.num_wraps = num_wraps;
|
||||
priv->event_log.next_entry = next_entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_bg_ucode_trace - Timer callback to log ucode event
|
||||
*
|
||||
* The timer is continually set to execute every
|
||||
* UCODE_TRACE_PERIOD milliseconds after the last timer expired
|
||||
* this function is to perform continuous uCode event logging operation
|
||||
* if enabled
|
||||
*/
|
||||
static void iwl_bg_ucode_trace(unsigned long data)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)data;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (priv->event_log.ucode_trace) {
|
||||
iwl_continuous_event_trace(priv);
|
||||
/* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
|
||||
mod_timer(&priv->ucode_trace,
|
||||
jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_rx_beacon_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
@ -689,12 +814,14 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
|
||||
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
|
||||
unsigned long status = priv->status;
|
||||
|
||||
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
|
||||
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
|
||||
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
|
||||
(flags & SW_CARD_DISABLED) ? "Kill" : "On");
|
||||
(flags & SW_CARD_DISABLED) ? "Kill" : "On",
|
||||
(flags & CT_CARD_DISABLED) ?
|
||||
"Reached" : "Not reached");
|
||||
|
||||
if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
|
||||
RF_CARD_DISABLED)) {
|
||||
CT_CARD_DISABLED)) {
|
||||
|
||||
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
|
||||
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
|
||||
@ -708,10 +835,10 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
|
||||
iwl_write_direct32(priv, HBUS_TARG_MBX_C,
|
||||
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
|
||||
}
|
||||
if (flags & RF_CARD_DISABLED)
|
||||
if (flags & CT_CARD_DISABLED)
|
||||
iwl_tt_enter_ct_kill(priv);
|
||||
}
|
||||
if (!(flags & RF_CARD_DISABLED))
|
||||
if (!(flags & CT_CARD_DISABLED))
|
||||
iwl_tt_exit_ct_kill(priv);
|
||||
|
||||
if (flags & HW_CARD_DISABLED)
|
||||
@ -1705,8 +1832,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
|
||||
* iwl_print_event_log - Dump error event log to syslog
|
||||
*
|
||||
*/
|
||||
static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
||||
u32 num_events, u32 mode)
|
||||
static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
||||
u32 num_events, u32 mode,
|
||||
int pos, char **buf, size_t bufsz)
|
||||
{
|
||||
u32 i;
|
||||
u32 base; /* SRAM byte address of event log header */
|
||||
@ -1716,7 +1844,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
||||
unsigned long reg_flags;
|
||||
|
||||
if (num_events == 0)
|
||||
return;
|
||||
return pos;
|
||||
if (priv->ucode_type == UCODE_INIT)
|
||||
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
|
||||
else
|
||||
@ -1744,27 +1872,44 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
||||
time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
if (mode == 0) {
|
||||
/* data, ev */
|
||||
trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
|
||||
IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
|
||||
if (bufsz) {
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
"EVT_LOG:0x%08x:%04u\n",
|
||||
time, ev);
|
||||
} else {
|
||||
trace_iwlwifi_dev_ucode_event(priv, 0,
|
||||
time, ev);
|
||||
IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
|
||||
time, ev);
|
||||
}
|
||||
} else {
|
||||
data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
|
||||
if (bufsz) {
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
"EVT_LOGT:%010u:0x%08x:%04u\n",
|
||||
time, data, ev);
|
||||
} else {
|
||||
IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
|
||||
time, data, ev);
|
||||
trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
|
||||
trace_iwlwifi_dev_ucode_event(priv, time,
|
||||
data, ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow device to power down */
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_print_last_event_logs - Dump the newest # of event log to syslog
|
||||
*/
|
||||
static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
u32 num_wraps, u32 next_entry,
|
||||
u32 size, u32 mode)
|
||||
static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
u32 num_wraps, u32 next_entry,
|
||||
u32 size, u32 mode,
|
||||
int pos, char **buf, size_t bufsz)
|
||||
{
|
||||
/*
|
||||
* display the newest DEFAULT_LOG_ENTRIES entries
|
||||
@ -1772,21 +1917,26 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
*/
|
||||
if (num_wraps) {
|
||||
if (next_entry < size) {
|
||||
iwl_print_event_log(priv,
|
||||
capacity - (size - next_entry),
|
||||
size - next_entry, mode);
|
||||
iwl_print_event_log(priv, 0,
|
||||
next_entry, mode);
|
||||
pos = iwl_print_event_log(priv,
|
||||
capacity - (size - next_entry),
|
||||
size - next_entry, mode,
|
||||
pos, buf, bufsz);
|
||||
pos = iwl_print_event_log(priv, 0,
|
||||
next_entry, mode,
|
||||
pos, buf, bufsz);
|
||||
} else
|
||||
iwl_print_event_log(priv, next_entry - size,
|
||||
size, mode);
|
||||
pos = iwl_print_event_log(priv, next_entry - size,
|
||||
size, mode, pos, buf, bufsz);
|
||||
} else {
|
||||
if (next_entry < size)
|
||||
iwl_print_event_log(priv, 0, next_entry, mode);
|
||||
else
|
||||
iwl_print_event_log(priv, next_entry - size,
|
||||
size, mode);
|
||||
if (next_entry < size) {
|
||||
pos = iwl_print_event_log(priv, 0, next_entry,
|
||||
mode, pos, buf, bufsz);
|
||||
} else {
|
||||
pos = iwl_print_event_log(priv, next_entry - size,
|
||||
size, mode, pos, buf, bufsz);
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
|
||||
@ -1794,7 +1944,8 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
|
||||
#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
|
||||
|
||||
void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
||||
char **buf, bool display)
|
||||
{
|
||||
u32 base; /* SRAM byte address of event log header */
|
||||
u32 capacity; /* event log capacity in # entries */
|
||||
@ -1802,6 +1953,8 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
u32 num_wraps; /* # times uCode wrapped to top of log */
|
||||
u32 next_entry; /* index of next entry to be written by uCode */
|
||||
u32 size; /* # entries that we'll print */
|
||||
int pos = 0;
|
||||
size_t bufsz = 0;
|
||||
|
||||
if (priv->ucode_type == UCODE_INIT)
|
||||
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
|
||||
@ -1812,7 +1965,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
IWL_ERR(priv,
|
||||
"Invalid event log pointer 0x%08X for %s uCode\n",
|
||||
base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
|
||||
return;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* event log header */
|
||||
@ -1838,7 +1991,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
/* bail out if nothing in log */
|
||||
if (size == 0) {
|
||||
IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
|
||||
return;
|
||||
return pos;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
@ -1853,6 +2006,15 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
size);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (display) {
|
||||
if (full_log)
|
||||
bufsz = capacity * 48;
|
||||
else
|
||||
bufsz = size * 48;
|
||||
*buf = kmalloc(bufsz, GFP_KERNEL);
|
||||
if (!*buf)
|
||||
return pos;
|
||||
}
|
||||
if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
|
||||
/*
|
||||
* if uCode has wrapped back to top of log,
|
||||
@ -1860,17 +2022,22 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
* i.e the next one that uCode would fill.
|
||||
*/
|
||||
if (num_wraps)
|
||||
iwl_print_event_log(priv, next_entry,
|
||||
capacity - next_entry, mode);
|
||||
pos = iwl_print_event_log(priv, next_entry,
|
||||
capacity - next_entry, mode,
|
||||
pos, buf, bufsz);
|
||||
/* (then/else) start at top of log */
|
||||
iwl_print_event_log(priv, 0, next_entry, mode);
|
||||
pos = iwl_print_event_log(priv, 0,
|
||||
next_entry, mode, pos, buf, bufsz);
|
||||
} else
|
||||
iwl_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode);
|
||||
pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode,
|
||||
pos, buf, bufsz);
|
||||
#else
|
||||
iwl_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode);
|
||||
pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode,
|
||||
pos, buf, bufsz);
|
||||
#endif
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2456,6 +2623,10 @@ static int iwl_setup_mac(struct iwl_priv *priv)
|
||||
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
|
||||
|
||||
if (priv->cfg->sku & IWL_SKU_N)
|
||||
hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
|
||||
IEEE80211_HW_SUPPORTS_STATIC_SMPS;
|
||||
|
||||
hw->sta_data_size = sizeof(struct iwl_station_priv);
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
@ -3126,6 +3297,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
priv->statistics_periodic.data = (unsigned long)priv;
|
||||
priv->statistics_periodic.function = iwl_bg_statistics_periodic;
|
||||
|
||||
init_timer(&priv->ucode_trace);
|
||||
priv->ucode_trace.data = (unsigned long)priv;
|
||||
priv->ucode_trace.function = iwl_bg_ucode_trace;
|
||||
|
||||
if (!priv->cfg->use_isr_legacy)
|
||||
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
|
||||
iwl_irq_tasklet, (unsigned long)priv);
|
||||
@ -3144,6 +3319,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
||||
cancel_delayed_work(&priv->alive_start);
|
||||
cancel_work_sync(&priv->beacon_update);
|
||||
del_timer_sync(&priv->statistics_periodic);
|
||||
del_timer_sync(&priv->ucode_trace);
|
||||
}
|
||||
|
||||
static void iwl_init_hw_rates(struct iwl_priv *priv,
|
||||
@ -3188,6 +3364,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
|
||||
priv->band = IEEE80211_BAND_2GHZ;
|
||||
|
||||
priv->iw_mode = NL80211_IFTYPE_STATION;
|
||||
priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
|
||||
|
||||
/* Choose which receivers/antennas to use */
|
||||
if (priv->cfg->ops->hcmd->set_rxon_chain)
|
||||
|
@ -414,7 +414,6 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
|
||||
/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
|
||||
static int iwl_sensitivity_write(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
struct iwl_sensitivity_cmd cmd ;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
struct iwl_host_cmd cmd_out = {
|
||||
@ -477,11 +476,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
|
||||
memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
|
||||
sizeof(u16)*HD_TABLE_SIZE);
|
||||
|
||||
ret = iwl_send_cmd(priv, &cmd_out);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "SENSITIVITY_CMD failed\n");
|
||||
|
||||
return ret;
|
||||
return iwl_send_cmd(priv, &cmd_out);
|
||||
}
|
||||
|
||||
void iwl_init_sensitivity(struct iwl_priv *priv)
|
||||
|
@ -2510,7 +2510,7 @@ struct iwl_card_state_notif {
|
||||
|
||||
#define HW_CARD_DISABLED 0x01
|
||||
#define SW_CARD_DISABLED 0x02
|
||||
#define RF_CARD_DISABLED 0x04
|
||||
#define CT_CARD_DISABLED 0x04
|
||||
#define RXON_CARD_DISABLED 0x10
|
||||
|
||||
struct iwl_ct_kill_config {
|
||||
|
@ -450,8 +450,6 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
|
||||
if (priv->cfg->ht_greenfield_support)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||
ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
|
||||
(priv->cfg->sm_ps_mode << 2));
|
||||
max_bit_rate = MAX_BIT_RATE_20_MHZ;
|
||||
if (priv->hw_params.ht40_channel & BIT(band)) {
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
@ -636,7 +634,7 @@ EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
|
||||
|
||||
static bool is_single_rx_stream(struct iwl_priv *priv)
|
||||
{
|
||||
return !priv->current_ht_config.is_ht ||
|
||||
return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
|
||||
priv->current_ht_config.single_chain_sufficient;
|
||||
}
|
||||
|
||||
@ -1003,28 +1001,18 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
|
||||
*/
|
||||
static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
|
||||
{
|
||||
int idle_cnt = active_cnt;
|
||||
bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
|
||||
|
||||
/* # Rx chains when idling and maybe trying to save power */
|
||||
switch (priv->cfg->sm_ps_mode) {
|
||||
case WLAN_HT_CAP_SM_PS_STATIC:
|
||||
idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DYNAMIC:
|
||||
idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
|
||||
IWL_NUM_IDLE_CHAINS_SINGLE;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DISABLED:
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_INVALID:
|
||||
/* # Rx chains when idling, depending on SMPS mode */
|
||||
switch (priv->current_ht_config.smps) {
|
||||
case IEEE80211_SMPS_STATIC:
|
||||
case IEEE80211_SMPS_DYNAMIC:
|
||||
return IWL_NUM_IDLE_CHAINS_SINGLE;
|
||||
case IEEE80211_SMPS_OFF:
|
||||
return active_cnt;
|
||||
default:
|
||||
IWL_ERR(priv, "invalid sm_ps mode %u\n",
|
||||
priv->cfg->sm_ps_mode);
|
||||
WARN_ON(1);
|
||||
break;
|
||||
WARN(1, "invalid SMPS mode %d",
|
||||
priv->current_ht_config.smps);
|
||||
return active_cnt;
|
||||
}
|
||||
return idle_cnt;
|
||||
}
|
||||
|
||||
/* up to 4 chains */
|
||||
@ -1363,7 +1351,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
|
||||
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
|
||||
|
||||
priv->cfg->ops->lib->dump_nic_error_log(priv);
|
||||
priv->cfg->ops->lib->dump_nic_event_log(priv, false);
|
||||
if (priv->cfg->ops->lib->dump_csr)
|
||||
priv->cfg->ops->lib->dump_csr(priv);
|
||||
priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
|
||||
iwl_print_rx_config_cmd(priv);
|
||||
@ -2684,6 +2674,21 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
|
||||
IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
|
||||
}
|
||||
|
||||
if (changed & (IEEE80211_CONF_CHANGE_SMPS |
|
||||
IEEE80211_CONF_CHANGE_CHANNEL)) {
|
||||
/* mac80211 uses static for non-HT which is what we want */
|
||||
priv->current_ht_config.smps = conf->smps_mode;
|
||||
|
||||
/*
|
||||
* Recalculate chain counts.
|
||||
*
|
||||
* If monitor mode is enabled then mac80211 will
|
||||
* set up the SM PS mode to OFF if an HT channel is
|
||||
* configured.
|
||||
*/
|
||||
if (priv->cfg->ops->hcmd->set_rxon_chain)
|
||||
priv->cfg->ops->hcmd->set_rxon_chain(priv);
|
||||
}
|
||||
|
||||
/* during scanning mac80211 will delay channel setting until
|
||||
* scan finish with changed = 0
|
||||
@ -2780,10 +2785,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
|
||||
iwl_set_tx_power(priv, conf->power_level, false);
|
||||
}
|
||||
|
||||
/* call to ensure that 4965 rx_chain is set properly in monitor mode */
|
||||
if (priv->cfg->ops->hcmd->set_rxon_chain)
|
||||
priv->cfg->ops->hcmd->set_rxon_chain(priv);
|
||||
|
||||
if (!iwl_is_ready(priv)) {
|
||||
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
|
||||
goto out;
|
||||
@ -3191,6 +3192,77 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
|
||||
EXPORT_SYMBOL(iwl_update_stats);
|
||||
#endif
|
||||
|
||||
const static char *get_csr_string(int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
IWL_CMD(CSR_HW_IF_CONFIG_REG);
|
||||
IWL_CMD(CSR_INT_COALESCING);
|
||||
IWL_CMD(CSR_INT);
|
||||
IWL_CMD(CSR_INT_MASK);
|
||||
IWL_CMD(CSR_FH_INT_STATUS);
|
||||
IWL_CMD(CSR_GPIO_IN);
|
||||
IWL_CMD(CSR_RESET);
|
||||
IWL_CMD(CSR_GP_CNTRL);
|
||||
IWL_CMD(CSR_HW_REV);
|
||||
IWL_CMD(CSR_EEPROM_REG);
|
||||
IWL_CMD(CSR_EEPROM_GP);
|
||||
IWL_CMD(CSR_OTP_GP_REG);
|
||||
IWL_CMD(CSR_GIO_REG);
|
||||
IWL_CMD(CSR_GP_UCODE_REG);
|
||||
IWL_CMD(CSR_GP_DRIVER_REG);
|
||||
IWL_CMD(CSR_UCODE_DRV_GP1);
|
||||
IWL_CMD(CSR_UCODE_DRV_GP2);
|
||||
IWL_CMD(CSR_LED_REG);
|
||||
IWL_CMD(CSR_DRAM_INT_TBL_REG);
|
||||
IWL_CMD(CSR_GIO_CHICKEN_BITS);
|
||||
IWL_CMD(CSR_ANA_PLL_CFG);
|
||||
IWL_CMD(CSR_HW_REV_WA_REG);
|
||||
IWL_CMD(CSR_DBG_HPET_MEM_REG);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_dump_csr(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
u32 csr_tbl[] = {
|
||||
CSR_HW_IF_CONFIG_REG,
|
||||
CSR_INT_COALESCING,
|
||||
CSR_INT,
|
||||
CSR_INT_MASK,
|
||||
CSR_FH_INT_STATUS,
|
||||
CSR_GPIO_IN,
|
||||
CSR_RESET,
|
||||
CSR_GP_CNTRL,
|
||||
CSR_HW_REV,
|
||||
CSR_EEPROM_REG,
|
||||
CSR_EEPROM_GP,
|
||||
CSR_OTP_GP_REG,
|
||||
CSR_GIO_REG,
|
||||
CSR_GP_UCODE_REG,
|
||||
CSR_GP_DRIVER_REG,
|
||||
CSR_UCODE_DRV_GP1,
|
||||
CSR_UCODE_DRV_GP2,
|
||||
CSR_LED_REG,
|
||||
CSR_DRAM_INT_TBL_REG,
|
||||
CSR_GIO_CHICKEN_BITS,
|
||||
CSR_ANA_PLL_CFG,
|
||||
CSR_HW_REV_WA_REG,
|
||||
CSR_DBG_HPET_MEM_REG
|
||||
};
|
||||
IWL_ERR(priv, "CSR values:\n");
|
||||
IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is "
|
||||
"CSR_INT_PERIODIC_REG)\n");
|
||||
for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) {
|
||||
IWL_ERR(priv, " %25s: 0X%08x\n",
|
||||
get_csr_string(csr_tbl[i]),
|
||||
iwl_read32(priv, csr_tbl[i]));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_dump_csr);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
@ -169,8 +169,10 @@ struct iwl_lib_ops {
|
||||
int (*is_valid_rtc_data_addr)(u32 addr);
|
||||
/* 1st ucode load */
|
||||
int (*load_ucode)(struct iwl_priv *priv);
|
||||
void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log);
|
||||
int (*dump_nic_event_log)(struct iwl_priv *priv,
|
||||
bool full_log, char **buf, bool display);
|
||||
void (*dump_nic_error_log)(struct iwl_priv *priv);
|
||||
void (*dump_csr)(struct iwl_priv *priv);
|
||||
int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
|
||||
/* power management */
|
||||
struct iwl_apm_ops apm_ops;
|
||||
@ -230,7 +232,6 @@ struct iwl_mod_params {
|
||||
* @chain_noise_num_beacons: number of beacons used to compute chain noise
|
||||
* @adv_thermal_throttle: support advance thermal throttle
|
||||
* @support_ct_kill_exit: support ct kill exit condition
|
||||
* @sm_ps_mode: spatial multiplexing power save mode
|
||||
* @support_wimax_coexist: support wimax/wifi co-exist
|
||||
*
|
||||
* We enable the driver to be backward compatible wrt API version. The
|
||||
@ -287,7 +288,6 @@ struct iwl_cfg {
|
||||
const bool supports_idle;
|
||||
bool adv_thermal_throttle;
|
||||
bool support_ct_kill_exit;
|
||||
u8 sm_ps_mode;
|
||||
const bool support_wimax_coexist;
|
||||
};
|
||||
|
||||
@ -581,7 +581,9 @@ int iwl_pci_resume(struct pci_dev *pdev);
|
||||
* Error Handling Debugging
|
||||
******************************************************/
|
||||
void iwl_dump_nic_error_log(struct iwl_priv *priv);
|
||||
void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
|
||||
int iwl_dump_nic_event_log(struct iwl_priv *priv,
|
||||
bool full_log, char **buf, bool display);
|
||||
void iwl_dump_csr(struct iwl_priv *priv);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
void iwl_print_rx_config_cmd(struct iwl_priv *priv);
|
||||
#else
|
||||
|
@ -109,6 +109,8 @@ struct iwl_debugfs {
|
||||
struct dentry *file_power_save_status;
|
||||
struct dentry *file_clear_ucode_statistics;
|
||||
struct dentry *file_clear_traffic_statistics;
|
||||
struct dentry *file_csr;
|
||||
struct dentry *file_ucode_tracing;
|
||||
} dbgfs_debug_files;
|
||||
u32 sram_offset;
|
||||
u32 sram_len;
|
||||
|
@ -420,6 +420,23 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_log_event_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char *buf;
|
||||
int pos = 0;
|
||||
ssize_t ret = -ENOMEM;
|
||||
|
||||
pos = priv->cfg->ops->lib->dump_nic_event_log(priv, true, &buf, true);
|
||||
if (pos && buf) {
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_log_event_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@ -436,7 +453,8 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
|
||||
if (sscanf(buf, "%d", &event_log_flag) != 1)
|
||||
return -EFAULT;
|
||||
if (event_log_flag == 1)
|
||||
priv->cfg->ops->lib->dump_nic_event_log(priv, true);
|
||||
priv->cfg->ops->lib->dump_nic_event_log(priv, true,
|
||||
NULL, false);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -859,7 +877,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
|
||||
}
|
||||
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(sram);
|
||||
DEBUGFS_WRITE_FILE_OPS(log_event);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(log_event);
|
||||
DEBUGFS_READ_FILE_OPS(nvm);
|
||||
DEBUGFS_READ_FILE_OPS(stations);
|
||||
DEBUGFS_READ_FILE_OPS(channels);
|
||||
@ -1845,6 +1863,80 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_csr_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
int csr;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%d", &csr) != 1)
|
||||
return -EFAULT;
|
||||
|
||||
if (priv->cfg->ops->lib->dump_csr)
|
||||
priv->cfg->ops->lib->dump_csr(priv);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
int pos = 0;
|
||||
char buf[128];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
ssize_t ret;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
|
||||
priv->event_log.ucode_trace ? "On" : "Off");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
|
||||
priv->event_log.non_wraps_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
|
||||
priv->event_log.wraps_once_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
|
||||
priv->event_log.wraps_more_count);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
int trace;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%d", &trace) != 1)
|
||||
return -EFAULT;
|
||||
|
||||
if (trace) {
|
||||
priv->event_log.ucode_trace = true;
|
||||
/* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */
|
||||
mod_timer(&priv->ucode_trace,
|
||||
jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
|
||||
} else {
|
||||
priv->event_log.ucode_trace = false;
|
||||
del_timer_sync(&priv->ucode_trace);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
DEBUGFS_READ_FILE_OPS(rx_statistics);
|
||||
DEBUGFS_READ_FILE_OPS(tx_statistics);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
|
||||
@ -1859,6 +1951,8 @@ DEBUGFS_READ_FILE_OPS(tx_power);
|
||||
DEBUGFS_READ_FILE_OPS(power_save_status);
|
||||
DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
|
||||
DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
|
||||
DEBUGFS_WRITE_FILE_OPS(csr);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
|
||||
|
||||
/*
|
||||
* Create the debugfs files and directories
|
||||
@ -1889,7 +1983,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
||||
DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
|
||||
DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(log_event, data, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(log_event, data, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(stations, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(channels, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(status, data, S_IRUSR);
|
||||
@ -1909,12 +2003,14 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
||||
DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(csr, debug, S_IWUSR);
|
||||
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
|
||||
DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(ucode_tracing, debug, S_IWUSR | S_IRUSR);
|
||||
}
|
||||
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
|
||||
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
|
||||
@ -1966,6 +2062,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
|
||||
file_clear_ucode_statistics);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
||||
file_clear_traffic_statistics);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr);
|
||||
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
||||
file_ucode_rx_stats);
|
||||
@ -1977,6 +2074,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
|
||||
file_sensitivity);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
||||
file_chain_noise);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
||||
file_ucode_tracing);
|
||||
}
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dir_debug);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
|
||||
|
@ -512,6 +512,7 @@ struct iwl_ht_config {
|
||||
bool is_ht;
|
||||
bool is_40mhz;
|
||||
bool single_chain_sufficient;
|
||||
enum ieee80211_smps_mode smps; /* current smps mode */
|
||||
/* BSS related data */
|
||||
u8 extension_chan_offset;
|
||||
u8 ht_protection;
|
||||
@ -984,6 +985,32 @@ struct iwl_switch_rxon {
|
||||
__le16 channel;
|
||||
};
|
||||
|
||||
/*
|
||||
* schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
|
||||
* to perform continuous uCode event logging operation if enabled
|
||||
*/
|
||||
#define UCODE_TRACE_PERIOD (100)
|
||||
|
||||
/*
|
||||
* iwl_event_log: current uCode event log position
|
||||
*
|
||||
* @ucode_trace: enable/disable ucode continuous trace timer
|
||||
* @num_wraps: how many times the event buffer wraps
|
||||
* @next_entry: the entry just before the next one that uCode would fill
|
||||
* @non_wraps_count: counter for no wrap detected when dump ucode events
|
||||
* @wraps_once_count: counter for wrap once detected when dump ucode events
|
||||
* @wraps_more_count: counter for wrap more than once detected
|
||||
* when dump ucode events
|
||||
*/
|
||||
struct iwl_event_log {
|
||||
bool ucode_trace;
|
||||
u32 num_wraps;
|
||||
u32 next_entry;
|
||||
int non_wraps_count;
|
||||
int wraps_once_count;
|
||||
int wraps_more_count;
|
||||
};
|
||||
|
||||
struct iwl_priv {
|
||||
|
||||
/* ieee device used by generic ieee processing code */
|
||||
@ -1261,6 +1288,7 @@ struct iwl_priv {
|
||||
u32 disable_tx_power_cal;
|
||||
struct work_struct run_time_calib_work;
|
||||
struct timer_list statistics_periodic;
|
||||
struct timer_list ucode_trace;
|
||||
bool hw_ready;
|
||||
/*For 3945*/
|
||||
#define IWL_DEFAULT_TX_POWER 0x0F
|
||||
@ -1268,6 +1296,8 @@ struct iwl_priv {
|
||||
struct iwl3945_notif_statistics statistics_39;
|
||||
|
||||
u32 sta_supp_rates;
|
||||
|
||||
struct iwl_event_log event_log;
|
||||
}; /*iwl_priv */
|
||||
|
||||
static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
|
||||
|
@ -11,4 +11,6 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
|
||||
#endif
|
||||
|
@ -64,6 +64,50 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
|
||||
TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM iwlwifi_ucode
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
|
||||
TP_ARGS(priv, time, data, ev),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
|
||||
__field(u32, time)
|
||||
__field(u32, data)
|
||||
__field(u32, ev)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->time = time;
|
||||
__entry->data = data;
|
||||
__entry->ev = ev;
|
||||
),
|
||||
TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
|
||||
__entry->priv, __entry->time, __entry->data, __entry->ev)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
|
||||
TP_ARGS(priv, wraps, n_entry, p_entry),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
|
||||
__field(u32, wraps)
|
||||
__field(u32, n_entry)
|
||||
__field(u32, p_entry)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->wraps = wraps;
|
||||
__entry->n_entry = n_entry;
|
||||
__entry->p_entry = p_entry;
|
||||
),
|
||||
TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X",
|
||||
__entry->priv, __entry->wraps, __entry->n_entry,
|
||||
__entry->p_entry)
|
||||
);
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM iwlwifi
|
||||
|
||||
|
@ -1559,8 +1559,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
|
||||
* iwl3945_print_event_log - Dump error event log to syslog
|
||||
*
|
||||
*/
|
||||
static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
||||
u32 num_events, u32 mode)
|
||||
static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
||||
u32 num_events, u32 mode,
|
||||
int pos, char **buf, size_t bufsz)
|
||||
{
|
||||
u32 i;
|
||||
u32 base; /* SRAM byte address of event log header */
|
||||
@ -1570,7 +1571,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
||||
unsigned long reg_flags;
|
||||
|
||||
if (num_events == 0)
|
||||
return;
|
||||
return pos;
|
||||
|
||||
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
||||
|
||||
@ -1596,26 +1597,43 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
||||
time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
if (mode == 0) {
|
||||
/* data, ev */
|
||||
IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
|
||||
trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
|
||||
if (bufsz) {
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
"0x%08x:%04u\n",
|
||||
time, ev);
|
||||
} else {
|
||||
IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
|
||||
trace_iwlwifi_dev_ucode_event(priv, 0,
|
||||
time, ev);
|
||||
}
|
||||
} else {
|
||||
data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
|
||||
trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
|
||||
if (bufsz) {
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
"%010u:0x%08x:%04u\n",
|
||||
time, data, ev);
|
||||
} else {
|
||||
IWL_ERR(priv, "%010u\t0x%08x\t%04u\n",
|
||||
time, data, ev);
|
||||
trace_iwlwifi_dev_ucode_event(priv, time,
|
||||
data, ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow device to power down */
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl3945_print_last_event_logs - Dump the newest # of event log to syslog
|
||||
*/
|
||||
static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
u32 num_wraps, u32 next_entry,
|
||||
u32 size, u32 mode)
|
||||
u32 size, u32 mode,
|
||||
int pos, char **buf, size_t bufsz)
|
||||
{
|
||||
/*
|
||||
* display the newest DEFAULT_LOG_ENTRIES entries
|
||||
@ -1623,21 +1641,28 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
*/
|
||||
if (num_wraps) {
|
||||
if (next_entry < size) {
|
||||
iwl3945_print_event_log(priv,
|
||||
capacity - (size - next_entry),
|
||||
size - next_entry, mode);
|
||||
iwl3945_print_event_log(priv, 0,
|
||||
next_entry, mode);
|
||||
pos = iwl3945_print_event_log(priv,
|
||||
capacity - (size - next_entry),
|
||||
size - next_entry, mode,
|
||||
pos, buf, bufsz);
|
||||
pos = iwl3945_print_event_log(priv, 0,
|
||||
next_entry, mode,
|
||||
pos, buf, bufsz);
|
||||
} else
|
||||
iwl3945_print_event_log(priv, next_entry - size,
|
||||
size, mode);
|
||||
pos = iwl3945_print_event_log(priv, next_entry - size,
|
||||
size, mode,
|
||||
pos, buf, bufsz);
|
||||
} else {
|
||||
if (next_entry < size)
|
||||
iwl3945_print_event_log(priv, 0, next_entry, mode);
|
||||
pos = iwl3945_print_event_log(priv, 0,
|
||||
next_entry, mode,
|
||||
pos, buf, bufsz);
|
||||
else
|
||||
iwl3945_print_event_log(priv, next_entry - size,
|
||||
size, mode);
|
||||
pos = iwl3945_print_event_log(priv, next_entry - size,
|
||||
size, mode,
|
||||
pos, buf, bufsz);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
|
||||
@ -1645,7 +1670,8 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
|
||||
#define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
|
||||
|
||||
void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
||||
char **buf, bool display)
|
||||
{
|
||||
u32 base; /* SRAM byte address of event log header */
|
||||
u32 capacity; /* event log capacity in # entries */
|
||||
@ -1653,11 +1679,13 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
u32 num_wraps; /* # times uCode wrapped to top of log */
|
||||
u32 next_entry; /* index of next entry to be written by uCode */
|
||||
u32 size; /* # entries that we'll print */
|
||||
int pos = 0;
|
||||
size_t bufsz = 0;
|
||||
|
||||
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
||||
if (!iwl3945_hw_valid_rtc_data_addr(base)) {
|
||||
IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
|
||||
return;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* event log header */
|
||||
@ -1683,7 +1711,7 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
/* bail out if nothing in log */
|
||||
if (size == 0) {
|
||||
IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
|
||||
return;
|
||||
return pos;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
@ -1699,25 +1727,38 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
size);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (display) {
|
||||
if (full_log)
|
||||
bufsz = capacity * 48;
|
||||
else
|
||||
bufsz = size * 48;
|
||||
*buf = kmalloc(bufsz, GFP_KERNEL);
|
||||
if (!*buf)
|
||||
return pos;
|
||||
}
|
||||
if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
|
||||
/* if uCode has wrapped back to top of log,
|
||||
* start at the oldest entry,
|
||||
* i.e the next one that uCode would fill.
|
||||
*/
|
||||
if (num_wraps)
|
||||
iwl3945_print_event_log(priv, next_entry,
|
||||
capacity - next_entry, mode);
|
||||
pos = iwl3945_print_event_log(priv, next_entry,
|
||||
capacity - next_entry, mode,
|
||||
pos, buf, bufsz);
|
||||
|
||||
/* (then/else) start at top of log */
|
||||
iwl3945_print_event_log(priv, 0, next_entry, mode);
|
||||
pos = iwl3945_print_event_log(priv, 0, next_entry, mode,
|
||||
pos, buf, bufsz);
|
||||
} else
|
||||
iwl3945_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode);
|
||||
pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode,
|
||||
pos, buf, bufsz);
|
||||
#else
|
||||
iwl3945_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode);
|
||||
pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode,
|
||||
pos, buf, bufsz);
|
||||
#endif
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
||||
|
@ -868,36 +868,35 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
|
||||
struct iwm_umac_notif_mgt_frame *mgt_frame =
|
||||
(struct iwm_umac_notif_mgt_frame *)buf;
|
||||
struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
|
||||
u8 *ie;
|
||||
|
||||
IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
|
||||
le16_to_cpu(mgt_frame->len));
|
||||
|
||||
if (ieee80211_is_assoc_req(mgt->frame_control)) {
|
||||
ie = mgt->u.assoc_req.variable;;
|
||||
iwm->req_ie_len =
|
||||
le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
|
||||
iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
|
||||
- offsetof(struct ieee80211_mgmt,
|
||||
u.assoc_req.variable);
|
||||
kfree(iwm->req_ie);
|
||||
iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
|
||||
iwm->req_ie_len, GFP_KERNEL);
|
||||
} else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
|
||||
ie = mgt->u.reassoc_req.variable;;
|
||||
iwm->req_ie_len =
|
||||
le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
|
||||
iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
|
||||
- offsetof(struct ieee80211_mgmt,
|
||||
u.reassoc_req.variable);
|
||||
kfree(iwm->req_ie);
|
||||
iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
|
||||
iwm->req_ie_len, GFP_KERNEL);
|
||||
} else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
|
||||
ie = mgt->u.assoc_resp.variable;;
|
||||
iwm->resp_ie_len =
|
||||
le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
|
||||
iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
|
||||
- offsetof(struct ieee80211_mgmt,
|
||||
u.assoc_resp.variable);
|
||||
kfree(iwm->resp_ie);
|
||||
iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
|
||||
iwm->resp_ie_len, GFP_KERNEL);
|
||||
} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
|
||||
ie = mgt->u.reassoc_resp.variable;;
|
||||
iwm->resp_ie_len =
|
||||
le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
|
||||
iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
|
||||
- offsetof(struct ieee80211_mgmt,
|
||||
u.reassoc_resp.variable);
|
||||
kfree(iwm->resp_ie);
|
||||
iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
|
||||
iwm->resp_ie_len, GFP_KERNEL);
|
||||
@ -1534,6 +1533,33 @@ static void classify8023(struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
|
||||
{
|
||||
struct wireless_dev *wdev = iwm_to_wdev(iwm);
|
||||
struct net_device *ndev = iwm_to_ndev(iwm);
|
||||
struct sk_buff_head list;
|
||||
struct sk_buff *frame;
|
||||
|
||||
IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
|
||||
|
||||
__skb_queue_head_init(&list);
|
||||
ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0);
|
||||
|
||||
while ((frame = __skb_dequeue(&list))) {
|
||||
ndev->stats.rx_packets++;
|
||||
ndev->stats.rx_bytes += frame->len;
|
||||
|
||||
frame->protocol = eth_type_trans(frame, ndev);
|
||||
frame->ip_summed = CHECKSUM_NONE;
|
||||
memset(frame->cb, 0, sizeof(frame->cb));
|
||||
|
||||
if (netif_rx_ni(frame) == NET_RX_DROP) {
|
||||
IWM_ERR(iwm, "Packet dropped\n");
|
||||
ndev->stats.rx_dropped++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void iwm_rx_process_packet(struct iwm_priv *iwm,
|
||||
struct iwm_rx_packet *packet,
|
||||
struct iwm_rx_ticket_node *ticket_node)
|
||||
@ -1548,25 +1574,34 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
|
||||
switch (le16_to_cpu(ticket_node->ticket->action)) {
|
||||
case IWM_RX_TICKET_RELEASE:
|
||||
IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
|
||||
classify8023(skb);
|
||||
|
||||
iwm_rx_adjust_packet(iwm, packet, ticket_node);
|
||||
skb->dev = iwm_to_ndev(iwm);
|
||||
classify8023(skb);
|
||||
|
||||
if (le16_to_cpu(ticket_node->ticket->flags) &
|
||||
IWM_RX_TICKET_AMSDU_MSK) {
|
||||
iwm_rx_process_amsdu(iwm, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
|
||||
if (ret < 0) {
|
||||
IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
|
||||
"%d\n", ret);
|
||||
kfree_skb(packet->skb);
|
||||
break;
|
||||
}
|
||||
|
||||
IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
|
||||
|
||||
skb->dev = iwm_to_ndev(iwm);
|
||||
ndev->stats.rx_packets++;
|
||||
ndev->stats.rx_bytes += skb->len;
|
||||
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
|
||||
ndev->stats.rx_packets++;
|
||||
ndev->stats.rx_bytes += skb->len;
|
||||
|
||||
if (netif_rx_ni(skb) == NET_RX_DROP) {
|
||||
IWM_ERR(iwm, "Packet dropped\n");
|
||||
ndev->stats.rx_dropped++;
|
||||
|
@ -37,3 +37,9 @@ config LIBERTAS_DEBUG
|
||||
depends on LIBERTAS
|
||||
---help---
|
||||
Debugging support.
|
||||
|
||||
config LIBERTAS_MESH
|
||||
bool "Enable mesh support"
|
||||
depends on LIBERTAS
|
||||
help
|
||||
This enables Libertas' MESH support, used by e.g. the OLPC people.
|
||||
|
@ -5,11 +5,11 @@ libertas-y += cmdresp.o
|
||||
libertas-y += debugfs.o
|
||||
libertas-y += ethtool.o
|
||||
libertas-y += main.o
|
||||
libertas-y += mesh.o
|
||||
libertas-y += rx.o
|
||||
libertas-y += scan.o
|
||||
libertas-y += tx.o
|
||||
libertas-y += wext.o
|
||||
libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
|
||||
|
||||
usb8xxx-objs += if_usb.o
|
||||
libertas_cs-objs += if_cs.o
|
||||
|
@ -390,10 +390,8 @@ int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
|
||||
cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
|
||||
cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
|
||||
if (!ret && cmd_action == CMD_ACT_GET) {
|
||||
priv->ratebitmap = le16_to_cpu(cmd.bitmap);
|
||||
if (!ret && cmd_action == CMD_ACT_GET)
|
||||
priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
@ -807,8 +805,7 @@ static int lbs_try_associate(struct lbs_private *priv,
|
||||
}
|
||||
|
||||
/* Use short preamble only when both the BSS and firmware support it */
|
||||
if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
|
||||
(assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
|
||||
if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
|
||||
preamble = RADIO_PREAMBLE_SHORT;
|
||||
|
||||
ret = lbs_set_radio(priv, preamble, 1);
|
||||
@ -939,8 +936,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
|
||||
}
|
||||
|
||||
/* Use short preamble only when both the BSS and firmware support it */
|
||||
if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
|
||||
(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
|
||||
if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
|
||||
lbs_deb_join("AdhocJoin: Short preamble\n");
|
||||
preamble = RADIO_PREAMBLE_SHORT;
|
||||
}
|
||||
@ -1049,7 +1045,7 @@ static int lbs_adhoc_start(struct lbs_private *priv,
|
||||
struct assoc_request *assoc_req)
|
||||
{
|
||||
struct cmd_ds_802_11_ad_hoc_start cmd;
|
||||
u8 preamble = RADIO_PREAMBLE_LONG;
|
||||
u8 preamble = RADIO_PREAMBLE_SHORT;
|
||||
size_t ratesize = 0;
|
||||
u16 tmpcap = 0;
|
||||
int ret = 0;
|
||||
@ -1057,11 +1053,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||
|
||||
if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
|
||||
lbs_deb_join("ADHOC_START: Will use short preamble\n");
|
||||
preamble = RADIO_PREAMBLE_SHORT;
|
||||
}
|
||||
|
||||
ret = lbs_set_radio(priv, preamble, 1);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
@ -143,19 +143,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
|
||||
lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
|
||||
cmd.hwifversion, cmd.version);
|
||||
|
||||
/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
|
||||
/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
|
||||
/* 5.110.22 have mesh command with 0xa3 command id */
|
||||
/* 10.0.0.p0 FW brings in mesh config command with different id */
|
||||
/* Check FW version MSB and initialize mesh_fw_ver */
|
||||
if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
|
||||
priv->mesh_fw_ver = MESH_FW_OLD;
|
||||
else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
|
||||
(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
|
||||
priv->mesh_fw_ver = MESH_FW_NEW;
|
||||
else
|
||||
priv->mesh_fw_ver = MESH_NONE;
|
||||
|
||||
/* Clamp region code to 8-bit since FW spec indicates that it should
|
||||
* only ever be 8-bit, even though the field size is 16-bit. Some firmware
|
||||
* returns non-zero high 8 bits here.
|
||||
@ -855,9 +842,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
|
||||
if (priv->fwrelease < 0x09000000) {
|
||||
switch (preamble) {
|
||||
case RADIO_PREAMBLE_SHORT:
|
||||
if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
|
||||
goto out;
|
||||
/* Fall through */
|
||||
case RADIO_PREAMBLE_AUTO:
|
||||
case RADIO_PREAMBLE_LONG:
|
||||
cmd.control = cpu_to_le16(preamble);
|
||||
@ -1011,6 +995,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
|
||||
case CMD_BT_ACCESS:
|
||||
ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
|
||||
break;
|
||||
@ -1019,6 +1005,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
|
||||
ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
case CMD_802_11_BEACON_CTRL:
|
||||
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
|
||||
break;
|
||||
@ -1317,7 +1305,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
|
||||
if ((priv->psmode != LBS802_11POWERMODECAM) &&
|
||||
(priv->psstate == PS_STATE_FULL_POWER) &&
|
||||
((priv->connect_status == LBS_CONNECTED) ||
|
||||
(priv->mesh_connect_status == LBS_CONNECTED))) {
|
||||
lbs_mesh_connected(priv))) {
|
||||
if (priv->secinfo.WPAenabled ||
|
||||
priv->secinfo.WPA2enabled) {
|
||||
/* check for valid WPA group keys */
|
||||
|
@ -110,18 +110,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
|
||||
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
|
||||
|
||||
|
||||
/* Mesh related */
|
||||
|
||||
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
|
||||
struct cmd_ds_mesh_access *cmd);
|
||||
|
||||
int lbs_mesh_config_send(struct lbs_private *priv,
|
||||
struct cmd_ds_mesh_config *cmd,
|
||||
uint16_t action, uint16_t type);
|
||||
|
||||
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
|
||||
|
||||
|
||||
/* Commands only used in wext.c, assoc. and scan.c */
|
||||
|
||||
int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
|
||||
|
@ -485,20 +485,8 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_MESH_AUTO_STARTED:
|
||||
/* Ignore spurious autostart events if autostart is disabled */
|
||||
if (!priv->mesh_autostart_enabled) {
|
||||
lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
|
||||
break;
|
||||
}
|
||||
lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
|
||||
priv->mesh_connect_status = LBS_CONNECTED;
|
||||
if (priv->mesh_open) {
|
||||
netif_carrier_on(priv->mesh_dev);
|
||||
if (!priv->tx_pending_len)
|
||||
netif_wake_queue(priv->mesh_dev);
|
||||
}
|
||||
priv->mode = IW_MODE_ADHOC;
|
||||
schedule_work(&priv->sync_channel);
|
||||
/* Ignore spurious autostart events */
|
||||
lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -397,13 +397,6 @@ enum KEY_INFO_WPA {
|
||||
KEY_INFO_WPA_ENABLED = 0x04
|
||||
};
|
||||
|
||||
/** mesh_fw_ver */
|
||||
enum _mesh_fw_ver {
|
||||
MESH_NONE = 0, /* MESH is not supported */
|
||||
MESH_FW_OLD, /* MESH is supported in FW V5 */
|
||||
MESH_FW_NEW, /* MESH is supported in FW V10 and newer */
|
||||
};
|
||||
|
||||
/* Default values for fwt commands. */
|
||||
#define FWT_DEFAULT_METRIC 0
|
||||
#define FWT_DEFAULT_DIR 1
|
||||
|
@ -39,15 +39,14 @@ struct lbs_private {
|
||||
|
||||
/* Mesh */
|
||||
struct net_device *mesh_dev; /* Virtual device */
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
u32 mesh_connect_status;
|
||||
struct lbs_mesh_stats mstats;
|
||||
int mesh_open;
|
||||
int mesh_fw_ver;
|
||||
int mesh_autostart_enabled;
|
||||
uint16_t mesh_tlv;
|
||||
u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
|
||||
u8 mesh_ssid_len;
|
||||
struct work_struct sync_channel;
|
||||
#endif
|
||||
|
||||
/* Monitor mode */
|
||||
struct net_device *rtap_net_dev;
|
||||
@ -176,9 +175,7 @@ struct lbs_private {
|
||||
struct bss_descriptor *networks;
|
||||
struct assoc_request * pending_assoc_req;
|
||||
struct assoc_request * in_progress_assoc_req;
|
||||
u16 capability;
|
||||
uint16_t enablehwauto;
|
||||
uint16_t ratebitmap;
|
||||
|
||||
/* ADHOC */
|
||||
u16 beacon_period;
|
||||
|
@ -114,9 +114,11 @@ const struct ethtool_ops lbs_ethtool_ops = {
|
||||
.get_drvinfo = lbs_ethtool_get_drvinfo,
|
||||
.get_eeprom = lbs_ethtool_get_eeprom,
|
||||
.get_eeprom_len = lbs_ethtool_get_eeprom_len,
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
.get_sset_count = lbs_mesh_ethtool_get_sset_count,
|
||||
.get_ethtool_stats = lbs_mesh_ethtool_get_stats,
|
||||
.get_strings = lbs_mesh_ethtool_get_strings,
|
||||
#endif
|
||||
.get_wol = lbs_ethtool_get_wol,
|
||||
.set_wol = lbs_ethtool_set_wol,
|
||||
};
|
||||
|
@ -123,7 +123,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
|
||||
if (priv->monitormode == monitor_mode)
|
||||
return strlen(buf);
|
||||
if (!priv->monitormode) {
|
||||
if (priv->infra_open || priv->mesh_open)
|
||||
if (priv->infra_open || lbs_mesh_open(priv))
|
||||
return -EBUSY;
|
||||
if (priv->mode == IW_MODE_INFRA)
|
||||
lbs_cmd_80211_deauthenticate(priv,
|
||||
@ -622,7 +622,7 @@ static int lbs_thread(void *data)
|
||||
if (priv->connect_status == LBS_CONNECTED)
|
||||
netif_wake_queue(priv->dev);
|
||||
if (priv->mesh_dev &&
|
||||
priv->mesh_connect_status == LBS_CONNECTED)
|
||||
lbs_mesh_connected(priv))
|
||||
netif_wake_queue(priv->mesh_dev);
|
||||
}
|
||||
}
|
||||
@ -809,18 +809,6 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lbs_sync_channel_worker(struct work_struct *work)
|
||||
{
|
||||
struct lbs_private *priv = container_of(work, struct lbs_private,
|
||||
sync_channel);
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
if (lbs_update_channel(priv))
|
||||
lbs_pr_info("Channel synchronization failed.");
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
}
|
||||
|
||||
|
||||
static int lbs_init_adapter(struct lbs_private *priv)
|
||||
{
|
||||
size_t bufsize;
|
||||
@ -848,14 +836,12 @@ static int lbs_init_adapter(struct lbs_private *priv)
|
||||
memset(priv->current_addr, 0xff, ETH_ALEN);
|
||||
|
||||
priv->connect_status = LBS_DISCONNECTED;
|
||||
priv->mesh_connect_status = LBS_DISCONNECTED;
|
||||
priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
|
||||
priv->mode = IW_MODE_INFRA;
|
||||
priv->channel = DEFAULT_AD_HOC_CHANNEL;
|
||||
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
|
||||
priv->radio_on = 1;
|
||||
priv->enablehwauto = 1;
|
||||
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
|
||||
priv->psmode = LBS802_11POWERMODECAM;
|
||||
priv->psstate = PS_STATE_FULL_POWER;
|
||||
priv->is_deep_sleep = 0;
|
||||
@ -998,11 +984,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
|
||||
INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
|
||||
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
|
||||
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
|
||||
INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
|
||||
|
||||
priv->mesh_open = 0;
|
||||
sprintf(priv->mesh_ssid, "mesh");
|
||||
priv->mesh_ssid_len = 4;
|
||||
|
||||
priv->wol_criteria = 0xffffffff;
|
||||
priv->wol_gpio = 0xff;
|
||||
@ -1076,6 +1057,17 @@ void lbs_remove_card(struct lbs_private *priv)
|
||||
EXPORT_SYMBOL_GPL(lbs_remove_card);
|
||||
|
||||
|
||||
static int lbs_rtap_supported(struct lbs_private *priv)
|
||||
{
|
||||
if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
|
||||
return 1;
|
||||
|
||||
/* newer firmware use a capability mask */
|
||||
return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
|
||||
(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK));
|
||||
}
|
||||
|
||||
|
||||
int lbs_start_card(struct lbs_private *priv)
|
||||
{
|
||||
struct net_device *dev = priv->dev;
|
||||
@ -1095,12 +1087,14 @@ int lbs_start_card(struct lbs_private *priv)
|
||||
|
||||
lbs_update_channel(priv);
|
||||
|
||||
lbs_init_mesh(priv);
|
||||
|
||||
/*
|
||||
* While rtap isn't related to mesh, only mesh-enabled
|
||||
* firmware implements the rtap functionality via
|
||||
* CMD_802_11_MONITOR_MODE.
|
||||
*/
|
||||
if (lbs_init_mesh(priv)) {
|
||||
if (lbs_rtap_supported(priv)) {
|
||||
if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
|
||||
lbs_pr_err("cannot register lbs_rtap attribute\n");
|
||||
}
|
||||
@ -1134,7 +1128,9 @@ void lbs_stop_card(struct lbs_private *priv)
|
||||
netif_carrier_off(dev);
|
||||
|
||||
lbs_debugfs_remove_one(priv);
|
||||
if (lbs_deinit_mesh(priv))
|
||||
lbs_deinit_mesh(priv);
|
||||
|
||||
if (lbs_rtap_supported(priv))
|
||||
device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
|
||||
|
||||
/* Delete the timeout of the currently processing command */
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
@ -196,7 +195,14 @@ int lbs_init_mesh(struct lbs_private *priv)
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MESH);
|
||||
|
||||
if (priv->mesh_fw_ver == MESH_FW_OLD) {
|
||||
priv->mesh_connect_status = LBS_DISCONNECTED;
|
||||
|
||||
/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
|
||||
/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
|
||||
/* 5.110.22 have mesh command with 0xa3 command id */
|
||||
/* 10.0.0.p0 FW brings in mesh config command with different id */
|
||||
/* Check FW version MSB and initialize mesh_fw_ver */
|
||||
if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
|
||||
/* Enable mesh, if supported, and work out which TLV it uses.
|
||||
0x100 + 291 is an unofficial value used in 5.110.20.pXX
|
||||
0x100 + 37 is the official value used in 5.110.21.pXX
|
||||
@ -218,7 +224,9 @@ int lbs_init_mesh(struct lbs_private *priv)
|
||||
priv->channel))
|
||||
priv->mesh_tlv = 0;
|
||||
}
|
||||
} else if (priv->mesh_fw_ver == MESH_FW_NEW) {
|
||||
} else
|
||||
if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
|
||||
(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
|
||||
/* 10.0.0.pXX new firmwares should succeed with TLV
|
||||
* 0x100+37; Do not invoke command with old TLV.
|
||||
*/
|
||||
@ -227,7 +235,12 @@ int lbs_init_mesh(struct lbs_private *priv)
|
||||
priv->channel))
|
||||
priv->mesh_tlv = 0;
|
||||
}
|
||||
|
||||
|
||||
if (priv->mesh_tlv) {
|
||||
sprintf(priv->mesh_ssid, "mesh");
|
||||
priv->mesh_ssid_len = 4;
|
||||
|
||||
lbs_add_mesh(priv);
|
||||
|
||||
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
|
||||
@ -416,10 +429,10 @@ struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
|
||||
struct net_device *dev, struct rxpd *rxpd)
|
||||
{
|
||||
if (priv->mesh_dev) {
|
||||
if (priv->mesh_fw_ver == MESH_FW_OLD) {
|
||||
if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
|
||||
if (rxpd->rx_control & RxPD_MESH_FRAME)
|
||||
dev = priv->mesh_dev;
|
||||
} else if (priv->mesh_fw_ver == MESH_FW_NEW) {
|
||||
} else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
|
||||
if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
|
||||
dev = priv->mesh_dev;
|
||||
}
|
||||
@ -432,9 +445,9 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
|
||||
struct net_device *dev, struct txpd *txpd)
|
||||
{
|
||||
if (dev == priv->mesh_dev) {
|
||||
if (priv->mesh_fw_ver == MESH_FW_OLD)
|
||||
if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
|
||||
txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
|
||||
else if (priv->mesh_fw_ver == MESH_FW_NEW)
|
||||
else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
|
||||
txpd->u.bss.bss_num = MESH_IFACE_ID;
|
||||
}
|
||||
}
|
||||
@ -538,7 +551,7 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
|
||||
* Command id is 0xac for v10 FW along with mesh interface
|
||||
* id in bits 14-13-12.
|
||||
*/
|
||||
if (priv->mesh_fw_ver == MESH_FW_NEW)
|
||||
if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
|
||||
command = CMD_MESH_CONFIG |
|
||||
(MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <net/lib80211.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
|
||||
/* Mesh statistics */
|
||||
struct lbs_mesh_stats {
|
||||
u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
|
||||
@ -46,11 +48,20 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
|
||||
/* Command handling */
|
||||
|
||||
struct cmd_ds_command;
|
||||
struct cmd_ds_mesh_access;
|
||||
struct cmd_ds_mesh_config;
|
||||
|
||||
int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
|
||||
u16 cmd_action, void *pdata_buf);
|
||||
int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
|
||||
u16 cmd_action, void *pdata_buf);
|
||||
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
|
||||
struct cmd_ds_mesh_access *cmd);
|
||||
int lbs_mesh_config_send(struct lbs_private *priv,
|
||||
struct cmd_ds_mesh_config *cmd,
|
||||
uint16_t action, uint16_t type);
|
||||
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
|
||||
|
||||
|
||||
|
||||
/* Persistent configuration */
|
||||
@ -75,4 +86,25 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
|
||||
uint32_t stringset, uint8_t *s);
|
||||
|
||||
|
||||
/* Accessors */
|
||||
|
||||
#define lbs_mesh_open(priv) (priv->mesh_open)
|
||||
#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED)
|
||||
|
||||
#else
|
||||
|
||||
#define lbs_init_mesh(priv)
|
||||
#define lbs_deinit_mesh(priv)
|
||||
#define lbs_add_mesh(priv)
|
||||
#define lbs_remove_mesh(priv)
|
||||
#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
|
||||
#define lbs_mesh_set_txpd(priv, dev, txpd)
|
||||
#define lbs_mesh_config(priv, enable, chan)
|
||||
#define lbs_mesh_open(priv) (0)
|
||||
#define lbs_mesh_connected(priv) (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -640,7 +640,7 @@ out:
|
||||
if (!priv->tx_pending_len)
|
||||
netif_wake_queue(priv->dev);
|
||||
}
|
||||
if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) {
|
||||
if (priv->mesh_dev && lbs_mesh_connected(priv)) {
|
||||
netif_carrier_on(priv->mesh_dev);
|
||||
if (!priv->tx_pending_len)
|
||||
netif_wake_queue(priv->mesh_dev);
|
||||
|
@ -198,7 +198,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
|
||||
if (priv->connect_status == LBS_CONNECTED)
|
||||
netif_wake_queue(priv->dev);
|
||||
|
||||
if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
|
||||
if (priv->mesh_dev && lbs_mesh_connected(priv))
|
||||
netif_wake_queue(priv->mesh_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
|
||||
|
@ -192,7 +192,7 @@ static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
|
||||
lbs_deb_enter(LBS_DEB_WEXT);
|
||||
|
||||
if ((priv->connect_status != LBS_CONNECTED) &&
|
||||
(priv->mesh_connect_status != LBS_CONNECTED))
|
||||
!lbs_mesh_connected(priv))
|
||||
memcpy(rates, lbs_bg_rates, MAX_RATES);
|
||||
else
|
||||
memcpy(rates, priv->curbssparams.rates, MAX_RATES);
|
||||
@ -298,6 +298,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
|
||||
struct iw_point *dwrq, char *extra)
|
||||
{
|
||||
@ -307,7 +308,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
|
||||
|
||||
/* Use nickname to indicate that mesh is on */
|
||||
|
||||
if (priv->mesh_connect_status == LBS_CONNECTED) {
|
||||
if (lbs_mesh_connected(priv)) {
|
||||
strncpy(extra, "Mesh", 12);
|
||||
extra[12] = '\0';
|
||||
dwrq->length = strlen(extra);
|
||||
@ -321,6 +322,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
|
||||
lbs_deb_leave(LBS_DEB_WEXT);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
|
||||
struct iw_param *vwrq, char *extra)
|
||||
@ -422,6 +424,7 @@ static int lbs_get_mode(struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
static int mesh_wlan_get_mode(struct net_device *dev,
|
||||
struct iw_request_info *info, u32 * uwrq,
|
||||
char *extra)
|
||||
@ -433,6 +436,7 @@ static int mesh_wlan_get_mode(struct net_device *dev,
|
||||
lbs_deb_leave(LBS_DEB_WEXT);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lbs_get_txpow(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
@ -863,7 +867,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
|
||||
|
||||
/* If we're not associated, all quality values are meaningless */
|
||||
if ((priv->connect_status != LBS_CONNECTED) &&
|
||||
(priv->mesh_connect_status != LBS_CONNECTED))
|
||||
!lbs_mesh_connected(priv))
|
||||
goto out;
|
||||
|
||||
/* Quality by RSSI */
|
||||
@ -1010,6 +1014,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
static int lbs_mesh_set_freq(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_freq *fwrq, char *extra)
|
||||
@ -1061,6 +1066,7 @@ out:
|
||||
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
|
||||
struct iw_param *vwrq, char *extra)
|
||||
@ -2108,6 +2114,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
static int lbs_mesh_get_essid(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_point *dwrq, char *extra)
|
||||
@ -2161,6 +2168,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
|
||||
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Connect to the AP or Ad-hoc Network with specific bssid
|
||||
@ -2267,7 +2275,13 @@ static const iw_handler lbs_handler[] = {
|
||||
(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
|
||||
(iw_handler) NULL, /* SIOCSIWPMKSA */
|
||||
};
|
||||
struct iw_handler_def lbs_handler_def = {
|
||||
.num_standard = ARRAY_SIZE(lbs_handler),
|
||||
.standard = (iw_handler *) lbs_handler,
|
||||
.get_wireless_stats = lbs_get_wireless_stats,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LIBERTAS_MESH
|
||||
static const iw_handler mesh_wlan_handler[] = {
|
||||
(iw_handler) NULL, /* SIOCSIWCOMMIT */
|
||||
(iw_handler) lbs_get_name, /* SIOCGIWNAME */
|
||||
@ -2325,14 +2339,10 @@ static const iw_handler mesh_wlan_handler[] = {
|
||||
(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
|
||||
(iw_handler) NULL, /* SIOCSIWPMKSA */
|
||||
};
|
||||
struct iw_handler_def lbs_handler_def = {
|
||||
.num_standard = ARRAY_SIZE(lbs_handler),
|
||||
.standard = (iw_handler *) lbs_handler,
|
||||
.get_wireless_stats = lbs_get_wireless_stats,
|
||||
};
|
||||
|
||||
struct iw_handler_def mesh_handler_def = {
|
||||
.num_standard = ARRAY_SIZE(mesh_wlan_handler),
|
||||
.standard = (iw_handler *) mesh_wlan_handler,
|
||||
.get_wireless_stats = lbs_get_wireless_stats,
|
||||
};
|
||||
#endif
|
||||
|
@ -436,6 +436,38 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
|
||||
}
|
||||
|
||||
|
||||
struct mac80211_hwsim_addr_match_data {
|
||||
bool ret;
|
||||
const u8 *addr;
|
||||
};
|
||||
|
||||
static void mac80211_hwsim_addr_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mac80211_hwsim_addr_match_data *md = data;
|
||||
if (memcmp(mac, md->addr, ETH_ALEN) == 0)
|
||||
md->ret = true;
|
||||
}
|
||||
|
||||
|
||||
static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct mac80211_hwsim_addr_match_data md;
|
||||
|
||||
if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0)
|
||||
return true;
|
||||
|
||||
md.ret = false;
|
||||
md.addr = addr;
|
||||
ieee80211_iterate_active_interfaces_atomic(data->hw,
|
||||
mac80211_hwsim_addr_iter,
|
||||
&md);
|
||||
|
||||
return md.ret;
|
||||
}
|
||||
|
||||
|
||||
static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@ -488,8 +520,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
|
||||
if (nskb == NULL)
|
||||
continue;
|
||||
|
||||
if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
|
||||
ETH_ALEN) == 0)
|
||||
if (mac80211_hwsim_addr_match(data2, hdr->addr1))
|
||||
ack = true;
|
||||
memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
|
||||
ieee80211_rx_irqsafe(data2->hw, nskb);
|
||||
@ -618,12 +649,26 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
|
||||
{
|
||||
struct mac80211_hwsim_data *data = hw->priv;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
static const char *chantypes[4] = {
|
||||
[NL80211_CHAN_NO_HT] = "noht",
|
||||
[NL80211_CHAN_HT20] = "ht20",
|
||||
[NL80211_CHAN_HT40MINUS] = "ht40-",
|
||||
[NL80211_CHAN_HT40PLUS] = "ht40+",
|
||||
};
|
||||
static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
|
||||
[IEEE80211_SMPS_AUTOMATIC] = "auto",
|
||||
[IEEE80211_SMPS_OFF] = "off",
|
||||
[IEEE80211_SMPS_STATIC] = "static",
|
||||
[IEEE80211_SMPS_DYNAMIC] = "dynamic",
|
||||
};
|
||||
|
||||
printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n",
|
||||
printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
|
||||
wiphy_name(hw->wiphy), __func__,
|
||||
conf->channel->center_freq,
|
||||
chantypes[conf->channel_type],
|
||||
!!(conf->flags & IEEE80211_CONF_IDLE),
|
||||
!!(conf->flags & IEEE80211_CONF_PS));
|
||||
!!(conf->flags & IEEE80211_CONF_PS),
|
||||
smps_modes[conf->smps_mode]);
|
||||
|
||||
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
|
||||
|
||||
@ -827,6 +872,31 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
{
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP:
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
break;
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
case IEEE80211_AMPDU_RX_STOP:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct ieee80211_ops mac80211_hwsim_ops =
|
||||
{
|
||||
.tx = mac80211_hwsim_tx,
|
||||
@ -841,6 +911,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
|
||||
.set_tim = mac80211_hwsim_set_tim,
|
||||
.conf_tx = mac80211_hwsim_conf_tx,
|
||||
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
|
||||
.ampdu_action = mac80211_hwsim_ampdu_action,
|
||||
};
|
||||
|
||||
|
||||
@ -1082,7 +1153,9 @@ static int __init init_mac80211_hwsim(void)
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
hw->flags = IEEE80211_HW_MFP_CAPABLE |
|
||||
IEEE80211_HW_SIGNAL_DBM;
|
||||
IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_SUPPORTS_STATIC_SMPS |
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
|
||||
|
||||
/* ask mac80211 to reserve space for magic */
|
||||
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
|
||||
|
@ -2594,23 +2594,9 @@ end:
|
||||
/*
|
||||
* driver/device initialization
|
||||
*/
|
||||
static int bcm4320a_early_init(struct usbnet *usbdev)
|
||||
{
|
||||
/* bcm4320a doesn't handle configuration parameters well. Try
|
||||
* set any and you get partially zeroed mac and broken device.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm4320b_early_init(struct usbnet *usbdev)
|
||||
static void rndis_copy_module_params(struct usbnet *usbdev)
|
||||
{
|
||||
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
|
||||
char buf[8];
|
||||
|
||||
/* Early initialization settings, setting these won't have effect
|
||||
* if called after generic_rndis_bind().
|
||||
*/
|
||||
|
||||
priv->param_country[0] = modparam_country[0];
|
||||
priv->param_country[1] = modparam_country[1];
|
||||
@ -2652,6 +2638,32 @@ static int bcm4320b_early_init(struct usbnet *usbdev)
|
||||
priv->param_workaround_interval = 500;
|
||||
else
|
||||
priv->param_workaround_interval = modparam_workaround_interval;
|
||||
}
|
||||
|
||||
static int bcm4320a_early_init(struct usbnet *usbdev)
|
||||
{
|
||||
/* copy module parameters for bcm4320a so that iwconfig reports txpower
|
||||
* and workaround parameter is copied to private structure correctly.
|
||||
*/
|
||||
rndis_copy_module_params(usbdev);
|
||||
|
||||
/* bcm4320a doesn't handle configuration parameters well. Try
|
||||
* set any and you get partially zeroed mac and broken device.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm4320b_early_init(struct usbnet *usbdev)
|
||||
{
|
||||
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
|
||||
char buf[8];
|
||||
|
||||
rndis_copy_module_params(usbdev);
|
||||
|
||||
/* Early initialization settings, setting these won't have effect
|
||||
* if called after generic_rndis_bind().
|
||||
*/
|
||||
|
||||
rndis_set_config_parameter_str(usbdev, "Country", priv->param_country);
|
||||
rndis_set_config_parameter_str(usbdev, "FrameBursting",
|
||||
|
@ -835,7 +835,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
|
||||
struct rxdone_entry_desc *rxdesc)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
|
||||
__le32 *rxd = entry_priv->desc;
|
||||
__le32 *rxwi = (__le32 *)entry->skb->data;
|
||||
@ -883,10 +882,8 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
|
||||
if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
|
||||
rxdesc->dev_flags |= RXDONE_MY_BSS;
|
||||
|
||||
if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) {
|
||||
if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD))
|
||||
rxdesc->dev_flags |= RXDONE_L2PAD;
|
||||
skbdesc->flags |= SKBDESC_L2_PADDED;
|
||||
}
|
||||
|
||||
if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
|
||||
rxdesc->flags |= RX_FLAG_SHORT_GI;
|
||||
@ -927,7 +924,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
|
||||
* Remove TXWI descriptor from start of buffer.
|
||||
*/
|
||||
skb_pull(entry->skb, RXWI_DESC_SIZE);
|
||||
skb_trim(entry->skb, rxdesc->size);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -295,9 +295,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
|
||||
|
||||
rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®);
|
||||
rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0);
|
||||
/* Don't use bulk in aggregation when working with USB 1.1 */
|
||||
rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN,
|
||||
(rt2x00dev->rx->usb_maxpacket == 512));
|
||||
rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
|
||||
rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);
|
||||
/*
|
||||
* Total room for RX frames in kilobytes, PBF might still exceed
|
||||
@ -573,41 +571,57 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
__le32 *rxd = (__le32 *)entry->skb->data;
|
||||
__le32 *rxi = (__le32 *)entry->skb->data;
|
||||
__le32 *rxwi;
|
||||
u32 rxd0;
|
||||
__le32 *rxd;
|
||||
u32 rxi0;
|
||||
u32 rxwi0;
|
||||
u32 rxwi1;
|
||||
u32 rxwi2;
|
||||
u32 rxwi3;
|
||||
u32 rxd0;
|
||||
int rx_pkt_len;
|
||||
|
||||
/*
|
||||
* RX frame format is :
|
||||
* | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad |
|
||||
* |<------------ rx_pkt_len -------------->|
|
||||
*/
|
||||
rt2x00_desc_read(rxi, 0, &rxi0);
|
||||
rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN);
|
||||
|
||||
rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE);
|
||||
|
||||
/*
|
||||
* FIXME : we need to check for rx_pkt_len validity
|
||||
*/
|
||||
rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len);
|
||||
|
||||
/*
|
||||
* Copy descriptor to the skbdesc->desc buffer, making it safe from
|
||||
* moving of frame data in rt2x00usb.
|
||||
*/
|
||||
memcpy(skbdesc->desc, rxd, skbdesc->desc_len);
|
||||
rxd = (__le32 *)skbdesc->desc;
|
||||
rxwi = &rxd[RXINFO_DESC_SIZE / sizeof(__le32)];
|
||||
memcpy(skbdesc->desc, rxi, skbdesc->desc_len);
|
||||
|
||||
/*
|
||||
* It is now safe to read the descriptor on all architectures.
|
||||
*/
|
||||
rt2x00_desc_read(rxd, 0, &rxd0);
|
||||
rt2x00_desc_read(rxwi, 0, &rxwi0);
|
||||
rt2x00_desc_read(rxwi, 1, &rxwi1);
|
||||
rt2x00_desc_read(rxwi, 2, &rxwi2);
|
||||
rt2x00_desc_read(rxwi, 3, &rxwi3);
|
||||
rt2x00_desc_read(rxd, 0, &rxd0);
|
||||
|
||||
if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR))
|
||||
if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))
|
||||
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
|
||||
|
||||
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
|
||||
rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
|
||||
rxdesc->cipher_status =
|
||||
rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR);
|
||||
rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR);
|
||||
}
|
||||
|
||||
if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) {
|
||||
if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {
|
||||
/*
|
||||
* Hardware has stripped IV/EIV data from 802.11 frame during
|
||||
* decryption. Unfortunately the descriptor doesn't contain
|
||||
@ -622,13 +636,11 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
|
||||
rxdesc->flags |= RX_FLAG_MMIC_ERROR;
|
||||
}
|
||||
|
||||
if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS))
|
||||
if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
|
||||
rxdesc->dev_flags |= RXDONE_MY_BSS;
|
||||
|
||||
if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) {
|
||||
if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
|
||||
rxdesc->dev_flags |= RXDONE_L2PAD;
|
||||
skbdesc->flags |= SKBDESC_L2_PADDED;
|
||||
}
|
||||
|
||||
if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
|
||||
rxdesc->flags |= RX_FLAG_SHORT_GI;
|
||||
@ -663,7 +675,6 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
|
||||
* Remove RXWI descriptor from start of buffer.
|
||||
*/
|
||||
skb_pull(entry->skb, skbdesc->desc_len);
|
||||
skb_trim(entry->skb, rxdesc->size);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -79,6 +79,8 @@
|
||||
*/
|
||||
#define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) )
|
||||
#define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) )
|
||||
#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) )
|
||||
#define RXD_DESC_SIZE ( 1 * sizeof(__le32) )
|
||||
|
||||
/*
|
||||
* TX Info structure
|
||||
@ -100,6 +102,54 @@
|
||||
#define TXINFO_W0_USB_DMA_NEXT_VALID FIELD32(0x40000000)
|
||||
#define TXINFO_W0_USB_DMA_TX_BURST FIELD32(0x80000000)
|
||||
|
||||
/*
|
||||
* RX Info structure
|
||||
*/
|
||||
|
||||
/*
|
||||
* Word 0
|
||||
*/
|
||||
|
||||
#define RXINFO_W0_USB_DMA_RX_PKT_LEN FIELD32(0x0000ffff)
|
||||
|
||||
/*
|
||||
* RX WI structure
|
||||
*/
|
||||
|
||||
/*
|
||||
* Word0
|
||||
*/
|
||||
#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff)
|
||||
#define RXWI_W0_KEY_INDEX FIELD32(0x00000300)
|
||||
#define RXWI_W0_BSSID FIELD32(0x00001c00)
|
||||
#define RXWI_W0_UDF FIELD32(0x0000e000)
|
||||
#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000)
|
||||
#define RXWI_W0_TID FIELD32(0xf0000000)
|
||||
|
||||
/*
|
||||
* Word1
|
||||
*/
|
||||
#define RXWI_W1_FRAG FIELD32(0x0000000f)
|
||||
#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0)
|
||||
#define RXWI_W1_MCS FIELD32(0x007f0000)
|
||||
#define RXWI_W1_BW FIELD32(0x00800000)
|
||||
#define RXWI_W1_SHORT_GI FIELD32(0x01000000)
|
||||
#define RXWI_W1_STBC FIELD32(0x06000000)
|
||||
#define RXWI_W1_PHYMODE FIELD32(0xc0000000)
|
||||
|
||||
/*
|
||||
* Word2
|
||||
*/
|
||||
#define RXWI_W2_RSSI0 FIELD32(0x000000ff)
|
||||
#define RXWI_W2_RSSI1 FIELD32(0x0000ff00)
|
||||
#define RXWI_W2_RSSI2 FIELD32(0x00ff0000)
|
||||
|
||||
/*
|
||||
* Word3
|
||||
*/
|
||||
#define RXWI_W3_SNR0 FIELD32(0x000000ff)
|
||||
#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
|
||||
|
||||
/*
|
||||
* RX descriptor format for RX Ring.
|
||||
*/
|
||||
@ -115,25 +165,25 @@
|
||||
* AMSDU: rx with 802.3 header, not 802.11 header.
|
||||
*/
|
||||
|
||||
#define RXINFO_W0_BA FIELD32(0x00000001)
|
||||
#define RXINFO_W0_DATA FIELD32(0x00000002)
|
||||
#define RXINFO_W0_NULLDATA FIELD32(0x00000004)
|
||||
#define RXINFO_W0_FRAG FIELD32(0x00000008)
|
||||
#define RXINFO_W0_UNICAST_TO_ME FIELD32(0x00000010)
|
||||
#define RXINFO_W0_MULTICAST FIELD32(0x00000020)
|
||||
#define RXINFO_W0_BROADCAST FIELD32(0x00000040)
|
||||
#define RXINFO_W0_MY_BSS FIELD32(0x00000080)
|
||||
#define RXINFO_W0_CRC_ERROR FIELD32(0x00000100)
|
||||
#define RXINFO_W0_CIPHER_ERROR FIELD32(0x00000600)
|
||||
#define RXINFO_W0_AMSDU FIELD32(0x00000800)
|
||||
#define RXINFO_W0_HTC FIELD32(0x00001000)
|
||||
#define RXINFO_W0_RSSI FIELD32(0x00002000)
|
||||
#define RXINFO_W0_L2PAD FIELD32(0x00004000)
|
||||
#define RXINFO_W0_AMPDU FIELD32(0x00008000)
|
||||
#define RXINFO_W0_DECRYPTED FIELD32(0x00010000)
|
||||
#define RXINFO_W0_PLCP_RSSI FIELD32(0x00020000)
|
||||
#define RXINFO_W0_CIPHER_ALG FIELD32(0x00040000)
|
||||
#define RXINFO_W0_LAST_AMSDU FIELD32(0x00080000)
|
||||
#define RXINFO_W0_PLCP_SIGNAL FIELD32(0xfff00000)
|
||||
#define RXD_W0_BA FIELD32(0x00000001)
|
||||
#define RXD_W0_DATA FIELD32(0x00000002)
|
||||
#define RXD_W0_NULLDATA FIELD32(0x00000004)
|
||||
#define RXD_W0_FRAG FIELD32(0x00000008)
|
||||
#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010)
|
||||
#define RXD_W0_MULTICAST FIELD32(0x00000020)
|
||||
#define RXD_W0_BROADCAST FIELD32(0x00000040)
|
||||
#define RXD_W0_MY_BSS FIELD32(0x00000080)
|
||||
#define RXD_W0_CRC_ERROR FIELD32(0x00000100)
|
||||
#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600)
|
||||
#define RXD_W0_AMSDU FIELD32(0x00000800)
|
||||
#define RXD_W0_HTC FIELD32(0x00001000)
|
||||
#define RXD_W0_RSSI FIELD32(0x00002000)
|
||||
#define RXD_W0_L2PAD FIELD32(0x00004000)
|
||||
#define RXD_W0_AMPDU FIELD32(0x00008000)
|
||||
#define RXD_W0_DECRYPTED FIELD32(0x00010000)
|
||||
#define RXD_W0_PLCP_RSSI FIELD32(0x00020000)
|
||||
#define RXD_W0_CIPHER_ALG FIELD32(0x00040000)
|
||||
#define RXD_W0_LAST_AMSDU FIELD32(0x00080000)
|
||||
#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000)
|
||||
|
||||
#endif /* RT2800USB_H */
|
||||
|
@ -103,6 +103,12 @@
|
||||
#define GET_DURATION(__size, __rate) (((__size) * 8 * 10) / (__rate))
|
||||
#define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate))
|
||||
|
||||
/*
|
||||
* Determine the number of L2 padding bytes required between the header and
|
||||
* the payload.
|
||||
*/
|
||||
#define L2PAD_SIZE(__hdrlen) (-(__hdrlen) & 3)
|
||||
|
||||
/*
|
||||
* Determine the alignment requirement,
|
||||
* to make sure the 802.11 payload is padded to a 4-byte boundrary
|
||||
|
@ -385,9 +385,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
||||
memset(&rxdesc, 0, sizeof(rxdesc));
|
||||
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
|
||||
|
||||
/* Trim buffer to correct size */
|
||||
skb_trim(entry->skb, rxdesc.size);
|
||||
|
||||
/*
|
||||
* The data behind the ieee80211 header must be
|
||||
* aligned on a 4 byte boundary.
|
||||
@ -404,11 +401,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
||||
(rxdesc.flags & RX_FLAG_IV_STRIPPED))
|
||||
rt2x00crypto_rx_insert_iv(entry->skb, header_length,
|
||||
&rxdesc);
|
||||
else if (rxdesc.dev_flags & RXDONE_L2PAD)
|
||||
else if (header_length &&
|
||||
(rxdesc.size > header_length) &&
|
||||
(rxdesc.dev_flags & RXDONE_L2PAD))
|
||||
rt2x00queue_remove_l2pad(entry->skb, header_length);
|
||||
else
|
||||
rt2x00queue_align_payload(entry->skb, header_length);
|
||||
|
||||
/* Trim buffer to correct size */
|
||||
skb_trim(entry->skb, rxdesc.size);
|
||||
|
||||
/*
|
||||
* Check if the frame was received using HT. In that case,
|
||||
* the rate is the MCS index and should be passed to mac80211
|
||||
|
@ -41,6 +41,9 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
|
||||
rt2x00pci_register_read(rt2x00dev, offset, reg);
|
||||
if (!rt2x00_get_field32(*reg, field))
|
||||
|
@ -177,55 +177,45 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length)
|
||||
|
||||
void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
|
||||
{
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
|
||||
unsigned int frame_length = skb->len;
|
||||
unsigned int payload_length = skb->len - header_length;
|
||||
unsigned int header_align = ALIGN_SIZE(skb, 0);
|
||||
unsigned int payload_align = ALIGN_SIZE(skb, header_length);
|
||||
unsigned int l2pad = 4 - (payload_align - header_align);
|
||||
unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0;
|
||||
|
||||
if (header_align == payload_align) {
|
||||
/*
|
||||
* Both header and payload must be moved the same
|
||||
* amount of bytes to align them properly. This means
|
||||
* we don't use the L2 padding but just move the entire
|
||||
* frame.
|
||||
*/
|
||||
rt2x00queue_align_frame(skb);
|
||||
} else if (!payload_align) {
|
||||
/*
|
||||
* Simple L2 padding, only the header needs to be moved,
|
||||
* the payload is already properly aligned.
|
||||
*/
|
||||
skb_push(skb, header_align);
|
||||
memmove(skb->data, skb->data + header_align, frame_length);
|
||||
skbdesc->flags |= SKBDESC_L2_PADDED;
|
||||
} else {
|
||||
/*
|
||||
*
|
||||
* Complicated L2 padding, both header and payload need
|
||||
* to be moved. By default we only move to the start
|
||||
* of the buffer, so our header alignment needs to be
|
||||
* increased if there is not enough room for the header
|
||||
* to be moved.
|
||||
*/
|
||||
if (payload_align > header_align)
|
||||
header_align += 4;
|
||||
/*
|
||||
* Adjust the header alignment if the payload needs to be moved more
|
||||
* than the header.
|
||||
*/
|
||||
if (payload_align > header_align)
|
||||
header_align += 4;
|
||||
|
||||
skb_push(skb, header_align);
|
||||
memmove(skb->data, skb->data + header_align, header_length);
|
||||
/* There is nothing to do if no alignment is needed */
|
||||
if (!header_align)
|
||||
return;
|
||||
|
||||
/* Reserve the amount of space needed in front of the frame */
|
||||
skb_push(skb, header_align);
|
||||
|
||||
/*
|
||||
* Move the header.
|
||||
*/
|
||||
memmove(skb->data, skb->data + header_align, header_length);
|
||||
|
||||
/* Move the payload, if present and if required */
|
||||
if (payload_length && payload_align)
|
||||
memmove(skb->data + header_length + l2pad,
|
||||
skb->data + header_length + l2pad + payload_align,
|
||||
frame_length - header_length);
|
||||
skbdesc->flags |= SKBDESC_L2_PADDED;
|
||||
}
|
||||
payload_length);
|
||||
|
||||
/* Trim the skb to the correct size */
|
||||
skb_trim(skb, header_length + l2pad + payload_length);
|
||||
}
|
||||
|
||||
void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
|
||||
{
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
|
||||
unsigned int l2pad = 4 - (header_length & 3);
|
||||
unsigned int l2pad = L2PAD_SIZE(header_length);
|
||||
|
||||
if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED))
|
||||
if (!l2pad)
|
||||
return;
|
||||
|
||||
memmove(skb->data + l2pad, skb->data, header_length);
|
||||
@ -346,7 +336,9 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
||||
* Header and alignment information.
|
||||
*/
|
||||
txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
|
||||
txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length);
|
||||
if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) &&
|
||||
(entry->skb->len > txdesc->header_length))
|
||||
txdesc->l2pad = L2PAD_SIZE(txdesc->header_length);
|
||||
|
||||
/*
|
||||
* Check whether this frame is to be acked.
|
||||
@ -387,10 +379,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
||||
|
||||
/*
|
||||
* Beacons and probe responses require the tsf timestamp
|
||||
* to be inserted into the frame.
|
||||
* to be inserted into the frame, except for a frame that has been injected
|
||||
* through a monitor interface. This latter is needed for testing a
|
||||
* monitor interface.
|
||||
*/
|
||||
if (ieee80211_is_beacon(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control))
|
||||
if ((ieee80211_is_beacon(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control)) &&
|
||||
(!(tx_info->flags & IEEE80211_TX_CTL_INJECTED)))
|
||||
__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
|
||||
|
||||
/*
|
||||
|
@ -92,8 +92,6 @@ enum data_queue_qid {
|
||||
* @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
|
||||
* @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by
|
||||
* mac80211 but was stripped for processing by the driver.
|
||||
* @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
|
||||
* the padded bytes are located between header and payload.
|
||||
* @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
|
||||
* don't try to pass it back.
|
||||
*/
|
||||
@ -101,8 +99,7 @@ enum skb_frame_desc_flags {
|
||||
SKBDESC_DMA_MAPPED_RX = 1 << 0,
|
||||
SKBDESC_DMA_MAPPED_TX = 1 << 1,
|
||||
SKBDESC_IV_STRIPPED = 1 << 2,
|
||||
SKBDESC_L2_PADDED = 1 << 3,
|
||||
SKBDESC_NOT_MAC80211 = 1 << 4,
|
||||
SKBDESC_NOT_MAC80211 = 1 << 3,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2354,6 +2354,7 @@ static struct usb_device_id rt73usb_device_table[] = {
|
||||
{ USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||
/* Buffalo */
|
||||
{ USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||
{ USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||
{ USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||
{ USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||
{ USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||
|
@ -132,7 +132,6 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
|
||||
|
||||
rx_status.antenna = (flags2 >> 15) & 1;
|
||||
/* TODO: improve signal/rssi reporting */
|
||||
rx_status.qual = flags2 & 0xFF;
|
||||
rx_status.signal = (flags2 >> 8) & 0x7F;
|
||||
/* XXX: is this correct? */
|
||||
rx_status.rate_idx = (flags >> 20) & 0xF;
|
||||
|
@ -247,6 +247,7 @@ struct wl1251_debugfs {
|
||||
struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
|
||||
|
||||
struct dentry *tx_queue_len;
|
||||
struct dentry *tx_queue_status;
|
||||
|
||||
struct dentry *retry_count;
|
||||
struct dentry *excessive_retries;
|
||||
|
@ -976,3 +976,72 @@ out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
u8 aifs, u16 txop)
|
||||
{
|
||||
struct wl1251_acx_ac_cfg *acx;
|
||||
int ret = 0;
|
||||
|
||||
wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d "
|
||||
"aifs %d txop %d", ac, cw_min, cw_max, aifs, txop);
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->ac = ac;
|
||||
acx->cw_min = cw_min;
|
||||
acx->cw_max = cw_max;
|
||||
acx->aifsn = aifs;
|
||||
acx->txop_limit = txop;
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1251_warning("acx ac cfg failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
|
||||
enum wl1251_acx_channel_type type,
|
||||
u8 tsid, enum wl1251_acx_ps_scheme ps_scheme,
|
||||
enum wl1251_acx_ack_policy ack_policy)
|
||||
{
|
||||
struct wl1251_acx_tid_cfg *acx;
|
||||
int ret = 0;
|
||||
|
||||
wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d "
|
||||
"ps_scheme %d ack_policy %d", queue, type, tsid,
|
||||
ps_scheme, ack_policy);
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->queue = queue;
|
||||
acx->type = type;
|
||||
acx->tsid = tsid;
|
||||
acx->ps_scheme = ps_scheme;
|
||||
acx->ack_policy = ack_policy;
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1251_warning("acx tid cfg failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1166,6 +1166,87 @@ struct wl1251_acx_wr_tbtt_and_dtim {
|
||||
u8 padding;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct wl1251_acx_ac_cfg {
|
||||
struct acx_header header;
|
||||
|
||||
/*
|
||||
* Access Category - The TX queue's access category
|
||||
* (refer to AccessCategory_enum)
|
||||
*/
|
||||
u8 ac;
|
||||
|
||||
/*
|
||||
* The contention window minimum size (in slots) for
|
||||
* the access class.
|
||||
*/
|
||||
u8 cw_min;
|
||||
|
||||
/*
|
||||
* The contention window maximum size (in slots) for
|
||||
* the access class.
|
||||
*/
|
||||
u16 cw_max;
|
||||
|
||||
/* The AIF value (in slots) for the access class. */
|
||||
u8 aifsn;
|
||||
|
||||
u8 reserved;
|
||||
|
||||
/* The TX Op Limit (in microseconds) for the access class. */
|
||||
u16 txop_limit;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
enum wl1251_acx_channel_type {
|
||||
CHANNEL_TYPE_DCF = 0,
|
||||
CHANNEL_TYPE_EDCF = 1,
|
||||
CHANNEL_TYPE_HCCA = 2,
|
||||
};
|
||||
|
||||
enum wl1251_acx_ps_scheme {
|
||||
/* regular ps: simple sending of packets */
|
||||
WL1251_ACX_PS_SCHEME_LEGACY = 0,
|
||||
|
||||
/* sending a packet triggers a unscheduled apsd downstream */
|
||||
WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1,
|
||||
|
||||
/* a pspoll packet will be sent before every data packet */
|
||||
WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2,
|
||||
|
||||
/* scheduled apsd mode */
|
||||
WL1251_ACX_PS_SCHEME_SAPSD = 3,
|
||||
};
|
||||
|
||||
enum wl1251_acx_ack_policy {
|
||||
WL1251_ACX_ACK_POLICY_LEGACY = 0,
|
||||
WL1251_ACX_ACK_POLICY_NO_ACK = 1,
|
||||
WL1251_ACX_ACK_POLICY_BLOCK = 2,
|
||||
};
|
||||
|
||||
struct wl1251_acx_tid_cfg {
|
||||
struct acx_header header;
|
||||
|
||||
/* tx queue id number (0-7) */
|
||||
u8 queue;
|
||||
|
||||
/* channel access type for the queue, enum wl1251_acx_channel_type */
|
||||
u8 type;
|
||||
|
||||
/* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */
|
||||
u8 tsid;
|
||||
|
||||
/* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */
|
||||
u8 ps_scheme;
|
||||
|
||||
/* the tx queue ack policy, enum wl1251_acx_ack_policy */
|
||||
u8 ack_policy;
|
||||
|
||||
u8 padding[3];
|
||||
|
||||
/* not supported */
|
||||
u32 apsdconf[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*************************************************************************
|
||||
|
||||
Host Interrupt Register (WiLink -> Host)
|
||||
@ -1322,5 +1403,11 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
|
||||
int wl1251_acx_rate_policies(struct wl1251 *wl);
|
||||
int wl1251_acx_mem_cfg(struct wl1251 *wl);
|
||||
int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
|
||||
int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
u8 aifs, u16 txop);
|
||||
int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
|
||||
enum wl1251_acx_channel_type type,
|
||||
u8 tsid, enum wl1251_acx_ps_scheme ps_scheme,
|
||||
enum wl1251_acx_ack_policy ack_policy);
|
||||
|
||||
#endif /* __WL1251_ACX_H__ */
|
||||
|
@ -237,6 +237,27 @@ static const struct file_operations tx_queue_len_ops = {
|
||||
.open = wl1251_open_file_generic,
|
||||
};
|
||||
|
||||
static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1251 *wl = file->private_data;
|
||||
char buf[3], status;
|
||||
int len;
|
||||
|
||||
if (wl->tx_queue_stopped)
|
||||
status = 's';
|
||||
else
|
||||
status = 'r';
|
||||
|
||||
len = scnprintf(buf, sizeof(buf), "%c\n", status);
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations tx_queue_status_ops = {
|
||||
.read = tx_queue_status_read,
|
||||
.open = wl1251_open_file_generic,
|
||||
};
|
||||
|
||||
static void wl1251_debugfs_delete_files(struct wl1251 *wl)
|
||||
{
|
||||
DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
|
||||
@ -331,6 +352,7 @@ static void wl1251_debugfs_delete_files(struct wl1251 *wl)
|
||||
DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data);
|
||||
|
||||
DEBUGFS_DEL(tx_queue_len);
|
||||
DEBUGFS_DEL(tx_queue_status);
|
||||
DEBUGFS_DEL(retry_count);
|
||||
DEBUGFS_DEL(excessive_retries);
|
||||
}
|
||||
@ -431,6 +453,7 @@ static int wl1251_debugfs_add_files(struct wl1251 *wl)
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
|
||||
|
||||
DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir);
|
||||
DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir);
|
||||
DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
|
||||
DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
|
||||
|
||||
|
@ -294,6 +294,11 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE);
|
||||
wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK);
|
||||
wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI);
|
||||
wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO);
|
||||
|
||||
out:
|
||||
kfree(config);
|
||||
return ret;
|
||||
|
@ -26,6 +26,53 @@
|
||||
|
||||
#include "wl1251.h"
|
||||
|
||||
enum {
|
||||
/* best effort/legacy */
|
||||
AC_BE = 0,
|
||||
|
||||
/* background */
|
||||
AC_BK = 1,
|
||||
|
||||
/* video */
|
||||
AC_VI = 2,
|
||||
|
||||
/* voice */
|
||||
AC_VO = 3,
|
||||
|
||||
/* broadcast dummy access category */
|
||||
AC_BCAST = 4,
|
||||
|
||||
NUM_ACCESS_CATEGORIES = 4
|
||||
};
|
||||
|
||||
/* following are defult values for the IE fields*/
|
||||
#define CWMIN_BK 15
|
||||
#define CWMIN_BE 15
|
||||
#define CWMIN_VI 7
|
||||
#define CWMIN_VO 3
|
||||
#define CWMAX_BK 1023
|
||||
#define CWMAX_BE 63
|
||||
#define CWMAX_VI 15
|
||||
#define CWMAX_VO 7
|
||||
|
||||
/* slot number setting to start transmission at PIFS interval */
|
||||
#define AIFS_PIFS 1
|
||||
|
||||
/*
|
||||
* slot number setting to start transmission at DIFS interval - normal DCF
|
||||
* access
|
||||
*/
|
||||
#define AIFS_DIFS 2
|
||||
|
||||
#define AIFSN_BK 7
|
||||
#define AIFSN_BE 3
|
||||
#define AIFSN_VI AIFS_PIFS
|
||||
#define AIFSN_VO AIFS_PIFS
|
||||
#define TXOP_BK 0
|
||||
#define TXOP_BE 0
|
||||
#define TXOP_VI 3008
|
||||
#define TXOP_VO 1504
|
||||
|
||||
int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
|
||||
int wl1251_hw_init_templates_config(struct wl1251 *wl);
|
||||
int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
|
||||
|
@ -395,6 +395,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
* the queue here, otherwise the queue will get too long.
|
||||
*/
|
||||
if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
|
||||
wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues");
|
||||
ieee80211_stop_queues(wl->hw);
|
||||
|
||||
/*
|
||||
@ -640,20 +641,25 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
* through the bss_info_changed() hook.
|
||||
*/
|
||||
ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
|
||||
wl->psm_requested) {
|
||||
wl1251_debug(DEBUG_PSM, "psm disabled");
|
||||
|
||||
wl->psm_requested = false;
|
||||
|
||||
if (wl->psm)
|
||||
if (wl->psm) {
|
||||
ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->power_level != wl->power_level) {
|
||||
ret = wl1251_acx_tx_power(wl, conf->power_level);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto out_sleep;
|
||||
|
||||
wl->power_level = conf->power_level;
|
||||
}
|
||||
@ -1273,6 +1279,43 @@ static struct ieee80211_channel wl1251_channels[] = {
|
||||
{ .hw_value = 13, .center_freq = 2472},
|
||||
};
|
||||
|
||||
static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
struct wl1251 *wl = hw->priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
|
||||
|
||||
ret = wl1251_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue),
|
||||
params->cw_min, params->cw_max,
|
||||
params->aifs, params->txop);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue),
|
||||
CHANNEL_TYPE_EDCF,
|
||||
wl1251_tx_get_queue(queue),
|
||||
WL1251_ACX_PS_SCHEME_LEGACY,
|
||||
WL1251_ACX_ACK_POLICY_LEGACY);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
out_sleep:
|
||||
wl1251_ps_elp_sleep(wl);
|
||||
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* can't be const, mac80211 writes to this */
|
||||
static struct ieee80211_supported_band wl1251_band_2ghz = {
|
||||
.channels = wl1251_channels,
|
||||
@ -1293,6 +1336,7 @@ static const struct ieee80211_ops wl1251_ops = {
|
||||
.hw_scan = wl1251_op_hw_scan,
|
||||
.bss_info_changed = wl1251_op_bss_info_changed,
|
||||
.set_rts_threshold = wl1251_op_set_rts_threshold,
|
||||
.conf_tx = wl1251_op_conf_tx,
|
||||
};
|
||||
|
||||
static int wl1251_register_hw(struct wl1251 *wl)
|
||||
@ -1338,6 +1382,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
|
||||
wl->hw->wiphy->max_scan_ssids = 1;
|
||||
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
|
||||
|
||||
wl->hw->queues = 4;
|
||||
|
||||
ret = wl1251_register_hw(wl);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
@ -26,7 +26,8 @@
|
||||
#include "wl1251_cmd.h"
|
||||
#include "wl1251_io.h"
|
||||
|
||||
#define WL1251_WAKEUP_TIMEOUT 2000
|
||||
/* in ms */
|
||||
#define WL1251_WAKEUP_TIMEOUT 100
|
||||
|
||||
void wl1251_elp_work(struct work_struct *work)
|
||||
{
|
||||
@ -67,7 +68,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)
|
||||
|
||||
int wl1251_ps_elp_wakeup(struct wl1251 *wl)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned long timeout, start;
|
||||
u32 elp_reg;
|
||||
|
||||
if (!wl->elp)
|
||||
@ -75,6 +76,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
|
||||
|
||||
wl1251_debug(DEBUG_PSM, "waking up chip from elp");
|
||||
|
||||
start = jiffies;
|
||||
timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
|
||||
|
||||
wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
|
||||
@ -95,8 +97,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
|
||||
}
|
||||
|
||||
wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
|
||||
jiffies_to_msecs(jiffies) -
|
||||
(jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
|
||||
jiffies_to_msecs(jiffies - start));
|
||||
|
||||
wl->elp = false;
|
||||
|
||||
|
@ -126,7 +126,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
|
||||
if (wl->rx_current_buffer)
|
||||
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
|
||||
|
||||
skb = dev_alloc_skb(length);
|
||||
skb = __dev_alloc_skb(length, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
wl1251_error("Couldn't allocate RX frame");
|
||||
return;
|
||||
|
@ -167,8 +167,7 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
|
||||
tx_hdr->expiry_time = cpu_to_le32(1 << 16);
|
||||
tx_hdr->id = id;
|
||||
|
||||
/* FIXME: how to get the correct queue id? */
|
||||
tx_hdr->xmit_queue = 0;
|
||||
tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
|
||||
wl1251_tx_control(tx_hdr, control, fc);
|
||||
wl1251_tx_frag_block_num(tx_hdr);
|
||||
@ -220,6 +219,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
|
||||
/* align the buffer on a 4-byte boundary */
|
||||
skb_reserve(skb, offset);
|
||||
memmove(skb->data, src, skb->len);
|
||||
tx_hdr = (struct tx_double_buffer_desc *) skb->data;
|
||||
} else {
|
||||
wl1251_info("No handler, fixme!");
|
||||
return -EINVAL;
|
||||
@ -237,8 +237,9 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
|
||||
|
||||
wl1251_mem_write(wl, addr, skb->data, len);
|
||||
|
||||
wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
|
||||
tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
|
||||
wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x "
|
||||
"queue %d", tx_hdr->id, skb, tx_hdr->length,
|
||||
tx_hdr->rate, tx_hdr->xmit_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define __WL1251_TX_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include "wl1251_acx.h"
|
||||
|
||||
/*
|
||||
*
|
||||
@ -209,6 +210,22 @@ struct tx_result {
|
||||
u8 done_2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static inline int wl1251_tx_get_queue(int queue)
|
||||
{
|
||||
switch (queue) {
|
||||
case 0:
|
||||
return QOS_AC_VO;
|
||||
case 1:
|
||||
return QOS_AC_VI;
|
||||
case 2:
|
||||
return QOS_AC_BE;
|
||||
case 3:
|
||||
return QOS_AC_BK;
|
||||
default:
|
||||
return QOS_AC_BE;
|
||||
}
|
||||
}
|
||||
|
||||
void wl1251_tx_work(struct work_struct *work);
|
||||
void wl1251_tx_complete(struct wl1251 *wl);
|
||||
void wl1251_tx_flush(struct wl1251 *wl);
|
||||
|
@ -1078,11 +1078,15 @@ static int eject_installer(struct usb_interface *intf)
|
||||
int r;
|
||||
|
||||
/* Find bulk out endpoint */
|
||||
endpoint = &iface_desc->endpoint[1].desc;
|
||||
if (usb_endpoint_dir_out(endpoint) &&
|
||||
usb_endpoint_xfer_bulk(endpoint)) {
|
||||
bulk_out_ep = endpoint->bEndpointAddress;
|
||||
} else {
|
||||
for (r = 1; r >= 0; r--) {
|
||||
endpoint = &iface_desc->endpoint[r].desc;
|
||||
if (usb_endpoint_dir_out(endpoint) &&
|
||||
usb_endpoint_xfer_bulk(endpoint)) {
|
||||
bulk_out_ep = endpoint->bEndpointAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (r == -1) {
|
||||
dev_err(&udev->dev,
|
||||
"zd1211rw: Could not find bulk out endpoint\n");
|
||||
return -ENODEV;
|
||||
|
@ -707,6 +707,10 @@ struct ieee80211_mgmt {
|
||||
u8 action;
|
||||
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
|
||||
} __attribute__ ((packed)) sa_query;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 smps_control;
|
||||
} __attribute__ ((packed)) ht_smps;
|
||||
} u;
|
||||
} __attribute__ ((packed)) action;
|
||||
} u;
|
||||
@ -771,7 +775,10 @@ struct ieee80211_bar {
|
||||
/**
|
||||
* struct ieee80211_mcs_info - MCS information
|
||||
* @rx_mask: RX mask
|
||||
* @rx_highest: highest supported RX rate
|
||||
* @rx_highest: highest supported RX rate. If set represents
|
||||
* the highest supported RX data rate in units of 1 Mbps.
|
||||
* If this field is 0 this value should not be used to
|
||||
* consider the highest RX data rate supported.
|
||||
* @tx_params: TX parameters
|
||||
*/
|
||||
struct ieee80211_mcs_info {
|
||||
@ -824,6 +831,7 @@ struct ieee80211_ht_cap {
|
||||
#define IEEE80211_HT_CAP_LDPC_CODING 0x0001
|
||||
#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002
|
||||
#define IEEE80211_HT_CAP_SM_PS 0x000C
|
||||
#define IEEE80211_HT_CAP_SM_PS_SHIFT 2
|
||||
#define IEEE80211_HT_CAP_GRN_FLD 0x0010
|
||||
#define IEEE80211_HT_CAP_SGI_20 0x0020
|
||||
#define IEEE80211_HT_CAP_SGI_40 0x0040
|
||||
@ -839,6 +847,7 @@ struct ieee80211_ht_cap {
|
||||
/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
|
||||
#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03
|
||||
#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C
|
||||
#define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2
|
||||
|
||||
/*
|
||||
* Maximum length of AMPDU that the STA can receive.
|
||||
@ -922,12 +931,17 @@ struct ieee80211_ht_info {
|
||||
#define IEEE80211_MAX_AMPDU_BUF 0x40
|
||||
|
||||
|
||||
/* Spatial Multiplexing Power Save Modes */
|
||||
/* Spatial Multiplexing Power Save Modes (for capability) */
|
||||
#define WLAN_HT_CAP_SM_PS_STATIC 0
|
||||
#define WLAN_HT_CAP_SM_PS_DYNAMIC 1
|
||||
#define WLAN_HT_CAP_SM_PS_INVALID 2
|
||||
#define WLAN_HT_CAP_SM_PS_DISABLED 3
|
||||
|
||||
/* for SM power control field lower two bits */
|
||||
#define WLAN_HT_SMPS_CONTROL_DISABLED 0
|
||||
#define WLAN_HT_SMPS_CONTROL_STATIC 1
|
||||
#define WLAN_HT_SMPS_CONTROL_DYNAMIC 3
|
||||
|
||||
/* Authentication algorithms */
|
||||
#define WLAN_AUTH_OPEN 0
|
||||
#define WLAN_AUTH_SHARED_KEY 1
|
||||
@ -1150,6 +1164,18 @@ enum ieee80211_spectrum_mgmt_actioncode {
|
||||
WLAN_ACTION_SPCT_CHL_SWITCH = 4,
|
||||
};
|
||||
|
||||
/* HT action codes */
|
||||
enum ieee80211_ht_actioncode {
|
||||
WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0,
|
||||
WLAN_HT_ACTION_SMPS = 1,
|
||||
WLAN_HT_ACTION_PSMP = 2,
|
||||
WLAN_HT_ACTION_PCO_PHASE = 3,
|
||||
WLAN_HT_ACTION_CSI = 4,
|
||||
WLAN_HT_ACTION_NONCOMPRESSED_BF = 5,
|
||||
WLAN_HT_ACTION_COMPRESSED_BF = 6,
|
||||
WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7,
|
||||
};
|
||||
|
||||
/* Security key length */
|
||||
enum ieee80211_key_len {
|
||||
WLAN_KEY_LEN_WEP40 = 5,
|
||||
|
@ -1578,7 +1578,7 @@ unsigned int ieee80211_hdrlen(__le16 fc);
|
||||
* @addr: the device MAC address
|
||||
* @iftype: the virtual interface type
|
||||
*/
|
||||
int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
|
||||
int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype);
|
||||
|
||||
/**
|
||||
@ -1589,9 +1589,27 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
|
||||
* @bssid: the network bssid (used only for iftype STATION and ADHOC)
|
||||
* @qos: build 802.11 QoS data frame
|
||||
*/
|
||||
int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
|
||||
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype, u8 *bssid, bool qos);
|
||||
|
||||
/**
|
||||
* ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
|
||||
*
|
||||
* Decode an IEEE 802.11n A-MSDU frame and convert it to a list of
|
||||
* 802.3 frames. The @list will be empty if the decode fails. The
|
||||
* @skb is consumed after the function returns.
|
||||
*
|
||||
* @skb: The input IEEE 802.11n A-MSDU frame.
|
||||
* @list: The output list of 802.3 frames. It must be allocated and
|
||||
* initialized by by the caller.
|
||||
* @addr: The device MAC address.
|
||||
* @iftype: The device interface type.
|
||||
* @extra_headroom: The hardware extra headroom for SKBs in the @list.
|
||||
*/
|
||||
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||
const u8 *addr, enum nl80211_iftype iftype,
|
||||
const unsigned int extra_headroom);
|
||||
|
||||
/**
|
||||
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
|
||||
* @skb: the data frame
|
||||
|
@ -597,8 +597,10 @@ enum ieee80211_conf_flags {
|
||||
* @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed
|
||||
* @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
|
||||
* @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
|
||||
* @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
|
||||
*/
|
||||
enum ieee80211_conf_changed {
|
||||
IEEE80211_CONF_CHANGE_SMPS = BIT(1),
|
||||
IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2),
|
||||
IEEE80211_CONF_CHANGE_MONITOR = BIT(3),
|
||||
IEEE80211_CONF_CHANGE_PS = BIT(4),
|
||||
@ -608,6 +610,21 @@ enum ieee80211_conf_changed {
|
||||
IEEE80211_CONF_CHANGE_IDLE = BIT(8),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_smps_mode - spatial multiplexing power save mode
|
||||
*
|
||||
* @
|
||||
*/
|
||||
enum ieee80211_smps_mode {
|
||||
IEEE80211_SMPS_AUTOMATIC,
|
||||
IEEE80211_SMPS_OFF,
|
||||
IEEE80211_SMPS_STATIC,
|
||||
IEEE80211_SMPS_DYNAMIC,
|
||||
|
||||
/* keep last */
|
||||
IEEE80211_SMPS_NUM_MODES,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_conf - configuration of the device
|
||||
*
|
||||
@ -636,6 +653,10 @@ enum ieee80211_conf_changed {
|
||||
* @short_frame_max_tx_count: Maximum number of transmissions for a "short"
|
||||
* frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
|
||||
* number of transmissions not the number of retries
|
||||
*
|
||||
* @smps_mode: spatial multiplexing powersave mode; note that
|
||||
* %IEEE80211_SMPS_STATIC is used when the device is not
|
||||
* configured for an HT channel
|
||||
*/
|
||||
struct ieee80211_conf {
|
||||
u32 flags;
|
||||
@ -648,6 +669,7 @@ struct ieee80211_conf {
|
||||
|
||||
struct ieee80211_channel *channel;
|
||||
enum nl80211_channel_type channel_type;
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -659,12 +681,14 @@ struct ieee80211_conf {
|
||||
* @type: type of this virtual interface
|
||||
* @bss_conf: BSS configuration for this interface, either our own
|
||||
* or the BSS we're associated to
|
||||
* @addr: address of this interface
|
||||
* @drv_priv: data area for driver use, will always be aligned to
|
||||
* sizeof(void *).
|
||||
*/
|
||||
struct ieee80211_vif {
|
||||
enum nl80211_iftype type;
|
||||
struct ieee80211_bss_conf bss_conf;
|
||||
u8 addr[ETH_ALEN];
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
|
||||
};
|
||||
@ -928,6 +952,16 @@ enum ieee80211_tkip_key_type {
|
||||
* @IEEE80211_HW_BEACON_FILTER:
|
||||
* Hardware supports dropping of irrelevant beacon frames to
|
||||
* avoid waking up cpu.
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_STATIC_SMPS:
|
||||
* Hardware supports static spatial multiplexing powersave,
|
||||
* ie. can turn off all but one chain even on HT connections
|
||||
* that should be using more chains.
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS:
|
||||
* Hardware supports dynamic spatial multiplexing powersave,
|
||||
* ie. can turn off all but one chain and then wake the rest
|
||||
* up as required after, for example, rts/cts handshake.
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
|
||||
@ -945,6 +979,8 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12,
|
||||
IEEE80211_HW_MFP_CAPABLE = 1<<13,
|
||||
IEEE80211_HW_BEACON_FILTER = 1<<14,
|
||||
IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15,
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1212,6 +1248,31 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
|
||||
* signal strength threshold checking.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Spatial multiplexing power save
|
||||
*
|
||||
* SMPS (Spatial multiplexing power save) is a mechanism to conserve
|
||||
* power in an 802.11n implementation. For details on the mechanism
|
||||
* and rationale, please refer to 802.11 (as amended by 802.11n-2009)
|
||||
* "11.2.3 SM power save".
|
||||
*
|
||||
* The mac80211 implementation is capable of sending action frames
|
||||
* to update the AP about the station's SMPS mode, and will instruct
|
||||
* the driver to enter the specific mode. It will also announce the
|
||||
* requested SMPS mode during the association handshake. Hardware
|
||||
* support for this feature is required, and can be indicated by
|
||||
* hardware flags.
|
||||
*
|
||||
* The default mode will be "automatic", which nl80211/cfg80211
|
||||
* defines to be dynamic SMPS in (regular) powersave, and SMPS
|
||||
* turned off otherwise.
|
||||
*
|
||||
* To support this feature, the driver must set the appropriate
|
||||
* hardware support flags, and handle the SMPS flag to the config()
|
||||
* operation. It will then with this mechanism be instructed to
|
||||
* enter the requested SMPS mode while associated to an HT AP.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Frame filtering
|
||||
*
|
||||
|
@ -96,18 +96,6 @@ menuconfig MAC80211_DEBUG_MENU
|
||||
---help---
|
||||
This option collects various mac80211 debug settings.
|
||||
|
||||
config MAC80211_DEBUG_PACKET_ALIGNMENT
|
||||
bool "Enable packet alignment debugging"
|
||||
depends on MAC80211_DEBUG_MENU
|
||||
---help---
|
||||
This option is recommended for driver authors and strongly
|
||||
discouraged for everybody else, it will trigger a warning
|
||||
when a driver hands mac80211 a buffer that is aligned in
|
||||
a way that will cause problems with the IP stack on some
|
||||
architectures.
|
||||
|
||||
Say N unless you're writing a mac80211 based driver.
|
||||
|
||||
config MAC80211_NOINLINE
|
||||
bool "Do not inline TX/RX handlers"
|
||||
depends on MAC80211_DEBUG_MENU
|
||||
|
@ -41,8 +41,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
sta->sta.addr, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (drv_ampdu_action(local, &sta->sdata->vif,
|
||||
IEEE80211_AMPDU_RX_STOP,
|
||||
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL))
|
||||
printk(KERN_DEBUG "HW problem - can not stop rx "
|
||||
"aggregation for tid %d\n", tid);
|
||||
@ -83,12 +82,11 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
|
||||
u16 initiator, u16 reason)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, ra);
|
||||
sta = sta_info_get(sdata, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
@ -136,7 +134,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer "
|
||||
"for addba resp frame\n", sdata->dev->name);
|
||||
"for addba resp frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -144,10 +142,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
|
||||
@ -281,8 +279,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = drv_ampdu_action(local, &sta->sdata->vif,
|
||||
IEEE80211_AMPDU_RX_START,
|
||||
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
|
@ -58,17 +58,17 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer "
|
||||
"for addba request frame\n", sdata->dev->name);
|
||||
"for addba request frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
|
||||
@ -104,7 +104,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
|
||||
skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer for "
|
||||
"bar frame\n", sdata->dev->name);
|
||||
"bar frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
@ -113,7 +113,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
|
||||
bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
|
||||
IEEE80211_STYPE_BACK_REQ);
|
||||
memcpy(bar->ra, ra, ETH_ALEN);
|
||||
memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(bar->ta, sdata->vif.addr, ETH_ALEN);
|
||||
bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
|
||||
bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
|
||||
bar_control |= (u16)(tid << 12);
|
||||
@ -144,7 +144,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
||||
|
||||
ret = drv_ampdu_action(local, &sta->sdata->vif,
|
||||
ret = drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_STOP,
|
||||
&sta->sta, tid, NULL);
|
||||
|
||||
@ -303,8 +303,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
|
||||
|
||||
start_seq_num = sta->tid_seq[tid];
|
||||
|
||||
ret = drv_ampdu_action(local, &sdata->vif,
|
||||
IEEE80211_AMPDU_TX_START,
|
||||
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
|
||||
pubsta, tid, &start_seq_num);
|
||||
|
||||
if (ret) {
|
||||
@ -420,7 +419,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
||||
ieee80211_agg_splice_finish(local, sta, tid);
|
||||
spin_unlock(&local->ampdu_lock);
|
||||
|
||||
drv_ampdu_action(local, &sta->sdata->vif,
|
||||
drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
&sta->sta, tid, NULL);
|
||||
}
|
||||
@ -441,7 +440,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
sta = sta_info_get(sdata, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
@ -489,7 +488,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "%s: Not enough memory, "
|
||||
"dropping start BA session", skb->dev->name);
|
||||
"dropping start BA session", sdata->name);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -564,7 +563,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
sta = sta_info_get(sdata, ra);
|
||||
if (!sta) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
|
||||
@ -621,7 +620,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "%s: Not enough memory, "
|
||||
"dropping stop BA session", skb->dev->name);
|
||||
"dropping stop BA session", sdata->name);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
rcu_read_lock();
|
||||
|
||||
if (mac_addr) {
|
||||
sta = sta_info_get(sdata->local, mac_addr);
|
||||
sta = sta_info_get(sdata, mac_addr);
|
||||
if (!sta) {
|
||||
ieee80211_key_free(key);
|
||||
err = -ENOENT;
|
||||
@ -181,7 +181,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (mac_addr) {
|
||||
ret = -ENOENT;
|
||||
|
||||
sta = sta_info_get(sdata->local, mac_addr);
|
||||
sta = sta_info_get(sdata, mac_addr);
|
||||
if (!sta)
|
||||
goto out_unlock;
|
||||
|
||||
@ -228,7 +228,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
rcu_read_lock();
|
||||
|
||||
if (mac_addr) {
|
||||
sta = sta_info_get(sdata->local, mac_addr);
|
||||
sta = sta_info_get(sdata, mac_addr);
|
||||
if (!sta)
|
||||
goto out;
|
||||
|
||||
@ -415,15 +415,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 *mac, struct station_info *sinfo)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sta_info *sta;
|
||||
int ret = -ENOENT;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* XXX: verify sta->dev == dev */
|
||||
|
||||
sta = sta_info_get(local, mac);
|
||||
sta = sta_info_get(sdata, mac);
|
||||
if (sta) {
|
||||
ret = 0;
|
||||
sta_set_sinfo(sta, sinfo);
|
||||
@ -732,7 +730,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
} else
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (compare_ether_addr(mac, dev->dev_addr) == 0)
|
||||
if (compare_ether_addr(mac, sdata->vif.addr) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (is_multicast_ether_addr(mac))
|
||||
@ -779,8 +777,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (mac) {
|
||||
rcu_read_lock();
|
||||
|
||||
/* XXX: get sta belonging to dev */
|
||||
sta = sta_info_get(local, mac);
|
||||
sta = sta_info_get(sdata, mac);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
@ -801,14 +798,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
u8 *mac,
|
||||
struct station_parameters *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *vlansdata;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* XXX: get sta belonging to dev */
|
||||
sta = sta_info_get(local, mac);
|
||||
sta = sta_info_get(sdata, mac);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
@ -847,7 +844,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 *dst, u8 *next_hop)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct mesh_path *mpath;
|
||||
struct sta_info *sta;
|
||||
@ -856,7 +852,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, next_hop);
|
||||
sta = sta_info_get(sdata, next_hop);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
@ -895,7 +891,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u8 *dst, u8 *next_hop)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct mesh_path *mpath;
|
||||
struct sta_info *sta;
|
||||
@ -904,7 +899,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, next_hop);
|
||||
sta = sta_info_get(sdata, next_hop);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
@ -1324,6 +1319,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
|
||||
}
|
||||
#endif
|
||||
|
||||
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode)
|
||||
{
|
||||
const u8 *ap;
|
||||
enum ieee80211_smps_mode old_req;
|
||||
int err;
|
||||
|
||||
old_req = sdata->u.mgd.req_smps;
|
||||
sdata->u.mgd.req_smps = smps_mode;
|
||||
|
||||
if (old_req == smps_mode &&
|
||||
smps_mode != IEEE80211_SMPS_AUTOMATIC)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If not associated, or current association is not an HT
|
||||
* association, there's no need to send an action frame.
|
||||
*/
|
||||
if (!sdata->u.mgd.associated ||
|
||||
sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
|
||||
mutex_lock(&sdata->local->iflist_mtx);
|
||||
ieee80211_recalc_smps(sdata->local, sdata);
|
||||
mutex_unlock(&sdata->local->iflist_mtx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ap = sdata->u.mgd.associated->cbss.bssid;
|
||||
|
||||
if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
|
||||
if (sdata->u.mgd.powersave)
|
||||
smps_mode = IEEE80211_SMPS_DYNAMIC;
|
||||
else
|
||||
smps_mode = IEEE80211_SMPS_OFF;
|
||||
}
|
||||
|
||||
/* send SM PS frame to AP */
|
||||
err = ieee80211_send_smps_action(sdata, smps_mode,
|
||||
ap, ap);
|
||||
if (err)
|
||||
sdata->u.mgd.req_smps = old_req;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
||||
bool enabled, int timeout)
|
||||
{
|
||||
@ -1341,6 +1380,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
||||
sdata->u.mgd.powersave = enabled;
|
||||
conf->dynamic_ps_timeout = timeout;
|
||||
|
||||
/* no change, but if automatic follow powersave */
|
||||
mutex_lock(&sdata->u.mgd.mtx);
|
||||
__ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
|
||||
mutex_unlock(&sdata->u.mgd.mtx);
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
|
||||
@ -1356,15 +1400,25 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
int i, err = -EINVAL;
|
||||
int i;
|
||||
u32 target_rate;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
/*
|
||||
* This _could_ be supported by providing a hook for
|
||||
* drivers for this function, but at this point it
|
||||
* doesn't seem worth bothering.
|
||||
*/
|
||||
if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
|
||||
/*
|
||||
* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
|
||||
* target_rate = X, rate->fixed = 1 means only rate X
|
||||
* target_rate = X, rate->fixed = 0 means all rates <= X */
|
||||
* target_rate = X, rate->fixed = 0 means all rates <= X
|
||||
*/
|
||||
sdata->max_ratectrl_rateidx = -1;
|
||||
sdata->force_unicast_rateidx = -1;
|
||||
|
||||
@ -1375,20 +1429,18 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
||||
else
|
||||
return 0;
|
||||
|
||||
for (i=0; i< sband->n_bitrates; i++) {
|
||||
struct ieee80211_rate *brate = &sband->bitrates[i];
|
||||
int this_rate = brate->bitrate;
|
||||
for (i = 0; i< sband->n_bitrates; i++) {
|
||||
if (target_rate != sband->bitrates[i].bitrate)
|
||||
continue;
|
||||
|
||||
if (target_rate == this_rate) {
|
||||
sdata->max_ratectrl_rateidx = i;
|
||||
if (mask->fixed)
|
||||
sdata->force_unicast_rateidx = i;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
/* requested bitrate found */
|
||||
sdata->max_ratectrl_rateidx = i;
|
||||
if (mask->fixed)
|
||||
sdata->force_unicast_rateidx = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct cfg80211_ops mac80211_config_ops = {
|
||||
|
@ -56,7 +56,7 @@ KEY_CONF_FILE(keyidx, D);
|
||||
KEY_CONF_FILE(hw_key_idx, D);
|
||||
KEY_FILE(flags, X);
|
||||
KEY_FILE(tx_rx_count, D);
|
||||
KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n");
|
||||
KEY_READ(ifindex, sdata->name, IFNAMSIZ + 2, "%s\n");
|
||||
KEY_OPS(ifindex);
|
||||
|
||||
static ssize_t key_algorithm_read(struct file *file,
|
||||
|
@ -41,6 +41,30 @@ static ssize_t ieee80211_if_read(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ieee80211_if_write(
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
const char __user *userbuf,
|
||||
size_t count, loff_t *ppos,
|
||||
ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
|
||||
{
|
||||
u8 *buf;
|
||||
ssize_t ret = -ENODEV;
|
||||
|
||||
buf = kzalloc(count, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buf, userbuf, count))
|
||||
return -EFAULT;
|
||||
|
||||
rtnl_lock();
|
||||
if (sdata->dev->reg_state == NETREG_REGISTERED)
|
||||
ret = (*write)(sdata, buf, count);
|
||||
rtnl_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define IEEE80211_IF_FMT(name, field, format_string) \
|
||||
static ssize_t ieee80211_if_fmt_##name( \
|
||||
const struct ieee80211_sub_if_data *sdata, char *buf, \
|
||||
@ -71,7 +95,7 @@ static ssize_t ieee80211_if_fmt_##name( \
|
||||
return scnprintf(buf, buflen, "%pM\n", sdata->field); \
|
||||
}
|
||||
|
||||
#define __IEEE80211_IF_FILE(name) \
|
||||
#define __IEEE80211_IF_FILE(name, _write) \
|
||||
static ssize_t ieee80211_if_read_##name(struct file *file, \
|
||||
char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
@ -82,12 +106,24 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \
|
||||
} \
|
||||
static const struct file_operations name##_ops = { \
|
||||
.read = ieee80211_if_read_##name, \
|
||||
.write = (_write), \
|
||||
.open = mac80211_open_file_generic, \
|
||||
}
|
||||
|
||||
#define __IEEE80211_IF_FILE_W(name) \
|
||||
static ssize_t ieee80211_if_write_##name(struct file *file, \
|
||||
const char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
return ieee80211_if_write(file->private_data, userbuf, count, \
|
||||
ppos, ieee80211_if_parse_##name); \
|
||||
} \
|
||||
__IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
|
||||
|
||||
|
||||
#define IEEE80211_IF_FILE(name, field, format) \
|
||||
IEEE80211_IF_FMT_##format(name, field) \
|
||||
__IEEE80211_IF_FILE(name)
|
||||
__IEEE80211_IF_FILE(name, NULL)
|
||||
|
||||
/* common attributes */
|
||||
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
|
||||
@ -99,6 +135,70 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
|
||||
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
|
||||
IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
|
||||
|
||||
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int err;
|
||||
|
||||
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) &&
|
||||
smps_mode == IEEE80211_SMPS_STATIC)
|
||||
return -EINVAL;
|
||||
|
||||
/* auto should be dynamic if in PS mode */
|
||||
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) &&
|
||||
(smps_mode == IEEE80211_SMPS_DYNAMIC ||
|
||||
smps_mode == IEEE80211_SMPS_AUTOMATIC))
|
||||
return -EINVAL;
|
||||
|
||||
/* supported only on managed interfaces for now */
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
err = __ieee80211_request_smps(sdata, smps_mode);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
|
||||
[IEEE80211_SMPS_AUTOMATIC] = "auto",
|
||||
[IEEE80211_SMPS_OFF] = "off",
|
||||
[IEEE80211_SMPS_STATIC] = "static",
|
||||
[IEEE80211_SMPS_DYNAMIC] = "dynamic",
|
||||
};
|
||||
|
||||
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
|
||||
char *buf, int buflen)
|
||||
{
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return snprintf(buf, buflen, "request: %s\nused: %s\n",
|
||||
smps_modes[sdata->u.mgd.req_smps],
|
||||
smps_modes[sdata->u.mgd.ap_smps]);
|
||||
}
|
||||
|
||||
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
|
||||
const char *buf, int buflen)
|
||||
{
|
||||
enum ieee80211_smps_mode mode;
|
||||
|
||||
for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
|
||||
if (strncmp(buf, smps_modes[mode], buflen) == 0) {
|
||||
int err = ieee80211_set_smps(sdata, mode);
|
||||
if (!err)
|
||||
return buflen;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
__IEEE80211_IF_FILE_W(smps);
|
||||
|
||||
/* AP attributes */
|
||||
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
|
||||
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
|
||||
@ -109,7 +209,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
|
||||
return scnprintf(buf, buflen, "%u\n",
|
||||
skb_queue_len(&sdata->u.ap.ps_bc_buf));
|
||||
}
|
||||
__IEEE80211_IF_FILE(num_buffered_multicast);
|
||||
__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
|
||||
|
||||
/* WDS attributes */
|
||||
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
|
||||
@ -158,6 +258,10 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
|
||||
debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
|
||||
sdata, &name##_ops);
|
||||
|
||||
#define DEBUGFS_ADD_MODE(name, mode) \
|
||||
debugfs_create_file(#name, mode, sdata->debugfs.dir, \
|
||||
sdata, &name##_ops);
|
||||
|
||||
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, sta);
|
||||
@ -167,6 +271,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
||||
DEBUGFS_ADD(bssid, sta);
|
||||
DEBUGFS_ADD(aid, sta);
|
||||
DEBUGFS_ADD(capab, sta);
|
||||
DEBUGFS_ADD_MODE(smps, 0600);
|
||||
}
|
||||
|
||||
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
|
||||
@ -280,16 +385,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
|
||||
}
|
||||
}
|
||||
|
||||
static int notif_registered;
|
||||
|
||||
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
char buf[10+IFNAMSIZ];
|
||||
|
||||
if (!notif_registered)
|
||||
return;
|
||||
|
||||
sprintf(buf, "netdev:%s", sdata->dev->name);
|
||||
sprintf(buf, "netdev:%s", sdata->name);
|
||||
sdata->debugfs.dir = debugfs_create_dir(buf,
|
||||
sdata->local->hw.wiphy->debugfsdir);
|
||||
add_files(sdata);
|
||||
@ -304,58 +404,18 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
|
||||
sdata->debugfs.dir = NULL;
|
||||
}
|
||||
|
||||
static int netdev_notify(struct notifier_block *nb,
|
||||
unsigned long state,
|
||||
void *ndev)
|
||||
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct net_device *dev = ndev;
|
||||
struct dentry *dir;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
char buf[10+IFNAMSIZ];
|
||||
|
||||
if (state != NETDEV_CHANGENAME)
|
||||
return 0;
|
||||
|
||||
if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
|
||||
return 0;
|
||||
|
||||
if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
|
||||
return 0;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
char buf[10 + IFNAMSIZ];
|
||||
|
||||
dir = sdata->debugfs.dir;
|
||||
|
||||
if (!dir)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
sprintf(buf, "netdev:%s", dev->name);
|
||||
sprintf(buf, "netdev:%s", sdata->name);
|
||||
if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
|
||||
printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
|
||||
"dir to %s\n", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block mac80211_debugfs_netdev_notifier = {
|
||||
.notifier_call = netdev_notify,
|
||||
};
|
||||
|
||||
void ieee80211_debugfs_netdev_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
|
||||
if (err) {
|
||||
printk(KERN_ERR
|
||||
"mac80211: failed to install netdev notifier,"
|
||||
" disabling per-netdev debugfs!\n");
|
||||
} else
|
||||
notif_registered = 1;
|
||||
}
|
||||
|
||||
void ieee80211_debugfs_netdev_exit(void)
|
||||
{
|
||||
unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
|
||||
notif_registered = 0;
|
||||
}
|
||||
|
@ -6,8 +6,7 @@
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_debugfs_netdev_init(void);
|
||||
void ieee80211_debugfs_netdev_exit(void);
|
||||
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata);
|
||||
#else
|
||||
static inline void ieee80211_debugfs_add_netdev(
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
@ -15,10 +14,8 @@ static inline void ieee80211_debugfs_add_netdev(
|
||||
static inline void ieee80211_debugfs_remove_netdev(
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{}
|
||||
static inline void ieee80211_debugfs_netdev_init(void)
|
||||
{}
|
||||
|
||||
static inline void ieee80211_debugfs_netdev_exit(void)
|
||||
static inline void ieee80211_debugfs_rename_netdev(
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{}
|
||||
#endif
|
||||
|
||||
|
@ -44,7 +44,7 @@ static const struct file_operations sta_ ##name## _ops = { \
|
||||
STA_OPS(name)
|
||||
|
||||
STA_FILE(aid, sta.aid, D);
|
||||
STA_FILE(dev, sdata->dev->name, S);
|
||||
STA_FILE(dev, sdata->name, S);
|
||||
STA_FILE(rx_packets, rx_packets, LU);
|
||||
STA_FILE(tx_packets, tx_packets, LU);
|
||||
STA_FILE(rx_bytes, rx_bytes, LU);
|
||||
@ -160,7 +160,12 @@ STA_OPS(agg_status);
|
||||
static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[200], *p = buf;
|
||||
#define PRINT_HT_CAP(_cond, _str) \
|
||||
do { \
|
||||
if (_cond) \
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \
|
||||
} while (0)
|
||||
char buf[1024], *p = buf;
|
||||
int i;
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap;
|
||||
@ -168,15 +173,64 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n",
|
||||
htc->ht_supported ? "" : "not ");
|
||||
if (htc->ht_supported) {
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap);
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap);
|
||||
|
||||
PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDCP");
|
||||
PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40");
|
||||
PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20");
|
||||
|
||||
PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 0, "Static SM Power Save");
|
||||
PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 1, "Dynamic SM Power Save");
|
||||
PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 3, "SM Power Save disabled");
|
||||
|
||||
PRINT_HT_CAP((htc->cap & BIT(4)), "RX Greenfield");
|
||||
PRINT_HT_CAP((htc->cap & BIT(5)), "RX HT20 SGI");
|
||||
PRINT_HT_CAP((htc->cap & BIT(6)), "RX HT40 SGI");
|
||||
PRINT_HT_CAP((htc->cap & BIT(7)), "TX STBC");
|
||||
|
||||
PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 0, "No RX STBC");
|
||||
PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 1, "RX STBC 1-stream");
|
||||
PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 2, "RX STBC 2-streams");
|
||||
PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 3, "RX STBC 3-streams");
|
||||
|
||||
PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack");
|
||||
|
||||
PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: "
|
||||
"3839 bytes");
|
||||
PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: "
|
||||
"7935 bytes");
|
||||
|
||||
/*
|
||||
* For beacons and probe response this would mean the BSS
|
||||
* does or does not allow the usage of DSSS/CCK HT40.
|
||||
* Otherwise it means the STA does or does not use
|
||||
* DSSS/CCK HT40.
|
||||
*/
|
||||
PRINT_HT_CAP((htc->cap & BIT(12)), "DSSS/CCK HT40");
|
||||
PRINT_HT_CAP(!(htc->cap & BIT(12)), "No DSSS/CCK HT40");
|
||||
|
||||
/* BIT(13) is reserved */
|
||||
|
||||
PRINT_HT_CAP((htc->cap & BIT(14)), "40 MHz Intolerant");
|
||||
|
||||
PRINT_HT_CAP((htc->cap & BIT(15)), "L-SIG TXOP protection");
|
||||
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n",
|
||||
htc->ampdu_factor, htc->ampdu_density);
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:");
|
||||
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, " %.2x",
|
||||
htc->mcs.rx_mask[i]);
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n",
|
||||
le16_to_cpu(htc->mcs.rx_highest));
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "\n");
|
||||
|
||||
/* If not set this is meaningless */
|
||||
if (le16_to_cpu(htc->mcs.rx_highest)) {
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
"MCS rx highest: %d Mbps\n",
|
||||
le16_to_cpu(htc->mcs.rx_highest));
|
||||
}
|
||||
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n",
|
||||
htc->mcs.tx_params);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ static inline int drv_add_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_if_init_conf *conf)
|
||||
{
|
||||
int ret = local->ops->add_interface(&local->hw, conf);
|
||||
trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret);
|
||||
trace_drv_add_interface(local, vif_to_sdata(conf->vif), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ static inline void drv_remove_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_if_init_conf *conf)
|
||||
{
|
||||
local->ops->remove_interface(&local->hw, conf);
|
||||
trace_drv_remove_interface(local, conf->mac_addr, conf->vif);
|
||||
trace_drv_remove_interface(local, vif_to_sdata(conf->vif));
|
||||
}
|
||||
|
||||
static inline int drv_config(struct ieee80211_local *local, u32 changed)
|
||||
@ -58,13 +58,13 @@ static inline int drv_config(struct ieee80211_local *local, u32 changed)
|
||||
}
|
||||
|
||||
static inline void drv_bss_info_changed(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_bss_conf *info,
|
||||
u32 changed)
|
||||
{
|
||||
if (local->ops->bss_info_changed)
|
||||
local->ops->bss_info_changed(&local->hw, vif, info, changed);
|
||||
trace_drv_bss_info_changed(local, vif, info, changed);
|
||||
local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
|
||||
trace_drv_bss_info_changed(local, sdata, info, changed);
|
||||
}
|
||||
|
||||
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
|
||||
@ -106,12 +106,13 @@ static inline int drv_set_tim(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
static inline int drv_set_key(struct ieee80211_local *local,
|
||||
enum set_key_cmd cmd, struct ieee80211_vif *vif,
|
||||
enum set_key_cmd cmd,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key);
|
||||
trace_drv_set_key(local, cmd, vif, sta, key, ret);
|
||||
int ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
|
||||
trace_drv_set_key(local, cmd, sdata, sta, key, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -179,13 +180,13 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
static inline void drv_sta_notify(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum sta_notify_cmd cmd,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
if (local->ops->sta_notify)
|
||||
local->ops->sta_notify(&local->hw, vif, cmd, sta);
|
||||
trace_drv_sta_notify(local, vif, cmd, sta);
|
||||
local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
|
||||
trace_drv_sta_notify(local, sdata, cmd, sta);
|
||||
}
|
||||
|
||||
static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
|
||||
@ -239,16 +240,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
|
||||
}
|
||||
|
||||
static inline int drv_ampdu_action(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(&local->hw, vif, action,
|
||||
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
|
||||
sta, tid, ssn);
|
||||
trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret);
|
||||
trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,12 @@ static inline void trace_ ## name(proto) {}
|
||||
#define STA_PR_FMT " sta:%pM"
|
||||
#define STA_PR_ARG __entry->sta_addr
|
||||
|
||||
#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, vif)
|
||||
#define VIF_ASSIGN __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif
|
||||
#define VIF_PR_FMT " vif:%p(%d)"
|
||||
#define VIF_PR_ARG __entry->vif, __entry->vif_type
|
||||
#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
|
||||
__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
|
||||
#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
|
||||
__assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
|
||||
#define VIF_PR_FMT " vif:%s(%d)"
|
||||
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type
|
||||
|
||||
TRACE_EVENT(drv_start,
|
||||
TP_PROTO(struct ieee80211_local *local, int ret),
|
||||
@ -70,11 +72,10 @@ TRACE_EVENT(drv_stop,
|
||||
|
||||
TRACE_EVENT(drv_add_interface,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
const u8 *addr,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
int ret),
|
||||
|
||||
TP_ARGS(local, addr, vif, ret),
|
||||
TP_ARGS(local, sdata, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
@ -86,7 +87,7 @@ TRACE_EVENT(drv_add_interface,
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
memcpy(__entry->addr, addr, 6);
|
||||
memcpy(__entry->addr, sdata->vif.addr, 6);
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
@ -97,10 +98,9 @@ TRACE_EVENT(drv_add_interface,
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_remove_interface,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
const u8 *addr, struct ieee80211_vif *vif),
|
||||
TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
|
||||
|
||||
TP_ARGS(local, addr, vif),
|
||||
TP_ARGS(local, sdata),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
@ -111,7 +111,7 @@ TRACE_EVENT(drv_remove_interface,
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
memcpy(__entry->addr, addr, 6);
|
||||
memcpy(__entry->addr, sdata->vif.addr, 6);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
@ -140,6 +140,7 @@ TRACE_EVENT(drv_config,
|
||||
__field(u8, short_frame_max_tx_count)
|
||||
__field(int, center_freq)
|
||||
__field(int, channel_type)
|
||||
__field(int, smps)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
@ -155,6 +156,7 @@ TRACE_EVENT(drv_config,
|
||||
__entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
|
||||
__entry->center_freq = local->hw.conf.channel->center_freq;
|
||||
__entry->channel_type = local->hw.conf.channel_type;
|
||||
__entry->smps = local->hw.conf.smps_mode;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
@ -165,11 +167,11 @@ TRACE_EVENT(drv_config,
|
||||
|
||||
TRACE_EVENT(drv_bss_info_changed,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_bss_conf *info,
|
||||
u32 changed),
|
||||
|
||||
TP_ARGS(local, vif, info, changed),
|
||||
TP_ARGS(local, sdata, info, changed),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
@ -293,11 +295,11 @@ TRACE_EVENT(drv_set_tim,
|
||||
|
||||
TRACE_EVENT(drv_set_key,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
enum set_key_cmd cmd, struct ieee80211_vif *vif,
|
||||
enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key, int ret),
|
||||
|
||||
TP_ARGS(local, cmd, vif, sta, key, ret),
|
||||
TP_ARGS(local, cmd, sdata, sta, key, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
@ -491,11 +493,11 @@ TRACE_EVENT(drv_set_rts_threshold,
|
||||
|
||||
TRACE_EVENT(drv_sta_notify,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum sta_notify_cmd cmd,
|
||||
struct ieee80211_sta *sta),
|
||||
|
||||
TP_ARGS(local, vif, cmd, sta),
|
||||
TP_ARGS(local, sdata, cmd, sta),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
@ -656,12 +658,12 @@ TRACE_EVENT(drv_tx_last_beacon,
|
||||
|
||||
TRACE_EVENT(drv_ampdu_action,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, int ret),
|
||||
|
||||
TP_ARGS(local, vif, action, sta, tid, ssn, ret),
|
||||
TP_ARGS(local, sdata, action, sta, tid, ssn, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
|
@ -125,7 +125,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer "
|
||||
"for delba frame\n", sdata->dev->name);
|
||||
"for delba frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -133,10 +133,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
|
||||
@ -185,3 +185,50 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||
spin_unlock_bh(&sta->lock);
|
||||
}
|
||||
}
|
||||
|
||||
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps, const u8 *da,
|
||||
const u8 *bssid)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *action_frame;
|
||||
|
||||
/* 27 = header + category + action + smps mode */
|
||||
skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
action_frame = (void *)skb_put(skb, 27);
|
||||
memcpy(action_frame->da, da, ETH_ALEN);
|
||||
memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(action_frame->bssid, bssid, ETH_ALEN);
|
||||
action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
action_frame->u.action.category = WLAN_CATEGORY_HT;
|
||||
action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
|
||||
switch (smps) {
|
||||
case IEEE80211_SMPS_AUTOMATIC:
|
||||
case IEEE80211_SMPS_NUM_MODES:
|
||||
WARN_ON(1);
|
||||
case IEEE80211_SMPS_OFF:
|
||||
action_frame->u.action.u.ht_smps.smps_control =
|
||||
WLAN_HT_SMPS_CONTROL_DISABLED;
|
||||
break;
|
||||
case IEEE80211_SMPS_STATIC:
|
||||
action_frame->u.action.u.ht_smps.smps_control =
|
||||
WLAN_HT_SMPS_CONTROL_STATIC;
|
||||
break;
|
||||
case IEEE80211_SMPS_DYNAMIC:
|
||||
action_frame->u.action.u.ht_smps.smps_control =
|
||||
WLAN_HT_SMPS_CONTROL_DYNAMIC;
|
||||
break;
|
||||
}
|
||||
|
||||
/* we'll do more on status of this frame */
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
memset(mgmt->da, 0xff, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
|
||||
mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int);
|
||||
mgmt->u.beacon.timestamp = cpu_to_le64(tsf);
|
||||
@ -252,7 +252,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, mgmt->sa);
|
||||
sta = sta_info_get(sdata, mgmt->sa);
|
||||
if (sta) {
|
||||
u32 prev_rates;
|
||||
|
||||
@ -266,7 +266,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
printk(KERN_DEBUG "%s: updated supp_rates set "
|
||||
"for %pM based on beacon info (0x%llx | "
|
||||
"0x%llx -> 0x%llx)\n",
|
||||
sdata->dev->name,
|
||||
sdata->name,
|
||||
sta->sta.addr,
|
||||
(unsigned long long) prev_rates,
|
||||
(unsigned long long) supp_rates,
|
||||
@ -364,7 +364,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: beacon TSF higher than "
|
||||
"local TSF - IBSS merge with BSSID %pM\n",
|
||||
sdata->dev->name, mgmt->bssid);
|
||||
sdata->name, mgmt->bssid);
|
||||
#endif
|
||||
ieee80211_sta_join_ibss(sdata, bss);
|
||||
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
|
||||
@ -393,7 +393,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
||||
if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n",
|
||||
sdata->dev->name, addr);
|
||||
sdata->name, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -402,7 +402,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
|
||||
wiphy_name(local->hw.wiphy), addr, sdata->dev->name);
|
||||
wiphy_name(local->hw.wiphy), addr, sdata->name);
|
||||
#endif
|
||||
|
||||
sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
|
||||
@ -466,7 +466,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
return;
|
||||
|
||||
printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
|
||||
"IBSS networks with same SSID (merge)\n", sdata->dev->name);
|
||||
"IBSS networks with same SSID (merge)\n", sdata->name);
|
||||
|
||||
ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len);
|
||||
}
|
||||
@ -488,13 +488,13 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
* random number generator get different BSSID. */
|
||||
get_random_bytes(bssid, ETH_ALEN);
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
bssid[i] ^= sdata->dev->dev_addr[i];
|
||||
bssid[i] ^= sdata->vif.addr[i];
|
||||
bssid[0] &= ~0x01;
|
||||
bssid[0] |= 0x02;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
|
||||
sdata->dev->name, bssid);
|
||||
sdata->name, bssid);
|
||||
|
||||
sband = local->hw.wiphy->bands[ifibss->channel->band];
|
||||
|
||||
@ -523,7 +523,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
active_ibss = ieee80211_sta_active_ibss(sdata);
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
|
||||
sdata->dev->name, active_ibss);
|
||||
sdata->name, active_ibss);
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
|
||||
if (active_ibss)
|
||||
@ -552,7 +552,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
|
||||
" based on configured SSID\n",
|
||||
sdata->dev->name, bss->cbss.bssid);
|
||||
sdata->name, bss->cbss.bssid);
|
||||
|
||||
ieee80211_sta_join_ibss(sdata, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
@ -571,7 +571,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
} else if (time_after(jiffies, ifibss->last_scan_completed +
|
||||
IEEE80211_SCAN_INTERVAL)) {
|
||||
printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
|
||||
"join\n", sdata->dev->name);
|
||||
"join\n", sdata->name);
|
||||
|
||||
ieee80211_request_internal_scan(sdata, ifibss->ssid,
|
||||
ifibss->ssid_len);
|
||||
@ -585,7 +585,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
return;
|
||||
}
|
||||
printk(KERN_DEBUG "%s: IBSS not allowed on"
|
||||
" %d MHz\n", sdata->dev->name,
|
||||
" %d MHz\n", sdata->name,
|
||||
local->hw.conf.channel->center_freq);
|
||||
|
||||
/* No IBSS found - decrease scan interval and continue
|
||||
@ -619,7 +619,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
|
||||
" (tx_last_beacon=%d)\n",
|
||||
sdata->dev->name, mgmt->sa, mgmt->da,
|
||||
sdata->name, mgmt->sa, mgmt->da,
|
||||
mgmt->bssid, tx_last_beacon);
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
|
||||
@ -637,7 +637,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
|
||||
"from %pM\n",
|
||||
sdata->dev->name, mgmt->sa);
|
||||
sdata->name, mgmt->sa);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -657,7 +657,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
memcpy(resp->da, mgmt->sa, ETH_ALEN);
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
|
||||
sdata->dev->name, resp->da);
|
||||
sdata->name, resp->da);
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
@ -671,7 +671,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||
size_t baselen;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
|
||||
if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
|
||||
return; /* ignore ProbeResp to foreign address */
|
||||
|
||||
baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
|
||||
|
@ -140,7 +140,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result;
|
||||
|
||||
struct ieee80211_tx_data {
|
||||
struct sk_buff *skb;
|
||||
struct net_device *dev;
|
||||
struct ieee80211_local *local;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
@ -298,6 +297,8 @@ struct ieee80211_if_managed {
|
||||
|
||||
unsigned long timers_running; /* used for quiesce/restart */
|
||||
bool powersave; /* powersave requested for this iface */
|
||||
enum ieee80211_smps_mode req_smps, /* requested smps mode */
|
||||
ap_smps; /* smps mode AP thinks we're in */
|
||||
|
||||
unsigned long request;
|
||||
|
||||
@ -433,6 +434,8 @@ struct ieee80211_sub_if_data {
|
||||
|
||||
int drop_unencrypted;
|
||||
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
/*
|
||||
* keep track of whether the HT opmode (stored in
|
||||
* vif.bss_info.ht_operation_mode) is valid.
|
||||
@ -586,6 +589,9 @@ struct ieee80211_local {
|
||||
/* used for uploading changed mc list */
|
||||
struct work_struct reconfig_filter;
|
||||
|
||||
/* used to reconfigure hardware SM PS */
|
||||
struct work_struct recalc_smps;
|
||||
|
||||
/* aggregated multicast list */
|
||||
struct dev_addr_list *mc_list;
|
||||
int mc_count;
|
||||
@ -760,6 +766,8 @@ struct ieee80211_local {
|
||||
int user_power_level; /* in dBm */
|
||||
int power_constr_level; /* in dBm */
|
||||
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
|
||||
struct work_struct restart_work;
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
@ -874,6 +882,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
void ieee80211_configure_filter(struct ieee80211_local *local);
|
||||
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
extern bool ieee80211_disable_40mhz_24ghz;
|
||||
|
||||
/* STA code */
|
||||
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
||||
@ -938,6 +948,8 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss);
|
||||
|
||||
/* interface handling */
|
||||
int ieee80211_iface_init(void);
|
||||
void ieee80211_iface_exit(void);
|
||||
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
struct net_device **new_dev, enum nl80211_iftype type,
|
||||
struct vif_params *params);
|
||||
@ -976,6 +988,9 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
|
||||
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *da, u16 tid,
|
||||
u16 initiator, u16 reason_code);
|
||||
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps, const u8 *da,
|
||||
const u8 *bssid);
|
||||
|
||||
void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
|
||||
u16 tid, u16 initiator, u16 reason);
|
||||
@ -1086,6 +1101,10 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
|
||||
struct ieee802_11_elems *elems,
|
||||
enum ieee80211_band band);
|
||||
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode);
|
||||
void ieee80211_recalc_smps(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *forsdata);
|
||||
|
||||
#ifdef CONFIG_MAC80211_NOINLINE
|
||||
#define debug_noinline noinline
|
||||
|
@ -60,6 +60,22 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_change_mac(struct net_device *dev, void *addr)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
int ret;
|
||||
|
||||
if (netif_running(dev))
|
||||
return -EBUSY;
|
||||
|
||||
ret = eth_mac_addr(dev, addr);
|
||||
|
||||
if (ret == 0)
|
||||
memcpy(sdata->vif.addr, addr, ETH_ALEN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int identical_mac_addr_allowed(int type1, int type2)
|
||||
{
|
||||
return type1 == NL80211_IFTYPE_MONITOR ||
|
||||
@ -234,7 +250,7 @@ static int ieee80211_open(struct net_device *dev)
|
||||
default:
|
||||
conf.vif = &sdata->vif;
|
||||
conf.type = sdata->vif.type;
|
||||
conf.mac_addr = dev->dev_addr;
|
||||
conf.mac_addr = sdata->vif.addr;
|
||||
res = drv_add_interface(local, &conf);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
@ -514,7 +530,7 @@ static int ieee80211_stop(struct net_device *dev)
|
||||
|
||||
conf.vif = &sdata->vif;
|
||||
conf.type = sdata->vif.type;
|
||||
conf.mac_addr = dev->dev_addr;
|
||||
conf.mac_addr = sdata->vif.addr;
|
||||
/* disable all keys for as long as this netdev is down */
|
||||
ieee80211_disable_keys(sdata);
|
||||
drv_remove_interface(local, &conf);
|
||||
@ -651,7 +667,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
|
||||
.ndo_start_xmit = ieee80211_subif_start_xmit,
|
||||
.ndo_set_multicast_list = ieee80211_set_multicast_list,
|
||||
.ndo_change_mtu = ieee80211_change_mtu,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
.ndo_set_mac_address = ieee80211_change_mac,
|
||||
};
|
||||
|
||||
static const struct net_device_ops ieee80211_monitorif_ops = {
|
||||
@ -794,6 +810,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
|
||||
sdata = netdev_priv(ndev);
|
||||
ndev->ieee80211_ptr = &sdata->wdev;
|
||||
memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN);
|
||||
memcpy(sdata->name, ndev->name, IFNAMSIZ);
|
||||
|
||||
/* initialise type-independent data */
|
||||
sdata->wdev.wiphy = local->hw.wiphy;
|
||||
@ -945,3 +963,41 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
if (chg)
|
||||
ieee80211_hw_config(local, chg);
|
||||
}
|
||||
|
||||
static int netdev_notify(struct notifier_block *nb,
|
||||
unsigned long state,
|
||||
void *ndev)
|
||||
{
|
||||
struct net_device *dev = ndev;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (state != NETDEV_CHANGENAME)
|
||||
return 0;
|
||||
|
||||
if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
|
||||
return 0;
|
||||
|
||||
if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
|
||||
return 0;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
memcpy(sdata->name, sdata->name, IFNAMSIZ);
|
||||
|
||||
ieee80211_debugfs_rename_netdev(sdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block mac80211_netdev_notifier = {
|
||||
.notifier_call = netdev_notify,
|
||||
};
|
||||
|
||||
int ieee80211_iface_init(void)
|
||||
{
|
||||
return register_netdevice_notifier(&mac80211_netdev_notifier);
|
||||
}
|
||||
|
||||
void ieee80211_iface_exit(void)
|
||||
{
|
||||
unregister_netdevice_notifier(&mac80211_netdev_notifier);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
|
||||
ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
|
||||
|
||||
if (!ret) {
|
||||
spin_lock_bh(&todo_lock);
|
||||
@ -181,7 +181,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif,
|
||||
ret = drv_set_key(key->local, DISABLE_KEY, sdata,
|
||||
sta, &key->conf);
|
||||
|
||||
if (ret)
|
||||
@ -421,7 +421,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
|
||||
*/
|
||||
|
||||
/* same here, the AP could be using QoS */
|
||||
ap = sta_info_get(key->local, key->sdata->u.mgd.bssid);
|
||||
ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
|
||||
if (ap) {
|
||||
if (test_sta_flags(ap, WLAN_STA_WME))
|
||||
key->conf.flags |=
|
||||
|
@ -59,11 +59,17 @@ enum ieee80211_internal_key_flags {
|
||||
KEY_FLAG_TODO_DEFMGMTKEY = BIT(6),
|
||||
};
|
||||
|
||||
enum ieee80211_internal_tkip_state {
|
||||
TKIP_STATE_NOT_INIT,
|
||||
TKIP_STATE_PHASE1_DONE,
|
||||
TKIP_STATE_PHASE1_HW_UPLOADED,
|
||||
};
|
||||
|
||||
struct tkip_ctx {
|
||||
u32 iv32;
|
||||
u16 iv16;
|
||||
u16 p1k[5];
|
||||
int initialized;
|
||||
enum ieee80211_internal_tkip_state state;
|
||||
};
|
||||
|
||||
struct ieee80211_key {
|
||||
|
@ -32,7 +32,12 @@
|
||||
#include "led.h"
|
||||
#include "cfg.h"
|
||||
#include "debugfs.h"
|
||||
#include "debugfs_netdev.h"
|
||||
|
||||
|
||||
bool ieee80211_disable_40mhz_24ghz;
|
||||
module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
|
||||
MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
|
||||
"Disable 40MHz support in the 2.4GHz band");
|
||||
|
||||
void ieee80211_configure_filter(struct ieee80211_local *local)
|
||||
{
|
||||
@ -114,6 +119,18 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
||||
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
|
||||
}
|
||||
|
||||
if (!conf_is_ht(&local->hw.conf)) {
|
||||
/*
|
||||
* mac80211.h documents that this is only valid
|
||||
* when the channel is set to an HT type, and
|
||||
* that otherwise STATIC is used.
|
||||
*/
|
||||
local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC;
|
||||
} else if (local->hw.conf.smps_mode != local->smps_mode) {
|
||||
local->hw.conf.smps_mode = local->smps_mode;
|
||||
changed |= IEEE80211_CONF_CHANGE_SMPS;
|
||||
}
|
||||
|
||||
if (scan_chan)
|
||||
power = chan->max_power;
|
||||
else
|
||||
@ -173,7 +190,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
sdata->vif.bss_conf.bssid = sdata->dev->dev_addr;
|
||||
sdata->vif.bss_conf.bssid = sdata->vif.addr;
|
||||
else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
sdata->vif.bss_conf.bssid = zero;
|
||||
} else {
|
||||
@ -223,8 +240,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
drv_bss_info_changed(local, &sdata->vif,
|
||||
&sdata->vif.bss_conf, changed);
|
||||
drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed);
|
||||
}
|
||||
|
||||
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
|
||||
@ -299,6 +315,16 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_restart_hw);
|
||||
|
||||
static void ieee80211_recalc_smps_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, recalc_smps);
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_smps(local, NULL);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
const struct ieee80211_ops *ops)
|
||||
{
|
||||
@ -372,6 +398,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
INIT_WORK(&local->restart_work, ieee80211_restart_work);
|
||||
|
||||
INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
|
||||
INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work);
|
||||
local->smps_mode = IEEE80211_SMPS_OFF;
|
||||
|
||||
INIT_WORK(&local->dynamic_ps_enable_work,
|
||||
ieee80211_dynamic_ps_enable_work);
|
||||
@ -674,11 +702,19 @@ static int __init ieee80211_init(void)
|
||||
|
||||
ret = rc80211_pid_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_pid;
|
||||
|
||||
ieee80211_debugfs_netdev_init();
|
||||
ret = ieee80211_iface_init();
|
||||
if (ret)
|
||||
goto err_netdev;
|
||||
|
||||
return 0;
|
||||
err_netdev:
|
||||
rc80211_pid_exit();
|
||||
err_pid:
|
||||
rc80211_minstrel_exit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ieee80211_exit(void)
|
||||
@ -695,7 +731,7 @@ static void __exit ieee80211_exit(void)
|
||||
if (mesh_allocated)
|
||||
ieee80211s_stop();
|
||||
|
||||
ieee80211_debugfs_netdev_exit();
|
||||
ieee80211_iface_exit();
|
||||
}
|
||||
|
||||
|
||||
|
@ -457,7 +457,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: running mesh housekeeping\n",
|
||||
sdata->dev->name);
|
||||
sdata->name);
|
||||
#endif
|
||||
|
||||
ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
|
||||
@ -565,7 +565,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
/* ignore ProbeResp to foreign address */
|
||||
if (stype == IEEE80211_STYPE_PROBE_RESP &&
|
||||
compare_ether_addr(mgmt->da, sdata->dev->dev_addr))
|
||||
compare_ether_addr(mgmt->da, sdata->vif.addr))
|
||||
return;
|
||||
|
||||
baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
|
||||
|
@ -128,9 +128,9 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
/* BSSID == SA */
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||
mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
|
||||
mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
|
||||
|
||||
@ -222,7 +222,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
||||
memcpy(mgmt->da, ra, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
/* BSSID is left zeroed, wildcard value */
|
||||
mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
|
||||
mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
|
||||
@ -335,7 +335,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
bool process = true;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, mgmt->sa);
|
||||
sta = sta_info_get(sdata, mgmt->sa);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
@ -374,7 +374,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
new_metric = MAX_METRIC;
|
||||
exp_time = TU_TO_EXP_TIME(orig_lifetime);
|
||||
|
||||
if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
|
||||
if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) {
|
||||
/* This MP is the originator, we are not interested in this
|
||||
* frame, except for updating transmitter's path info.
|
||||
*/
|
||||
@ -486,7 +486,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
mhwmp_dbg("received PREQ from %pM\n", orig_addr);
|
||||
|
||||
if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
|
||||
if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
|
||||
mhwmp_dbg("PREQ is for us\n");
|
||||
forward = false;
|
||||
reply = true;
|
||||
@ -579,7 +579,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
* replies
|
||||
*/
|
||||
target_addr = PREP_IE_TARGET_ADDR(prep_elem);
|
||||
if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0)
|
||||
if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0)
|
||||
/* destination, no forwarding required */
|
||||
return;
|
||||
|
||||
@ -890,7 +890,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
|
||||
target_flags = MP_F_RF;
|
||||
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
|
||||
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
|
||||
cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
|
||||
cpu_to_le32(mpath->sn), broadcast_addr, 0,
|
||||
ttl, cpu_to_le32(lifetime), 0,
|
||||
@ -939,7 +939,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
|
||||
if (time_after(jiffies,
|
||||
mpath->exp_time -
|
||||
msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
|
||||
!memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) &&
|
||||
!memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
|
||||
!(mpath->flags & MESH_PATH_RESOLVING) &&
|
||||
!(mpath->flags & MESH_PATH_FIXED)) {
|
||||
mesh_queue_preq(mpath,
|
||||
@ -1010,7 +1010,7 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
|
||||
mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr,
|
||||
mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
|
||||
cpu_to_le32(++ifmsh->sn),
|
||||
0, NULL, 0, broadcast_addr,
|
||||
0, MESH_TTL, 0, 0, 0, sdata);
|
||||
|
@ -260,7 +260,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
|
||||
int err = 0;
|
||||
u32 hash_idx;
|
||||
|
||||
if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
|
||||
if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
|
||||
/* never add ourselves as neighbours */
|
||||
return -ENOTSUPP;
|
||||
|
||||
@ -377,7 +377,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
|
||||
int err = 0;
|
||||
u32 hash_idx;
|
||||
|
||||
if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
|
||||
if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
|
||||
/* never add ourselves as neighbours */
|
||||
return -ENOTSUPP;
|
||||
|
||||
@ -605,7 +605,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
|
||||
struct mesh_path *mpath;
|
||||
u32 sn = 0;
|
||||
|
||||
if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) {
|
||||
if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
|
||||
u8 *ra, *da;
|
||||
|
||||
da = hdr->addr3;
|
||||
|
@ -169,7 +169,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
/* BSSID is left zeroed, wildcard value */
|
||||
mgmt->u.action.category = MESH_PLINK_CATEGORY;
|
||||
mgmt->u.action.u.plink_action.action_code = action;
|
||||
@ -234,7 +234,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, hw_addr);
|
||||
sta = sta_info_get(sdata, hw_addr);
|
||||
if (!sta) {
|
||||
sta = mesh_plink_alloc(sdata, hw_addr, rates);
|
||||
if (!sta) {
|
||||
@ -455,7 +455,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, mgmt->sa);
|
||||
sta = sta_info_get(sdata, mgmt->sa);
|
||||
if (!sta && ftype != PLINK_OPEN) {
|
||||
mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
|
||||
rcu_read_unlock();
|
||||
|
@ -75,6 +75,9 @@ enum rx_mgmt_action {
|
||||
/* caller must call cfg80211_send_disassoc() */
|
||||
RX_MGMT_CFG80211_DISASSOC,
|
||||
|
||||
/* caller must tell cfg80211 about internal error */
|
||||
RX_MGMT_CFG80211_ASSOC_ERROR,
|
||||
|
||||
/* caller must call cfg80211_auth_timeout() & free work */
|
||||
RX_MGMT_CFG80211_AUTH_TO,
|
||||
|
||||
@ -202,7 +205,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_hw_config(local, 0);
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, bssid);
|
||||
sta = sta_info_get(sdata, bssid);
|
||||
if (sta)
|
||||
rate_control_rate_update(local, sband, sta,
|
||||
IEEE80211_RC_HT_CHANGED);
|
||||
@ -248,7 +251,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
wk->ssid_len);
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
|
||||
"frame\n", sdata->dev->name);
|
||||
"frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
@ -282,7 +285,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN);
|
||||
|
||||
if (!is_zero_ether_addr(wk->prev_bssid)) {
|
||||
@ -398,6 +401,14 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
__le16 tmp;
|
||||
u32 flags = local->hw.conf.channel->flags;
|
||||
|
||||
/* determine capability flags */
|
||||
|
||||
if (ieee80211_disable_40mhz_24ghz &&
|
||||
sband->band == IEEE80211_BAND_2GHZ) {
|
||||
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
cap &= ~IEEE80211_HT_CAP_SGI_40;
|
||||
}
|
||||
|
||||
switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
||||
if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
|
||||
@ -413,17 +424,64 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = cpu_to_le16(cap);
|
||||
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
|
||||
/* set SM PS mode properly */
|
||||
cap &= ~IEEE80211_HT_CAP_SM_PS;
|
||||
/* new association always uses requested smps mode */
|
||||
if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
|
||||
if (ifmgd->powersave)
|
||||
ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
|
||||
else
|
||||
ifmgd->ap_smps = IEEE80211_SMPS_OFF;
|
||||
} else
|
||||
ifmgd->ap_smps = ifmgd->req_smps;
|
||||
|
||||
switch (ifmgd->ap_smps) {
|
||||
case IEEE80211_SMPS_AUTOMATIC:
|
||||
case IEEE80211_SMPS_NUM_MODES:
|
||||
WARN_ON(1);
|
||||
case IEEE80211_SMPS_OFF:
|
||||
cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
|
||||
IEEE80211_HT_CAP_SM_PS_SHIFT;
|
||||
break;
|
||||
case IEEE80211_SMPS_STATIC:
|
||||
cap |= WLAN_HT_CAP_SM_PS_STATIC <<
|
||||
IEEE80211_HT_CAP_SM_PS_SHIFT;
|
||||
break;
|
||||
case IEEE80211_SMPS_DYNAMIC:
|
||||
cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
|
||||
IEEE80211_HT_CAP_SM_PS_SHIFT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* reserve and fill IE */
|
||||
|
||||
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
|
||||
*pos++ = WLAN_EID_HT_CAPABILITY;
|
||||
*pos++ = sizeof(struct ieee80211_ht_cap);
|
||||
memset(pos, 0, sizeof(struct ieee80211_ht_cap));
|
||||
|
||||
/* capability flags */
|
||||
tmp = cpu_to_le16(cap);
|
||||
memcpy(pos, &tmp, sizeof(u16));
|
||||
pos += sizeof(u16);
|
||||
/* TODO: needs a define here for << 2 */
|
||||
|
||||
/* AMPDU parameters */
|
||||
*pos++ = sband->ht_cap.ampdu_factor |
|
||||
(sband->ht_cap.ampdu_density << 2);
|
||||
(sband->ht_cap.ampdu_density <<
|
||||
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
|
||||
|
||||
/* MCS set */
|
||||
memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
|
||||
pos += sizeof(sband->ht_cap.mcs);
|
||||
|
||||
/* extended capabilities */
|
||||
pos += sizeof(__le16);
|
||||
|
||||
/* BF capabilities */
|
||||
pos += sizeof(__le32);
|
||||
|
||||
/* antenna selection */
|
||||
pos += sizeof(u8);
|
||||
}
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
@ -443,7 +501,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for "
|
||||
"deauth/disassoc frame\n", sdata->dev->name);
|
||||
"deauth/disassoc frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
@ -451,7 +509,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, bssid, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, bssid, ETH_ALEN);
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
|
||||
skb_put(skb, 2);
|
||||
@ -484,7 +542,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for "
|
||||
"pspoll frame\n", sdata->dev->name);
|
||||
"pspoll frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
@ -499,7 +557,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
|
||||
pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
|
||||
|
||||
memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
|
||||
memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(pspoll->ta, sdata->vif.addr, ETH_ALEN);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
@ -519,7 +577,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
|
||||
"frame\n", sdata->dev->name);
|
||||
"frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
@ -532,7 +590,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
nullfunc->frame_control = fc;
|
||||
memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
@ -940,6 +998,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_smps(local, sdata);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
netif_start_queue(sdata->dev);
|
||||
@ -956,7 +1015,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
|
||||
wk->tries++;
|
||||
if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
|
||||
printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
|
||||
sdata->dev->name, wk->bss->cbss.bssid);
|
||||
sdata->name, wk->bss->cbss.bssid);
|
||||
|
||||
/*
|
||||
* Most likely AP is not in the range so remove the
|
||||
@ -974,7 +1033,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n",
|
||||
sdata->dev->name, wk->bss->cbss.bssid,
|
||||
sdata->name, wk->bss->cbss.bssid,
|
||||
wk->tries);
|
||||
|
||||
/*
|
||||
@ -1001,7 +1060,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
|
||||
if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
|
||||
printk(KERN_DEBUG "%s: authentication with AP %pM"
|
||||
" timed out\n",
|
||||
sdata->dev->name, wk->bss->cbss.bssid);
|
||||
sdata->name, wk->bss->cbss.bssid);
|
||||
|
||||
/*
|
||||
* Most likely AP is not in the range so remove the
|
||||
@ -1019,7 +1078,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n",
|
||||
sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
|
||||
sdata->name, wk->bss->cbss.bssid, wk->tries);
|
||||
|
||||
ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
|
||||
wk->bss->cbss.bssid, NULL, 0, 0);
|
||||
@ -1078,7 +1137,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
netif_carrier_off(sdata->dev);
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, bssid);
|
||||
sta = sta_info_get(sdata, bssid);
|
||||
if (sta)
|
||||
ieee80211_sta_tear_down_BA_sessions(sta);
|
||||
rcu_read_unlock();
|
||||
@ -1115,7 +1174,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, bssid);
|
||||
sta = sta_info_get(sdata, bssid);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
@ -1139,7 +1198,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata,
|
||||
if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) {
|
||||
printk(KERN_DEBUG "%s: association with AP %pM"
|
||||
" timed out\n",
|
||||
sdata->dev->name, wk->bss->cbss.bssid);
|
||||
sdata->name, wk->bss->cbss.bssid);
|
||||
|
||||
/*
|
||||
* Most likely AP is not in the range so remove the
|
||||
@ -1157,7 +1216,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n",
|
||||
sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
|
||||
sdata->name, wk->bss->cbss.bssid, wk->tries);
|
||||
ieee80211_send_assoc(sdata, wk);
|
||||
|
||||
wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
|
||||
@ -1218,7 +1277,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
if (beacon && net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: detected beacon loss from AP "
|
||||
"- sending probe request\n", sdata->dev->name);
|
||||
"- sending probe request\n", sdata->name);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -1275,7 +1334,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgd_work *wk)
|
||||
{
|
||||
wk->state = IEEE80211_MGD_STATE_IDLE;
|
||||
printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
|
||||
printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
|
||||
}
|
||||
|
||||
|
||||
@ -1372,7 +1431,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
|
||||
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
|
||||
|
||||
printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
|
||||
sdata->dev->name, bssid, reason_code);
|
||||
sdata->name, bssid, reason_code);
|
||||
|
||||
if (!wk) {
|
||||
ieee80211_set_disassoc(sdata, true);
|
||||
@ -1407,7 +1466,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
|
||||
|
||||
printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
|
||||
sdata->dev->name, mgmt->sa, reason_code);
|
||||
sdata->name, mgmt->sa, reason_code);
|
||||
|
||||
ieee80211_set_disassoc(sdata, false);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
@ -1431,8 +1490,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
|
||||
u8 *pos;
|
||||
u32 changed = 0;
|
||||
int i, j;
|
||||
bool have_higher_than_11mbit = false, newsta = false;
|
||||
int i, j, err;
|
||||
bool have_higher_than_11mbit = false;
|
||||
u16 ap_ht_cap_flags;
|
||||
|
||||
/*
|
||||
@ -1452,7 +1511,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
|
||||
"status=%d aid=%d)\n",
|
||||
sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa,
|
||||
sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
|
||||
capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
|
||||
|
||||
pos = mgmt->u.assoc_resp.variable;
|
||||
@ -1466,7 +1525,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
ms = tu * 1024 / 1000;
|
||||
printk(KERN_DEBUG "%s: AP rejected association temporarily; "
|
||||
"comeback duration %u TU (%u ms)\n",
|
||||
sdata->dev->name, tu, ms);
|
||||
sdata->name, tu, ms);
|
||||
wk->timeout = jiffies + msecs_to_jiffies(ms);
|
||||
if (ms > IEEE80211_ASSOC_TIMEOUT)
|
||||
run_again(ifmgd, jiffies + msecs_to_jiffies(ms));
|
||||
@ -1475,49 +1534,37 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (status_code != WLAN_STATUS_SUCCESS) {
|
||||
printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
|
||||
sdata->dev->name, status_code);
|
||||
sdata->name, status_code);
|
||||
wk->state = IEEE80211_MGD_STATE_IDLE;
|
||||
return RX_MGMT_CFG80211_ASSOC;
|
||||
}
|
||||
|
||||
if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
|
||||
printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
|
||||
"set\n", sdata->dev->name, aid);
|
||||
"set\n", sdata->name, aid);
|
||||
aid &= ~(BIT(15) | BIT(14));
|
||||
|
||||
if (!elems.supp_rates) {
|
||||
printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
|
||||
sdata->dev->name);
|
||||
sdata->name);
|
||||
return RX_MGMT_NONE;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
|
||||
printk(KERN_DEBUG "%s: associated\n", sdata->name);
|
||||
ifmgd->aid = aid;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Add STA entry for the AP */
|
||||
sta = sta_info_get(local, wk->bss->cbss.bssid);
|
||||
sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
|
||||
if (!sta) {
|
||||
newsta = true;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
|
||||
if (!sta) {
|
||||
printk(KERN_DEBUG "%s: failed to alloc STA entry for"
|
||||
" the AP\n", sdata->dev->name);
|
||||
return RX_MGMT_NONE;
|
||||
}
|
||||
|
||||
set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
|
||||
WLAN_STA_ASSOC_AP);
|
||||
if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
|
||||
set_sta_flags(sta, WLAN_STA_AUTHORIZED);
|
||||
|
||||
rcu_read_lock();
|
||||
printk(KERN_DEBUG "%s: failed to alloc STA entry for"
|
||||
" the AP\n", sdata->name);
|
||||
return RX_MGMT_CFG80211_ASSOC_ERROR;
|
||||
}
|
||||
|
||||
set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
|
||||
WLAN_STA_ASSOC_AP);
|
||||
if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
|
||||
set_sta_flags(sta, WLAN_STA_AUTHORIZED);
|
||||
|
||||
rates = 0;
|
||||
basic_rates = 0;
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
@ -1580,18 +1627,14 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
if (elems.wmm_param)
|
||||
set_sta_flags(sta, WLAN_STA_WME);
|
||||
|
||||
if (newsta) {
|
||||
int err = sta_info_insert(sta);
|
||||
if (err) {
|
||||
printk(KERN_DEBUG "%s: failed to insert STA entry for"
|
||||
" the AP (error %d)\n", sdata->dev->name, err);
|
||||
rcu_read_unlock();
|
||||
return RX_MGMT_NONE;
|
||||
}
|
||||
err = sta_info_insert(sta);
|
||||
sta = NULL;
|
||||
if (err) {
|
||||
printk(KERN_DEBUG "%s: failed to insert STA entry for"
|
||||
" the AP (error %d)\n", sdata->name, err);
|
||||
return RX_MGMT_CFG80211_ASSOC_ERROR;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (elems.wmm_param)
|
||||
ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
|
||||
elems.wmm_param_len);
|
||||
@ -1679,7 +1722,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ASSERT_MGD_MTX(ifmgd);
|
||||
|
||||
if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
|
||||
if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
|
||||
return; /* ignore ProbeResp to foreign address */
|
||||
|
||||
baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
|
||||
@ -1694,7 +1737,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||
/* direct probe may be part of the association flow */
|
||||
if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) {
|
||||
printk(KERN_DEBUG "%s: direct probe responded\n",
|
||||
sdata->dev->name);
|
||||
sdata->name);
|
||||
wk->tries = 0;
|
||||
wk->state = IEEE80211_MGD_STATE_AUTH;
|
||||
WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE);
|
||||
@ -1787,7 +1830,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_DEBUG "%s: cancelling probereq poll due "
|
||||
"to a received beacon\n", sdata->dev->name);
|
||||
"to a received beacon\n", sdata->name);
|
||||
}
|
||||
#endif
|
||||
ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
|
||||
@ -1865,7 +1908,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, bssid);
|
||||
sta = sta_info_get(sdata, bssid);
|
||||
if (WARN_ON(!sta)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
@ -2036,6 +2079,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
case RX_MGMT_CFG80211_DEAUTH:
|
||||
cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
|
||||
break;
|
||||
case RX_MGMT_CFG80211_ASSOC_ERROR:
|
||||
/* an internal error -- pretend timeout for now */
|
||||
cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
|
||||
break;
|
||||
default:
|
||||
WARN(1, "unexpected: %d", rma);
|
||||
}
|
||||
@ -2336,6 +2383,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
|
||||
|
||||
mutex_init(&ifmgd->mtx);
|
||||
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
|
||||
ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC;
|
||||
else
|
||||
ifmgd->req_smps = IEEE80211_SMPS_OFF;
|
||||
}
|
||||
|
||||
/* scan finished notification */
|
||||
@ -2563,7 +2615,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
|
||||
sdata->dev->name, bssid, req->reason_code);
|
||||
sdata->name, bssid, req->reason_code);
|
||||
|
||||
ieee80211_send_deauth_disassoc(sdata, bssid,
|
||||
IEEE80211_STYPE_DEAUTH, req->reason_code,
|
||||
@ -2594,7 +2646,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
|
||||
sdata->dev->name, req->bss->bssid, req->reason_code);
|
||||
sdata->name, req->bss->bssid, req->reason_code);
|
||||
|
||||
ieee80211_set_disassoc(sdata, false);
|
||||
|
||||
|
@ -65,7 +65,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE,
|
||||
&sta->sta);
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
|
||||
conf.vif = &sdata->vif;
|
||||
conf.type = sdata->vif.type;
|
||||
conf.mac_addr = sdata->dev->dev_addr;
|
||||
conf.mac_addr = sdata->vif.addr;
|
||||
drv_remove_interface(local, &conf);
|
||||
}
|
||||
|
||||
|
@ -283,15 +283,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
||||
skb->protocol = htons(ETH_P_802_2);
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
continue;
|
||||
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
|
||||
continue;
|
||||
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
|
||||
if (prev_dev) {
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (skb2) {
|
||||
@ -361,7 +361,9 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
||||
* boundary. In the case of regular frames, this simply means aligning the
|
||||
* payload to a four-byte boundary (because either the IP header is directly
|
||||
* contained, or IV/RFC1042 headers that have a length divisible by four are
|
||||
* in front of it).
|
||||
* in front of it). If the payload data is not properly aligned and the
|
||||
* architecture doesn't support efficient unaligned operations, mac80211
|
||||
* will align the data.
|
||||
*
|
||||
* With A-MSDU frames, however, the payload data address must yield two modulo
|
||||
* four because there are 14-byte 802.3 headers within the A-MSDU frames that
|
||||
@ -375,25 +377,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
||||
*/
|
||||
static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
int hdrlen;
|
||||
|
||||
#ifndef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
|
||||
return;
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
WARN_ONCE((unsigned long)rx->skb->data & 1,
|
||||
"unaligned packet at 0x%p\n", rx->skb->data);
|
||||
#endif
|
||||
|
||||
if (WARN_ONCE((unsigned long)rx->skb->data & 1,
|
||||
"unaligned packet at 0x%p\n", rx->skb->data))
|
||||
return;
|
||||
|
||||
if (!ieee80211_is_data_present(hdr->frame_control))
|
||||
return;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (rx->flags & IEEE80211_RX_AMSDU)
|
||||
hdrlen += ETH_HLEN;
|
||||
WARN_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3,
|
||||
"unaligned IP payload at 0x%p\n", rx->skb->data + hdrlen);
|
||||
}
|
||||
|
||||
|
||||
@ -476,7 +463,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
char *dev_addr = rx->sdata->dev->dev_addr;
|
||||
char *dev_addr = rx->sdata->vif.addr;
|
||||
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
if (is_multicast_ether_addr(hdr->addr1)) {
|
||||
@ -1021,10 +1008,10 @@ static void ap_sta_ps_start(struct sta_info *sta)
|
||||
|
||||
atomic_inc(&sdata->bss->num_sta_ps);
|
||||
set_sta_flags(sta, WLAN_STA_PS_STA);
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
|
||||
sdata->dev->name, sta->sta.addr, sta->sta.aid);
|
||||
sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
}
|
||||
|
||||
@ -1038,13 +1025,13 @@ static void ap_sta_ps_end(struct sta_info *sta)
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
|
||||
sdata->dev->name, sta->sta.addr, sta->sta.aid);
|
||||
sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
|
||||
if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
|
||||
sdata->dev->name, sta->sta.addr, sta->sta.aid);
|
||||
sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
return;
|
||||
}
|
||||
@ -1156,7 +1143,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
|
||||
printk(KERN_DEBUG "%s: RX reassembly removed oldest "
|
||||
"fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
|
||||
"addr1=%pM addr2=%pM\n",
|
||||
sdata->dev->name, idx,
|
||||
sdata->name, idx,
|
||||
jiffies - entry->first_frag_time, entry->seq,
|
||||
entry->last_frag, hdr->addr1, hdr->addr2);
|
||||
#endif
|
||||
@ -1424,7 +1411,6 @@ static int
|
||||
__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct net_device *dev = sdata->dev;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
|
||||
if (ieee80211_has_a4(hdr->frame_control) &&
|
||||
@ -1436,7 +1422,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
|
||||
(sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr)))
|
||||
return -1;
|
||||
|
||||
return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
|
||||
return ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1453,7 +1439,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
|
||||
* of whether the frame was encrypted or not.
|
||||
*/
|
||||
if (ehdr->h_proto == htons(ETH_P_PAE) &&
|
||||
(compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 ||
|
||||
(compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
|
||||
compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
|
||||
return true;
|
||||
|
||||
@ -1472,7 +1458,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct net_device *dev = sdata->dev;
|
||||
struct ieee80211_local *local = rx->local;
|
||||
struct sk_buff *skb, *xmit_skb;
|
||||
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
|
||||
struct sta_info *dsta;
|
||||
@ -1495,8 +1480,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
||||
printk(KERN_DEBUG "%s: failed to clone "
|
||||
"multicast frame\n", dev->name);
|
||||
} else {
|
||||
dsta = sta_info_get(local, skb->data);
|
||||
if (dsta && dsta->sdata->dev == dev) {
|
||||
dsta = sta_info_get(sdata, skb->data);
|
||||
if (dsta) {
|
||||
/*
|
||||
* The destination station is associated to
|
||||
* this AP (in this VLAN), so send the frame
|
||||
@ -1512,7 +1497,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
||||
if (skb) {
|
||||
int align __maybe_unused;
|
||||
|
||||
#if defined(CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT) || !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
/*
|
||||
* 'align' will only take the values 0 or 2 here
|
||||
* since all frames are required to be aligned
|
||||
@ -1556,16 +1541,10 @@ static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct net_device *dev = rx->sdata->dev;
|
||||
struct ieee80211_local *local = rx->local;
|
||||
u16 ethertype;
|
||||
u8 *payload;
|
||||
struct sk_buff *skb = rx->skb, *frame = NULL;
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
__le16 fc = hdr->frame_control;
|
||||
const struct ethhdr *eth;
|
||||
int remaining, err;
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 src[ETH_ALEN];
|
||||
struct sk_buff_head frame_list;
|
||||
|
||||
if (unlikely(!ieee80211_is_data(fc)))
|
||||
return RX_CONTINUE;
|
||||
@ -1576,94 +1555,34 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
||||
if (!(rx->flags & IEEE80211_RX_AMSDU))
|
||||
return RX_CONTINUE;
|
||||
|
||||
err = __ieee80211_data_to_8023(rx);
|
||||
if (unlikely(err))
|
||||
if (ieee80211_has_a4(hdr->frame_control) &&
|
||||
rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
||||
!rx->sdata->u.vlan.sta)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
if (is_multicast_ether_addr(hdr->addr1) &&
|
||||
((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
||||
rx->sdata->u.vlan.sta) ||
|
||||
(rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
rx->sdata->u.mgd.use_4addr)))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
skb->dev = dev;
|
||||
__skb_queue_head_init(&frame_list);
|
||||
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += skb->len;
|
||||
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
|
||||
rx->sdata->vif.type,
|
||||
rx->local->hw.extra_tx_headroom);
|
||||
|
||||
/* skip the wrapping header */
|
||||
eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
|
||||
if (!eth)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
while (skb != frame) {
|
||||
u8 padding;
|
||||
__be16 len = eth->h_proto;
|
||||
unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
|
||||
|
||||
remaining = skb->len;
|
||||
memcpy(dst, eth->h_dest, ETH_ALEN);
|
||||
memcpy(src, eth->h_source, ETH_ALEN);
|
||||
|
||||
padding = ((4 - subframe_len) & 0x3);
|
||||
/* the last MSDU has no padding */
|
||||
if (subframe_len > remaining)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
skb_pull(skb, sizeof(struct ethhdr));
|
||||
/* if last subframe reuse skb */
|
||||
if (remaining <= subframe_len + padding)
|
||||
frame = skb;
|
||||
else {
|
||||
/*
|
||||
* Allocate and reserve two bytes more for payload
|
||||
* alignment since sizeof(struct ethhdr) is 14.
|
||||
*/
|
||||
frame = dev_alloc_skb(
|
||||
ALIGN(local->hw.extra_tx_headroom, 4) +
|
||||
subframe_len + 2);
|
||||
|
||||
if (frame == NULL)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
skb_reserve(frame,
|
||||
ALIGN(local->hw.extra_tx_headroom, 4) +
|
||||
sizeof(struct ethhdr) + 2);
|
||||
memcpy(skb_put(frame, ntohs(len)), skb->data,
|
||||
ntohs(len));
|
||||
|
||||
eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
|
||||
padding);
|
||||
if (!eth) {
|
||||
dev_kfree_skb(frame);
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
}
|
||||
|
||||
skb_reset_network_header(frame);
|
||||
frame->dev = dev;
|
||||
frame->priority = skb->priority;
|
||||
rx->skb = frame;
|
||||
|
||||
payload = frame->data;
|
||||
ethertype = (payload[6] << 8) | payload[7];
|
||||
|
||||
if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
|
||||
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
||||
compare_ether_addr(payload,
|
||||
bridge_tunnel_header) == 0)) {
|
||||
/* remove RFC1042 or Bridge-Tunnel
|
||||
* encapsulation and replace EtherType */
|
||||
skb_pull(frame, 6);
|
||||
memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
|
||||
memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
|
||||
} else {
|
||||
memcpy(skb_push(frame, sizeof(__be16)),
|
||||
&len, sizeof(__be16));
|
||||
memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
|
||||
memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
|
||||
}
|
||||
while (!skb_queue_empty(&frame_list)) {
|
||||
rx->skb = __skb_dequeue(&frame_list);
|
||||
|
||||
if (!ieee80211_frame_allowed(rx, fc)) {
|
||||
if (skb == frame) /* last frame */
|
||||
return RX_DROP_UNUSABLE;
|
||||
dev_kfree_skb(frame);
|
||||
dev_kfree_skb(rx->skb);
|
||||
continue;
|
||||
}
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += rx->skb->len;
|
||||
|
||||
ieee80211_deliver_skb(rx);
|
||||
}
|
||||
@ -1721,7 +1640,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
|
||||
/* Frame has reached destination. Don't forward */
|
||||
if (!is_multicast_ether_addr(hdr->addr1) &&
|
||||
compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0)
|
||||
compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
|
||||
return RX_CONTINUE;
|
||||
|
||||
mesh_hdr->ttl--;
|
||||
@ -1738,10 +1657,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
|
||||
if (!fwd_skb && net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
|
||||
sdata->dev->name);
|
||||
sdata->name);
|
||||
|
||||
fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
|
||||
memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
info = IEEE80211_SKB_CB(fwd_skb);
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||
@ -1870,7 +1789,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *resp;
|
||||
|
||||
if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) {
|
||||
if (compare_ether_addr(mgmt->da, sdata->vif.addr) != 0) {
|
||||
/* Not to own unicast address */
|
||||
return;
|
||||
}
|
||||
@ -1894,7 +1813,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
|
||||
resp = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(resp, 0, 24);
|
||||
memcpy(resp->da, mgmt->sa, ETH_ALEN);
|
||||
memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(resp->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
@ -2274,7 +2193,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
||||
if (!bssid && !sdata->u.mgd.use_4addr)
|
||||
return 0;
|
||||
if (!multicast &&
|
||||
compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
|
||||
compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
|
||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||
return 0;
|
||||
rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
@ -2291,7 +2210,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
||||
return 0;
|
||||
rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
} else if (!multicast &&
|
||||
compare_ether_addr(sdata->dev->dev_addr,
|
||||
compare_ether_addr(sdata->vif.addr,
|
||||
hdr->addr1) != 0) {
|
||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||
return 0;
|
||||
@ -2308,7 +2227,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (!multicast &&
|
||||
compare_ether_addr(sdata->dev->dev_addr,
|
||||
compare_ether_addr(sdata->vif.addr,
|
||||
hdr->addr1) != 0) {
|
||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||
return 0;
|
||||
@ -2319,11 +2238,11 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_AP:
|
||||
if (!bssid) {
|
||||
if (compare_ether_addr(sdata->dev->dev_addr,
|
||||
if (compare_ether_addr(sdata->vif.addr,
|
||||
hdr->addr1))
|
||||
return 0;
|
||||
} else if (!ieee80211_bssid_match(bssid,
|
||||
sdata->dev->dev_addr)) {
|
||||
sdata->vif.addr)) {
|
||||
if (!(rx->flags & IEEE80211_RX_IN_SCAN))
|
||||
return 0;
|
||||
rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
@ -2362,6 +2281,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
||||
int prepares;
|
||||
struct ieee80211_sub_if_data *prev = NULL;
|
||||
struct sk_buff *skb_new;
|
||||
struct sta_info *sta, *tmp;
|
||||
bool found_sta = false;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
memset(&rx, 0, sizeof(rx));
|
||||
@ -2378,68 +2299,76 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
||||
ieee80211_parse_qos(&rx);
|
||||
ieee80211_verify_alignment(&rx);
|
||||
|
||||
rx.sta = sta_info_get(local, hdr->addr2);
|
||||
if (rx.sta)
|
||||
rx.sdata = rx.sta->sdata;
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
for_each_sta_info(local, hdr->addr2, sta, tmp) {
|
||||
rx.sta = sta;
|
||||
found_sta = true;
|
||||
rx.sdata = sta->sdata;
|
||||
|
||||
rx.flags |= IEEE80211_RX_RA_MATCH;
|
||||
prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
|
||||
if (prepares) {
|
||||
if (status->flag & RX_FLAG_MMIC_ERROR) {
|
||||
if (rx.flags & IEEE80211_RX_RA_MATCH)
|
||||
ieee80211_rx_michael_mic_report(hdr, &rx);
|
||||
} else
|
||||
prev = rx.sdata;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found_sta) {
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
continue;
|
||||
|
||||
rx.sta = sta_info_get(sdata, hdr->addr2);
|
||||
|
||||
rx.flags |= IEEE80211_RX_RA_MATCH;
|
||||
prepares = prepare_for_handlers(sdata, &rx, hdr);
|
||||
|
||||
if (!prepares)
|
||||
continue;
|
||||
|
||||
if (rx.sdata && ieee80211_is_data(hdr->frame_control)) {
|
||||
rx.flags |= IEEE80211_RX_RA_MATCH;
|
||||
prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
|
||||
if (prepares) {
|
||||
if (status->flag & RX_FLAG_MMIC_ERROR) {
|
||||
rx.sdata = sdata;
|
||||
if (rx.flags & IEEE80211_RX_RA_MATCH)
|
||||
ieee80211_rx_michael_mic_report(hdr, &rx);
|
||||
} else
|
||||
prev = rx.sdata;
|
||||
}
|
||||
} else list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
ieee80211_rx_michael_mic_report(hdr,
|
||||
&rx);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
continue;
|
||||
/*
|
||||
* frame is destined for this interface, but if it's
|
||||
* not also for the previous one we handle that after
|
||||
* the loop to avoid copying the SKB once too much
|
||||
*/
|
||||
|
||||
rx.flags |= IEEE80211_RX_RA_MATCH;
|
||||
prepares = prepare_for_handlers(sdata, &rx, hdr);
|
||||
if (!prev) {
|
||||
prev = sdata;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prepares)
|
||||
continue;
|
||||
/*
|
||||
* frame was destined for the previous interface
|
||||
* so invoke RX handlers for it
|
||||
*/
|
||||
|
||||
if (status->flag & RX_FLAG_MMIC_ERROR) {
|
||||
rx.sdata = sdata;
|
||||
if (rx.flags & IEEE80211_RX_RA_MATCH)
|
||||
ieee80211_rx_michael_mic_report(hdr, &rx);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* frame is destined for this interface, but if it's not
|
||||
* also for the previous one we handle that after the
|
||||
* loop to avoid copying the SKB once too much
|
||||
*/
|
||||
|
||||
if (!prev) {
|
||||
skb_new = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!skb_new) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: failed to copy "
|
||||
"multicast frame for %s\n",
|
||||
wiphy_name(local->hw.wiphy),
|
||||
prev->name);
|
||||
continue;
|
||||
}
|
||||
ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
|
||||
prev = sdata;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* frame was destined for the previous interface
|
||||
* so invoke RX handlers for it
|
||||
*/
|
||||
|
||||
skb_new = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!skb_new) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: failed to copy "
|
||||
"multicast frame for %s\n",
|
||||
wiphy_name(local->hw.wiphy),
|
||||
prev->dev->name);
|
||||
continue;
|
||||
}
|
||||
ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
|
||||
prev = sdata;
|
||||
}
|
||||
if (prev)
|
||||
ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
|
||||
|
@ -147,7 +147,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||
presp = ieee80211_is_probe_resp(fc);
|
||||
if (presp) {
|
||||
/* ignore ProbeResp to foreign address */
|
||||
if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
|
||||
if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
presp = true;
|
||||
|
@ -35,7 +35,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer for "
|
||||
"measurement report frame\n", sdata->dev->name);
|
||||
"measurement report frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
|
||||
msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
|
||||
memset(msr_report, 0, 24);
|
||||
memcpy(msr_report->da, da, ETH_ALEN);
|
||||
memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(msr_report->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(msr_report->bssid, bssid, ETH_ALEN);
|
||||
msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
@ -103,13 +103,16 @@ static int sta_info_hash_del(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
/* protected by RCU */
|
||||
struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr)
|
||||
struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
|
||||
while (sta) {
|
||||
if (memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
|
||||
if (sta->sdata == sdata &&
|
||||
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
|
||||
break;
|
||||
sta = rcu_dereference(sta->hnext);
|
||||
}
|
||||
@ -369,7 +372,7 @@ int sta_info_insert(struct sta_info *sta)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 ||
|
||||
if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 ||
|
||||
is_multicast_ether_addr(sta->sta.addr))) {
|
||||
err = -EINVAL;
|
||||
goto out_free;
|
||||
@ -377,7 +380,7 @@ int sta_info_insert(struct sta_info *sta)
|
||||
|
||||
spin_lock_irqsave(&local->sta_lock, flags);
|
||||
/* check if STA exists already */
|
||||
if (sta_info_get(local, sta->sta.addr)) {
|
||||
if (sta_info_get(sdata, sta->sta.addr)) {
|
||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
err = -EEXIST;
|
||||
goto out_free;
|
||||
@ -394,7 +397,7 @@ int sta_info_insert(struct sta_info *sta)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta);
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_ADD, &sta->sta);
|
||||
sdata = sta->sdata;
|
||||
}
|
||||
|
||||
@ -534,7 +537,7 @@ static void __sta_info_unlink(struct sta_info **sta)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE,
|
||||
&(*sta)->sta);
|
||||
sdata = (*sta)->sdata;
|
||||
}
|
||||
@ -828,7 +831,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
|
||||
if (time_after(jiffies, sta->last_rx + exp_time)) {
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: expiring inactive STA %pM\n",
|
||||
sdata->dev->name, sta->sta.addr);
|
||||
sdata->name, sta->sta.addr);
|
||||
#endif
|
||||
__sta_info_unlink(&sta);
|
||||
if (sta)
|
||||
@ -843,11 +846,12 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = sta_info_get(hw_to_local(hw), addr);
|
||||
struct sta_info *sta, *nxt;
|
||||
|
||||
if (!sta)
|
||||
return NULL;
|
||||
return &sta->sta;
|
||||
/* Just return a random station ... first in list ... */
|
||||
for_each_sta_info(hw_to_local(hw), addr, sta, nxt)
|
||||
return &sta->sta;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
|
||||
|
||||
@ -872,7 +876,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int sent, buffered;
|
||||
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
|
||||
|
||||
if (!skb_queue_empty(&sta->ps_tx_buf))
|
||||
sta_info_clear_tim_bit(sta);
|
||||
@ -885,7 +889,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
|
||||
"since STA not sleeping anymore\n", sdata->dev->name,
|
||||
"since STA not sleeping anymore\n", sdata->name,
|
||||
sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
}
|
||||
@ -944,7 +948,7 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
|
||||
*/
|
||||
printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
|
||||
"though there are no buffered frames for it\n",
|
||||
sdata->dev->name, sta->sta.addr);
|
||||
sdata->name, sta->sta.addr);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user