Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
54dceb008f
|
@ -611,14 +611,20 @@ config RTL8180
|
|||
Thanks to Realtek for their support!
|
||||
|
||||
config RTL8187
|
||||
tristate "Realtek 8187 USB support"
|
||||
tristate "Realtek 8187 and 8187B USB support"
|
||||
depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
|
||||
select EEPROM_93CX6
|
||||
---help---
|
||||
This is a driver for RTL8187 based cards.
|
||||
These are USB based chips found in cards such as:
|
||||
This is a driver for RTL8187 and RTL8187B based cards.
|
||||
These are USB based chips found in devices such as:
|
||||
|
||||
Netgear WG111v2
|
||||
Level 1 WNC-0301USB
|
||||
Micronet SP907GK V5
|
||||
Encore ENUWI-G2
|
||||
Trendnet TEW-424UB
|
||||
ASUS P5B Deluxe
|
||||
Toshiba Satellite Pro series of laptops
|
||||
|
||||
Thanks to Realtek for their support!
|
||||
|
||||
|
|
|
@ -859,6 +859,18 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev)
|
|||
return DMA_30BIT_MASK;
|
||||
}
|
||||
|
||||
static enum b43legacy_dmatype dma_mask_to_engine_type(u64 dmamask)
|
||||
{
|
||||
if (dmamask == DMA_30BIT_MASK)
|
||||
return B43legacy_DMA_30BIT;
|
||||
if (dmamask == DMA_32BIT_MASK)
|
||||
return B43legacy_DMA_32BIT;
|
||||
if (dmamask == DMA_64BIT_MASK)
|
||||
return B43legacy_DMA_64BIT;
|
||||
B43legacy_WARN_ON(1);
|
||||
return B43legacy_DMA_30BIT;
|
||||
}
|
||||
|
||||
/* Main initialization function. */
|
||||
static
|
||||
struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
||||
|
@ -1018,6 +1030,43 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev)
|
|||
dma->tx_ring0 = NULL;
|
||||
}
|
||||
|
||||
static int b43legacy_dma_set_mask(struct b43legacy_wldev *dev, u64 mask)
|
||||
{
|
||||
u64 orig_mask = mask;
|
||||
bool fallback = 0;
|
||||
int err;
|
||||
|
||||
/* Try to set the DMA mask. If it fails, try falling back to a
|
||||
* lower mask, as we can always also support a lower one. */
|
||||
while (1) {
|
||||
err = ssb_dma_set_mask(dev->dev, mask);
|
||||
if (!err)
|
||||
break;
|
||||
if (mask == DMA_64BIT_MASK) {
|
||||
mask = DMA_32BIT_MASK;
|
||||
fallback = 1;
|
||||
continue;
|
||||
}
|
||||
if (mask == DMA_32BIT_MASK) {
|
||||
mask = DMA_30BIT_MASK;
|
||||
fallback = 1;
|
||||
continue;
|
||||
}
|
||||
b43legacyerr(dev->wl, "The machine/kernel does not support "
|
||||
"the required %u-bit DMA mask\n",
|
||||
(unsigned int)dma_mask_to_engine_type(orig_mask));
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (fallback) {
|
||||
b43legacyinfo(dev->wl, "DMA mask fallback from %u-bit to %u-"
|
||||
"bit\n",
|
||||
(unsigned int)dma_mask_to_engine_type(orig_mask),
|
||||
(unsigned int)dma_mask_to_engine_type(mask));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int b43legacy_dma_init(struct b43legacy_wldev *dev)
|
||||
{
|
||||
struct b43legacy_dma *dma = &dev->dma;
|
||||
|
@ -1027,21 +1076,8 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev)
|
|||
enum b43legacy_dmatype type;
|
||||
|
||||
dmamask = supported_dma_mask(dev);
|
||||
switch (dmamask) {
|
||||
default:
|
||||
B43legacy_WARN_ON(1);
|
||||
case DMA_30BIT_MASK:
|
||||
type = B43legacy_DMA_30BIT;
|
||||
break;
|
||||
case DMA_32BIT_MASK:
|
||||
type = B43legacy_DMA_32BIT;
|
||||
break;
|
||||
case DMA_64BIT_MASK:
|
||||
type = B43legacy_DMA_64BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
err = ssb_dma_set_mask(dev->dev, dmamask);
|
||||
type = dma_mask_to_engine_type(dmamask);
|
||||
err = b43legacy_dma_set_mask(dev, dmamask);
|
||||
if (err) {
|
||||
#ifdef CONFIG_B43LEGACY_PIO
|
||||
b43legacywarn(dev->wl, "DMA for this device not supported. "
|
||||
|
|
|
@ -3417,7 +3417,7 @@ static void prism2_free_local_data(struct net_device *dev)
|
|||
}
|
||||
|
||||
|
||||
#ifndef PRISM2_PLX
|
||||
#if (defined(PRISM2_PCI) && defined(CONFIG_PM)) || defined(PRISM2_PCCARD)
|
||||
static void prism2_suspend(struct net_device *dev)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
|
@ -3436,7 +3436,7 @@ static void prism2_suspend(struct net_device *dev)
|
|||
/* Disable hardware and firmware */
|
||||
prism2_hw_shutdown(dev, 0);
|
||||
}
|
||||
#endif /* PRISM2_PLX */
|
||||
#endif /* (PRISM2_PCI && CONFIG_PM) || PRISM2_PCCARD */
|
||||
|
||||
|
||||
/* These might at some point be compiled separately and used as separate
|
||||
|
|
|
@ -104,6 +104,7 @@ config IWL3945
|
|||
select IWLWIFI
|
||||
select MAC80211_LEDS if IWL3945_LEDS
|
||||
select LEDS_CLASS if IWL3945_LEDS
|
||||
select RFKILL if IWL3945_RFKILL
|
||||
---help---
|
||||
Select to build the driver supporting the:
|
||||
|
||||
|
@ -126,6 +127,10 @@ config IWL3945
|
|||
say M here and read <file:Documentation/kbuild/modules.txt>. The
|
||||
module will be called iwl3945.ko.
|
||||
|
||||
config IWL3945_RFKILL
|
||||
bool "Enable RF kill support in iwl3945 drivers"
|
||||
depends on IWL3945
|
||||
|
||||
config IWL3945_SPECTRUM_MEASUREMENT
|
||||
bool "Enable Spectrum Measurement in iwl3945 drivers"
|
||||
depends on IWL3945
|
||||
|
|
|
@ -690,14 +690,9 @@ enum {
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_RFKILL
|
||||
#ifdef CONFIG_IWL3945_RFKILL
|
||||
struct iwl3945_priv;
|
||||
|
||||
struct iwl3945_rfkill_mngr {
|
||||
struct rfkill *rfkill;
|
||||
struct input_dev *input_dev;
|
||||
};
|
||||
|
||||
void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv);
|
||||
void iwl3945_rfkill_unregister(struct iwl3945_priv *priv);
|
||||
int iwl3945_rfkill_init(struct iwl3945_priv *priv);
|
||||
|
@ -800,8 +795,8 @@ struct iwl3945_priv {
|
|||
struct iwl3945_init_alive_resp card_alive_init;
|
||||
struct iwl3945_alive_resp card_alive;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_RFKILL
|
||||
struct iwl3945_rfkill_mngr rfkill_mngr;
|
||||
#ifdef CONFIG_IWL3945_RFKILL
|
||||
struct rfkill *rfkill;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IWL3945_LEDS
|
||||
|
|
|
@ -2285,9 +2285,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
|
|||
|
||||
iwl4965_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
|
||||
|
||||
if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) {
|
||||
/* TODO: send BAR */
|
||||
}
|
||||
/* check if BAR is needed */
|
||||
if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status))
|
||||
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
|
||||
|
||||
if (txq->q.read_ptr != (scd_ssn & 0xff)) {
|
||||
int freed, ampdu_q;
|
||||
|
|
|
@ -1278,9 +1278,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
|
|||
|
||||
iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
|
||||
|
||||
if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) {
|
||||
/* TODO: send BAR */
|
||||
}
|
||||
/* check if BAR is needed */
|
||||
if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status))
|
||||
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
|
||||
|
||||
if (txq->q.read_ptr != (scd_ssn & 0xff)) {
|
||||
int freed, ampdu_q;
|
||||
|
|
|
@ -356,10 +356,19 @@ static inline int iwl_is_init(struct iwl_priv *priv)
|
|||
return test_bit(STATUS_INIT, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl_is_rfkill_sw(struct iwl_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_RF_KILL_SW, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl_is_rfkill_hw(struct iwl_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_RF_KILL_HW, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl_is_rfkill(struct iwl_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
|
||||
test_bit(STATUS_RF_KILL_SW, &priv->status);
|
||||
return iwl_is_rfkill_hw(priv) || iwl_is_rfkill_sw(priv);
|
||||
}
|
||||
|
||||
static inline int iwl_is_ready_rf(struct iwl_priv *priv)
|
||||
|
|
|
@ -929,7 +929,7 @@ struct iwl_priv {
|
|||
struct iwl_init_alive_resp card_alive_init;
|
||||
struct iwl_alive_resp card_alive;
|
||||
#ifdef CONFIG_IWLWIFI_RFKILL
|
||||
struct iwl_rfkill_mngr rfkill_mngr;
|
||||
struct rfkill *rfkill;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
|
@ -1103,7 +1103,7 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
|
|||
clear_bit(txq_id, &priv->txq_ctx_active_msk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIF_DEBUG
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
const char *iwl_get_tx_fail_reason(u32 status);
|
||||
#else
|
||||
static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
|
||||
|
|
|
@ -44,7 +44,7 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
|
|||
struct iwl_priv *priv = data;
|
||||
int err = 0;
|
||||
|
||||
if (!priv->rfkill_mngr.rfkill)
|
||||
if (!priv->rfkill)
|
||||
return 0;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
|
@ -55,20 +55,20 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
|
|||
|
||||
switch (state) {
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
iwl_radio_kill_sw_enable_radio(priv);
|
||||
/* if HW rf-kill is set dont allow ON state */
|
||||
if (iwl_is_rfkill(priv))
|
||||
if (iwl_is_rfkill_hw(priv)) {
|
||||
err = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
iwl_radio_kill_sw_enable_radio(priv);
|
||||
break;
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
iwl_radio_kill_sw_disable_radio(priv);
|
||||
if (!iwl_is_rfkill(priv))
|
||||
err = -EBUSY;
|
||||
break;
|
||||
default:
|
||||
IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
|
||||
break;
|
||||
}
|
||||
out_unlock:
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return err;
|
||||
|
@ -82,39 +82,35 @@ int iwl_rfkill_init(struct iwl_priv *priv)
|
|||
BUG_ON(device == NULL);
|
||||
|
||||
IWL_DEBUG_RF_KILL("Initializing RFKILL.\n");
|
||||
priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
|
||||
if (!priv->rfkill_mngr.rfkill) {
|
||||
priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
|
||||
if (!priv->rfkill) {
|
||||
IWL_ERROR("Unable to allocate rfkill device.\n");
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->rfkill_mngr.rfkill->name = priv->cfg->name;
|
||||
priv->rfkill_mngr.rfkill->data = priv;
|
||||
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON;
|
||||
priv->rfkill_mngr.rfkill->toggle_radio = iwl_rfkill_soft_rf_kill;
|
||||
priv->rfkill_mngr.rfkill->user_claim_unsupported = 1;
|
||||
priv->rfkill->name = priv->cfg->name;
|
||||
priv->rfkill->data = priv;
|
||||
priv->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
||||
priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill;
|
||||
priv->rfkill->user_claim_unsupported = 1;
|
||||
|
||||
priv->rfkill_mngr.rfkill->dev.class->suspend = NULL;
|
||||
priv->rfkill_mngr.rfkill->dev.class->resume = NULL;
|
||||
priv->rfkill->dev.class->suspend = NULL;
|
||||
priv->rfkill->dev.class->resume = NULL;
|
||||
|
||||
ret = rfkill_register(priv->rfkill_mngr.rfkill);
|
||||
ret = rfkill_register(priv->rfkill);
|
||||
if (ret) {
|
||||
IWL_ERROR("Unable to register rfkill: %d\n", ret);
|
||||
goto unregister_rfkill;
|
||||
goto free_rfkill;
|
||||
}
|
||||
|
||||
IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
|
||||
return ret;
|
||||
|
||||
unregister_rfkill:
|
||||
rfkill_unregister(priv->rfkill_mngr.rfkill);
|
||||
priv->rfkill_mngr.rfkill = NULL;
|
||||
|
||||
freed_rfkill:
|
||||
if (priv->rfkill_mngr.rfkill != NULL)
|
||||
rfkill_free(priv->rfkill_mngr.rfkill);
|
||||
priv->rfkill_mngr.rfkill = NULL;
|
||||
free_rfkill:
|
||||
if (priv->rfkill != NULL)
|
||||
rfkill_free(priv->rfkill);
|
||||
priv->rfkill = NULL;
|
||||
|
||||
error:
|
||||
IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
|
||||
|
@ -125,22 +121,27 @@ EXPORT_SYMBOL(iwl_rfkill_init);
|
|||
void iwl_rfkill_unregister(struct iwl_priv *priv)
|
||||
{
|
||||
|
||||
if (priv->rfkill_mngr.rfkill)
|
||||
rfkill_unregister(priv->rfkill_mngr.rfkill);
|
||||
if (priv->rfkill)
|
||||
rfkill_unregister(priv->rfkill);
|
||||
|
||||
priv->rfkill_mngr.rfkill = NULL;
|
||||
priv->rfkill = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_rfkill_unregister);
|
||||
|
||||
/* set rf-kill to the right state. */
|
||||
void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
|
||||
{
|
||||
if (!priv->rfkill_mngr.rfkill)
|
||||
if (!priv->rfkill)
|
||||
return;
|
||||
|
||||
if (!iwl_is_rfkill(priv))
|
||||
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON;
|
||||
if (iwl_is_rfkill_hw(priv)) {
|
||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iwl_is_rfkill_sw(priv))
|
||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED);
|
||||
else
|
||||
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF;
|
||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_rfkill_set_hw_state);
|
||||
|
|
|
@ -33,9 +33,6 @@ struct iwl_priv;
|
|||
#include <linux/rfkill.h>
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_RFKILL
|
||||
struct iwl_rfkill_mngr {
|
||||
struct rfkill *rfkill;
|
||||
};
|
||||
|
||||
void iwl_rfkill_set_hw_state(struct iwl_priv *priv);
|
||||
void iwl_rfkill_unregister(struct iwl_priv *priv);
|
||||
|
|
|
@ -1493,7 +1493,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_rx_reply_compressed_ba);
|
||||
|
||||
#ifdef CONFIG_IWLWIF_DEBUG
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
|
||||
|
||||
const char *iwl_get_tx_fail_reason(u32 status)
|
||||
|
|
|
@ -537,10 +537,20 @@ static inline int iwl3945_is_init(struct iwl3945_priv *priv)
|
|||
return test_bit(STATUS_INIT, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl3945_is_rfkill_sw(struct iwl3945_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_RF_KILL_SW, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl3945_is_rfkill_hw(struct iwl3945_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_RF_KILL_HW, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl3945_is_rfkill(struct iwl3945_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
|
||||
test_bit(STATUS_RF_KILL_SW, &priv->status);
|
||||
return iwl3945_is_rfkill_hw(priv) ||
|
||||
iwl3945_is_rfkill_sw(priv);
|
||||
}
|
||||
|
||||
static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
|
||||
|
@ -6013,12 +6023,11 @@ static int __iwl3945_up(struct iwl3945_priv *priv)
|
|||
else {
|
||||
set_bit(STATUS_RF_KILL_HW, &priv->status);
|
||||
if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
|
||||
iwl3945_rfkill_set_hw_state(priv);
|
||||
IWL_WARNING("Radio disabled by HW RF Kill switch\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
iwl3945_rfkill_set_hw_state(priv);
|
||||
|
||||
iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
|
||||
|
||||
rc = iwl3945_hw_nic_init(priv);
|
||||
|
@ -6143,8 +6152,8 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
|
|||
"wireless networking to work.\n");
|
||||
}
|
||||
|
||||
iwl3945_rfkill_set_hw_state(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
iwl3945_rfkill_set_hw_state(priv);
|
||||
}
|
||||
|
||||
static void iwl3945_bg_set_monitor(struct work_struct *work)
|
||||
|
@ -6398,6 +6407,7 @@ static void iwl3945_bg_up(struct work_struct *data)
|
|||
mutex_lock(&priv->mutex);
|
||||
__iwl3945_up(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
iwl3945_rfkill_set_hw_state(priv);
|
||||
}
|
||||
|
||||
static void iwl3945_bg_restart(struct work_struct *data)
|
||||
|
@ -6618,6 +6628,8 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
|
|||
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
iwl3945_rfkill_set_hw_state(priv);
|
||||
|
||||
if (ret)
|
||||
goto out_release_irq;
|
||||
|
||||
|
@ -8276,14 +8288,14 @@ static int iwl3945_pci_resume(struct pci_dev *pdev)
|
|||
#endif /* CONFIG_PM */
|
||||
|
||||
/*************** RFKILL FUNCTIONS **********/
|
||||
#ifdef CONFIG_IWLWIFI_RFKILL
|
||||
#ifdef CONFIG_IWL3945_RFKILL
|
||||
/* software rf-kill from user */
|
||||
static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
|
||||
{
|
||||
struct iwl3945_priv *priv = data;
|
||||
int err = 0;
|
||||
|
||||
if (!priv->rfkill_mngr.rfkill)
|
||||
if (!priv->rfkill)
|
||||
return 0;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
|
@ -8294,20 +8306,20 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
|
|||
|
||||
switch (state) {
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
iwl3945_radio_kill_sw(priv, 0);
|
||||
/* if HW rf-kill is set dont allow ON state */
|
||||
if (iwl3945_is_rfkill(priv))
|
||||
if (iwl3945_is_rfkill_hw(priv)) {
|
||||
err = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
iwl3945_radio_kill_sw(priv, 0);
|
||||
break;
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
iwl3945_radio_kill_sw(priv, 1);
|
||||
if (!iwl3945_is_rfkill(priv))
|
||||
err = -EBUSY;
|
||||
break;
|
||||
default:
|
||||
IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
|
||||
break;
|
||||
}
|
||||
out_unlock:
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return err;
|
||||
|
@ -8321,64 +8333,35 @@ int iwl3945_rfkill_init(struct iwl3945_priv *priv)
|
|||
BUG_ON(device == NULL);
|
||||
|
||||
IWL_DEBUG_RF_KILL("Initializing RFKILL.\n");
|
||||
priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
|
||||
if (!priv->rfkill_mngr.rfkill) {
|
||||
priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
|
||||
if (!priv->rfkill) {
|
||||
IWL_ERROR("Unable to allocate rfkill device.\n");
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->rfkill_mngr.rfkill->name = priv->cfg->name;
|
||||
priv->rfkill_mngr.rfkill->data = priv;
|
||||
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON;
|
||||
priv->rfkill_mngr.rfkill->toggle_radio = iwl3945_rfkill_soft_rf_kill;
|
||||
priv->rfkill_mngr.rfkill->user_claim_unsupported = 1;
|
||||
priv->rfkill->name = priv->cfg->name;
|
||||
priv->rfkill->data = priv;
|
||||
priv->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
||||
priv->rfkill->toggle_radio = iwl3945_rfkill_soft_rf_kill;
|
||||
priv->rfkill->user_claim_unsupported = 1;
|
||||
|
||||
priv->rfkill_mngr.rfkill->dev.class->suspend = NULL;
|
||||
priv->rfkill_mngr.rfkill->dev.class->resume = NULL;
|
||||
priv->rfkill->dev.class->suspend = NULL;
|
||||
priv->rfkill->dev.class->resume = NULL;
|
||||
|
||||
priv->rfkill_mngr.input_dev = input_allocate_device();
|
||||
if (!priv->rfkill_mngr.input_dev) {
|
||||
IWL_ERROR("Unable to allocate rfkill input device.\n");
|
||||
ret = -ENOMEM;
|
||||
goto freed_rfkill;
|
||||
}
|
||||
|
||||
priv->rfkill_mngr.input_dev->name = priv->cfg->name;
|
||||
priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy);
|
||||
priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST;
|
||||
priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor;
|
||||
priv->rfkill_mngr.input_dev->dev.parent = device;
|
||||
priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit);
|
||||
|
||||
ret = rfkill_register(priv->rfkill_mngr.rfkill);
|
||||
ret = rfkill_register(priv->rfkill);
|
||||
if (ret) {
|
||||
IWL_ERROR("Unable to register rfkill: %d\n", ret);
|
||||
goto free_input_dev;
|
||||
}
|
||||
|
||||
ret = input_register_device(priv->rfkill_mngr.input_dev);
|
||||
if (ret) {
|
||||
IWL_ERROR("Unable to register rfkill input device: %d\n", ret);
|
||||
goto unregister_rfkill;
|
||||
goto freed_rfkill;
|
||||
}
|
||||
|
||||
IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
|
||||
return ret;
|
||||
|
||||
unregister_rfkill:
|
||||
rfkill_unregister(priv->rfkill_mngr.rfkill);
|
||||
priv->rfkill_mngr.rfkill = NULL;
|
||||
|
||||
free_input_dev:
|
||||
input_free_device(priv->rfkill_mngr.input_dev);
|
||||
priv->rfkill_mngr.input_dev = NULL;
|
||||
|
||||
freed_rfkill:
|
||||
if (priv->rfkill_mngr.rfkill != NULL)
|
||||
rfkill_free(priv->rfkill_mngr.rfkill);
|
||||
priv->rfkill_mngr.rfkill = NULL;
|
||||
if (priv->rfkill != NULL)
|
||||
rfkill_free(priv->rfkill);
|
||||
priv->rfkill = NULL;
|
||||
|
||||
error:
|
||||
IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
|
||||
|
@ -8387,28 +8370,28 @@ error:
|
|||
|
||||
void iwl3945_rfkill_unregister(struct iwl3945_priv *priv)
|
||||
{
|
||||
if (priv->rfkill)
|
||||
rfkill_unregister(priv->rfkill);
|
||||
|
||||
if (priv->rfkill_mngr.input_dev)
|
||||
input_unregister_device(priv->rfkill_mngr.input_dev);
|
||||
|
||||
if (priv->rfkill_mngr.rfkill)
|
||||
rfkill_unregister(priv->rfkill_mngr.rfkill);
|
||||
|
||||
priv->rfkill_mngr.input_dev = NULL;
|
||||
priv->rfkill_mngr.rfkill = NULL;
|
||||
priv->rfkill = NULL;
|
||||
}
|
||||
|
||||
/* set rf-kill to the right state. */
|
||||
void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv)
|
||||
{
|
||||
|
||||
if (!priv->rfkill_mngr.rfkill)
|
||||
if (!priv->rfkill)
|
||||
return;
|
||||
|
||||
if (!iwl3945_is_rfkill(priv))
|
||||
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON;
|
||||
if (iwl3945_is_rfkill_hw(priv)) {
|
||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iwl3945_is_rfkill_sw(priv))
|
||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED);
|
||||
else
|
||||
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF;
|
||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -2187,13 +2187,11 @@ static int __iwl4965_up(struct iwl_priv *priv)
|
|||
|
||||
if (!test_bit(STATUS_IN_SUSPEND, &priv->status) &&
|
||||
iwl_is_rfkill(priv)) {
|
||||
iwl_rfkill_set_hw_state(priv);
|
||||
IWL_WARNING("Radio disabled by %s RF Kill switch\n",
|
||||
test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
iwl_rfkill_set_hw_state(priv);
|
||||
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
|
||||
|
||||
ret = priv->cfg->ops->lib->alloc_shared_mem(priv);
|
||||
|
@ -2330,9 +2328,8 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
|
|||
"Kill switch must be turned off for "
|
||||
"wireless networking to work.\n");
|
||||
}
|
||||
iwl_rfkill_set_hw_state(priv);
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
iwl_rfkill_set_hw_state(priv);
|
||||
}
|
||||
|
||||
static void iwl4965_bg_set_monitor(struct work_struct *work)
|
||||
|
@ -2390,6 +2387,7 @@ static void iwl4965_bg_up(struct work_struct *data)
|
|||
mutex_lock(&priv->mutex);
|
||||
__iwl4965_up(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
iwl_rfkill_set_hw_state(priv);
|
||||
}
|
||||
|
||||
static void iwl4965_bg_restart(struct work_struct *data)
|
||||
|
@ -2604,6 +2602,8 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
|
|||
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
iwl_rfkill_set_hw_state(priv);
|
||||
|
||||
if (ret)
|
||||
goto out_release_irq;
|
||||
|
||||
|
|
|
@ -36,9 +36,7 @@ config RT2X00_LIB_FIRMWARE
|
|||
config RT2X00_LIB_RFKILL
|
||||
boolean
|
||||
depends on RT2X00_LIB
|
||||
depends on INPUT
|
||||
select RFKILL
|
||||
select INPUT_POLLDEV
|
||||
|
||||
config RT2X00_LIB_LEDS
|
||||
boolean
|
||||
|
@ -57,7 +55,7 @@ config RT2400PCI
|
|||
|
||||
config RT2400PCI_RFKILL
|
||||
bool "Ralink rt2400 rfkill support"
|
||||
depends on RT2400PCI && INPUT
|
||||
depends on RT2400PCI
|
||||
select RT2X00_LIB_RFKILL
|
||||
---help---
|
||||
This adds support for integrated rt2400 hardware that features a
|
||||
|
@ -85,7 +83,7 @@ config RT2500PCI
|
|||
|
||||
config RT2500PCI_RFKILL
|
||||
bool "Ralink rt2500 rfkill support"
|
||||
depends on RT2500PCI && INPUT
|
||||
depends on RT2500PCI
|
||||
select RT2X00_LIB_RFKILL
|
||||
---help---
|
||||
This adds support for integrated rt2500 hardware that features a
|
||||
|
@ -115,7 +113,7 @@ config RT61PCI
|
|||
|
||||
config RT61PCI_RFKILL
|
||||
bool "Ralink rt2501/rt61 rfkill support"
|
||||
depends on RT61PCI && INPUT
|
||||
depends on RT61PCI
|
||||
select RT2X00_LIB_RFKILL
|
||||
---help---
|
||||
This adds support for integrated rt61 hardware that features a
|
||||
|
|
|
@ -1087,25 +1087,48 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
|
|||
static void rt2400pci_fill_rxdone(struct queue_entry *entry,
|
||||
struct rxdone_entry_desc *rxdesc)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
|
||||
u32 word0;
|
||||
u32 word2;
|
||||
u32 word3;
|
||||
u32 word4;
|
||||
u64 tsf;
|
||||
u32 rx_low;
|
||||
u32 rx_high;
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 0, &word0);
|
||||
rt2x00_desc_read(entry_priv->desc, 2, &word2);
|
||||
rt2x00_desc_read(entry_priv->desc, 3, &word3);
|
||||
rt2x00_desc_read(entry_priv->desc, 4, &word4);
|
||||
|
||||
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
|
||||
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
|
||||
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
|
||||
rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
|
||||
|
||||
/*
|
||||
* We only get the lower 32bits from the timestamp,
|
||||
* to get the full 64bits we must complement it with
|
||||
* the timestamp from get_tsf().
|
||||
* Note that when a wraparound of the lower 32bits
|
||||
* has occurred between the frame arrival and the get_tsf()
|
||||
* call, we must decrease the higher 32bits with 1 to get
|
||||
* to correct value.
|
||||
*/
|
||||
tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw);
|
||||
rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME);
|
||||
rx_high = upper_32_bits(tsf);
|
||||
|
||||
if ((u32)tsf <= rx_low)
|
||||
rx_high--;
|
||||
|
||||
/*
|
||||
* Obtain the status about this packet.
|
||||
* The signal is the PLCP value, and needs to be stripped
|
||||
* of the preamble bit (0x08).
|
||||
*/
|
||||
rxdesc->timestamp = ((u64)rx_high << 32) | rx_low;
|
||||
rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL) & ~0x08;
|
||||
rxdesc->rssi = rt2x00_get_field32(word2, RXD_W3_RSSI) -
|
||||
entry->queue->rt2x00dev->rssi_offset;
|
||||
|
|
|
@ -751,7 +751,7 @@
|
|||
#define LEDCSR_LED_DEFAULT FIELD32(0x00100000)
|
||||
|
||||
/*
|
||||
* AES control register.
|
||||
* SECCSR3: AES control register.
|
||||
*/
|
||||
#define SECCSR3 0x00fc
|
||||
|
||||
|
@ -895,7 +895,7 @@
|
|||
#define ARTCSR2_ACK_CTS_54MBS FIELD32(0xff000000)
|
||||
|
||||
/*
|
||||
* SECCSR1_RT2509: WEP control register.
|
||||
* SECCSR1: WEP control register.
|
||||
* KICK_ENCRYPT: Kick encryption engine, self-clear.
|
||||
* ONE_SHOT: 0: ring mode, 1: One shot only mode.
|
||||
* DESC_ADDRESS: Descriptor physical address of frame.
|
||||
|
|
|
@ -209,7 +209,7 @@
|
|||
#define MAC_CSR21_OFF_PERIOD FIELD16(0xff00)
|
||||
|
||||
/*
|
||||
* Collision window control register.
|
||||
* MAC_CSR22: Collision window control register.
|
||||
*/
|
||||
#define MAC_CSR22 0x042c
|
||||
|
||||
|
@ -296,7 +296,7 @@
|
|||
#define TXRX_CSR7_BBP_ID1_VALID FIELD16(0x8000)
|
||||
|
||||
/*
|
||||
* TXRX_CSR5: OFDM TX BBP ID1.
|
||||
* TXRX_CSR8: OFDM TX BBP ID1.
|
||||
*/
|
||||
#define TXRX_CSR8 0x0450
|
||||
#define TXRX_CSR8_BBP_ID0 FIELD16(0x007f)
|
||||
|
@ -370,7 +370,14 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* SEC_CSR0-SEC_CSR7: Shared key 0, word 0-7
|
||||
* SEC_CSR0: Shared key 0, word 0
|
||||
* SEC_CSR1: Shared key 0, word 1
|
||||
* SEC_CSR2: Shared key 0, word 2
|
||||
* SEC_CSR3: Shared key 0, word 3
|
||||
* SEC_CSR4: Shared key 0, word 4
|
||||
* SEC_CSR5: Shared key 0, word 5
|
||||
* SEC_CSR6: Shared key 0, word 6
|
||||
* SEC_CSR7: Shared key 0, word 7
|
||||
*/
|
||||
#define SEC_CSR0 0x0480
|
||||
#define SEC_CSR1 0x0482
|
||||
|
@ -382,7 +389,14 @@
|
|||
#define SEC_CSR7 0x048e
|
||||
|
||||
/*
|
||||
* SEC_CSR8-SEC_CSR15: Shared key 1, word 0-7
|
||||
* SEC_CSR8: Shared key 1, word 0
|
||||
* SEC_CSR9: Shared key 1, word 1
|
||||
* SEC_CSR10: Shared key 1, word 2
|
||||
* SEC_CSR11: Shared key 1, word 3
|
||||
* SEC_CSR12: Shared key 1, word 4
|
||||
* SEC_CSR13: Shared key 1, word 5
|
||||
* SEC_CSR14: Shared key 1, word 6
|
||||
* SEC_CSR15: Shared key 1, word 7
|
||||
*/
|
||||
#define SEC_CSR8 0x0490
|
||||
#define SEC_CSR9 0x0492
|
||||
|
@ -394,7 +408,14 @@
|
|||
#define SEC_CSR15 0x049e
|
||||
|
||||
/*
|
||||
* SEC_CSR16-SEC_CSR23: Shared key 2, word 0-7
|
||||
* SEC_CSR16: Shared key 2, word 0
|
||||
* SEC_CSR17: Shared key 2, word 1
|
||||
* SEC_CSR18: Shared key 2, word 2
|
||||
* SEC_CSR19: Shared key 2, word 3
|
||||
* SEC_CSR20: Shared key 2, word 4
|
||||
* SEC_CSR21: Shared key 2, word 5
|
||||
* SEC_CSR22: Shared key 2, word 6
|
||||
* SEC_CSR23: Shared key 2, word 7
|
||||
*/
|
||||
#define SEC_CSR16 0x04a0
|
||||
#define SEC_CSR17 0x04a2
|
||||
|
@ -406,7 +427,14 @@
|
|||
#define SEC_CSR23 0x04ae
|
||||
|
||||
/*
|
||||
* SEC_CSR24-SEC_CSR31: Shared key 3, word 0-7
|
||||
* SEC_CSR24: Shared key 3, word 0
|
||||
* SEC_CSR25: Shared key 3, word 1
|
||||
* SEC_CSR26: Shared key 3, word 2
|
||||
* SEC_CSR27: Shared key 3, word 3
|
||||
* SEC_CSR28: Shared key 3, word 4
|
||||
* SEC_CSR29: Shared key 3, word 5
|
||||
* SEC_CSR30: Shared key 3, word 6
|
||||
* SEC_CSR31: Shared key 3, word 7
|
||||
*/
|
||||
#define SEC_CSR24 0x04b0
|
||||
#define SEC_CSR25 0x04b2
|
||||
|
|
|
@ -649,7 +649,7 @@ struct rt2x00_dev {
|
|||
#define RFKILL_STATE_ALLOCATED 1
|
||||
#define RFKILL_STATE_REGISTERED 2
|
||||
struct rfkill *rfkill;
|
||||
struct input_polled_dev *poll_dev;
|
||||
struct delayed_work rfkill_work;
|
||||
#endif /* CONFIG_RT2X00_LIB_RFKILL */
|
||||
|
||||
/*
|
||||
|
@ -787,8 +787,10 @@ struct rt2x00_dev {
|
|||
|
||||
/*
|
||||
* Scheduled work.
|
||||
* NOTE: intf_work will use ieee80211_iterate_active_interfaces()
|
||||
* which means it cannot be placed on the hw->workqueue
|
||||
* due to RTNL locking requirements.
|
||||
*/
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct intf_work;
|
||||
struct work_struct filter_work;
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
rt2x00lib_reset_link_tuner(rt2x00dev);
|
||||
|
||||
queue_delayed_work(rt2x00dev->workqueue,
|
||||
queue_delayed_work(rt2x00dev->hw->workqueue,
|
||||
&rt2x00dev->link.work, LINK_TUNE_INTERVAL);
|
||||
}
|
||||
|
||||
|
@ -392,7 +392,7 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
|
|||
* Increase tuner counter, and reschedule the next link tuner run.
|
||||
*/
|
||||
rt2x00dev->link.count++;
|
||||
queue_delayed_work(rt2x00dev->workqueue,
|
||||
queue_delayed_work(rt2x00dev->hw->workqueue,
|
||||
&rt2x00dev->link.work, LINK_TUNE_INTERVAL);
|
||||
}
|
||||
|
||||
|
@ -496,7 +496,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
|
|||
rt2x00lib_beacondone_iter,
|
||||
rt2x00dev);
|
||||
|
||||
queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
|
||||
schedule_work(&rt2x00dev->intf_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
|
||||
|
||||
|
@ -664,6 +664,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
|||
|
||||
rt2x00dev->link.qual.rx_success++;
|
||||
|
||||
rx_status->mactime = rxdesc.timestamp;
|
||||
rx_status->rate_idx = idx;
|
||||
rx_status->qual =
|
||||
rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi);
|
||||
|
@ -1064,10 +1065,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
/*
|
||||
* Initialize configuration work.
|
||||
*/
|
||||
rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib");
|
||||
if (!rt2x00dev->workqueue)
|
||||
goto exit;
|
||||
|
||||
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
|
||||
INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
|
||||
INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
|
||||
|
@ -1127,13 +1124,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
|
|||
rt2x00rfkill_free(rt2x00dev);
|
||||
rt2x00leds_unregister(rt2x00dev);
|
||||
|
||||
/*
|
||||
* Stop all queued work. Note that most tasks will already be halted
|
||||
* during rt2x00lib_disable_radio() and rt2x00lib_uninitialize().
|
||||
*/
|
||||
flush_workqueue(rt2x00dev->workqueue);
|
||||
destroy_workqueue(rt2x00dev->workqueue);
|
||||
|
||||
/*
|
||||
* Free ieee80211_hw memory.
|
||||
*/
|
||||
|
@ -1179,7 +1169,6 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
|
|||
* Suspend/disable extra components.
|
||||
*/
|
||||
rt2x00leds_suspend(rt2x00dev);
|
||||
rt2x00rfkill_suspend(rt2x00dev);
|
||||
rt2x00debug_deregister(rt2x00dev);
|
||||
|
||||
exit:
|
||||
|
@ -1235,7 +1224,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
|
|||
* Restore/enable extra components.
|
||||
*/
|
||||
rt2x00debug_register(rt2x00dev);
|
||||
rt2x00rfkill_resume(rt2x00dev);
|
||||
rt2x00leds_resume(rt2x00dev);
|
||||
|
||||
/*
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
* Both the link tuner as the rfkill will be called once per second.
|
||||
*/
|
||||
#define LINK_TUNE_INTERVAL ( round_jiffies_relative(HZ) )
|
||||
#define RFKILL_POLL_INTERVAL ( 1000 )
|
||||
#define RFKILL_POLL_INTERVAL ( round_jiffies_relative(HZ) )
|
||||
|
||||
/*
|
||||
* rt2x00_rate: Per rate device information
|
||||
|
@ -204,8 +204,6 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
|
|||
void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev);
|
||||
#else
|
||||
static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
|
@ -222,14 +220,6 @@ static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
|
|||
static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_RT2X00_LIB_RFKILL */
|
||||
|
||||
/*
|
||||
|
|
|
@ -431,7 +431,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
|||
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
|
||||
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
|
||||
else
|
||||
queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work);
|
||||
queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
|
||||
|
||||
|
@ -512,7 +512,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
|
|||
memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
|
||||
if (delayed) {
|
||||
intf->delayed_flags |= delayed;
|
||||
queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
|
||||
schedule_work(&rt2x00dev->intf_work);
|
||||
}
|
||||
spin_unlock(&intf->lock);
|
||||
}
|
||||
|
|
|
@ -45,10 +45,11 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
|
|||
frame_size = entry->queue->data_size + entry->queue->desc_size;
|
||||
|
||||
/*
|
||||
* Reserve a few bytes extra headroom to allow drivers some moving
|
||||
* space (e.g. for alignment), while keeping the skb aligned.
|
||||
* The payload should be aligned to a 4-byte boundary,
|
||||
* this means we need at least 3 bytes for moving the frame
|
||||
* into the correct offset.
|
||||
*/
|
||||
reserved_size = 8;
|
||||
reserved_size = 4;
|
||||
|
||||
/*
|
||||
* Allocate skbuffer.
|
||||
|
|
|
@ -146,6 +146,7 @@ enum rxdone_entry_desc_flags {
|
|||
*
|
||||
* Summary of information that has been read from the RX frame descriptor.
|
||||
*
|
||||
* @timestamp: RX Timestamp
|
||||
* @signal: Signal of the received frame.
|
||||
* @rssi: RSSI of the received frame.
|
||||
* @size: Data size of the received frame.
|
||||
|
@ -154,6 +155,7 @@ enum rxdone_entry_desc_flags {
|
|||
|
||||
*/
|
||||
struct rxdone_entry_desc {
|
||||
u64 timestamp;
|
||||
int signal;
|
||||
int rssi;
|
||||
int size;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
Abstract: rt2x00 rfkill routines.
|
||||
*/
|
||||
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rfkill.h>
|
||||
|
@ -61,15 +60,35 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
|
||||
static int rt2x00rfkill_get_state(void *data, enum rfkill_state *state)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = poll_dev->private;
|
||||
int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
|
||||
struct rt2x00_dev *rt2x00dev = data;
|
||||
|
||||
if (rt2x00dev->rfkill->state != state) {
|
||||
input_report_key(poll_dev->input, KEY_WLAN, 1);
|
||||
input_report_key(poll_dev->input, KEY_WLAN, 0);
|
||||
}
|
||||
*state = rt2x00dev->rfkill->state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rt2x00rfkill_poll(struct work_struct *work)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev =
|
||||
container_of(work, struct rt2x00_dev, rfkill_work.work);
|
||||
int state;
|
||||
|
||||
if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
|
||||
return;
|
||||
|
||||
/*
|
||||
* rfkill_poll reports 1 when the key has been pressed and the
|
||||
* radio should be blocked.
|
||||
*/
|
||||
state = !rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ?
|
||||
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
|
||||
|
||||
rfkill_force_state(rt2x00dev->rfkill, state);
|
||||
|
||||
queue_delayed_work(rt2x00dev->hw->workqueue,
|
||||
&rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL);
|
||||
}
|
||||
|
||||
void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
|
||||
|
@ -83,12 +102,6 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
|
|||
return;
|
||||
}
|
||||
|
||||
if (input_register_polled_device(rt2x00dev->poll_dev)) {
|
||||
ERROR(rt2x00dev, "Failed to register polled device.\n");
|
||||
rfkill_unregister(rt2x00dev->rfkill);
|
||||
return;
|
||||
}
|
||||
|
||||
__set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
|
||||
|
||||
/*
|
||||
|
@ -96,7 +109,7 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
|
|||
* and correctly sends the signal to the rfkill layer about this
|
||||
* state.
|
||||
*/
|
||||
rt2x00rfkill_poll(rt2x00dev->poll_dev);
|
||||
rt2x00rfkill_poll(&rt2x00dev->rfkill_work.work);
|
||||
}
|
||||
|
||||
void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
|
||||
|
@ -105,38 +118,13 @@ void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
|
|||
!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
|
||||
return;
|
||||
|
||||
input_unregister_polled_device(rt2x00dev->poll_dev);
|
||||
cancel_delayed_work_sync(&rt2x00dev->rfkill_work);
|
||||
|
||||
rfkill_unregister(rt2x00dev->rfkill);
|
||||
|
||||
__clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
|
||||
}
|
||||
|
||||
static struct input_polled_dev *
|
||||
rt2x00rfkill_allocate_polldev(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct input_polled_dev *poll_dev;
|
||||
|
||||
poll_dev = input_allocate_polled_device();
|
||||
if (!poll_dev)
|
||||
return NULL;
|
||||
|
||||
poll_dev->private = rt2x00dev;
|
||||
poll_dev->poll = rt2x00rfkill_poll;
|
||||
poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
|
||||
|
||||
poll_dev->input->name = rt2x00dev->ops->name;
|
||||
poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy);
|
||||
poll_dev->input->id.bustype = BUS_HOST;
|
||||
poll_dev->input->id.vendor = 0x1814;
|
||||
poll_dev->input->id.product = rt2x00dev->chip.rt;
|
||||
poll_dev->input->id.version = rt2x00dev->chip.rev;
|
||||
poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy);
|
||||
poll_dev->input->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_WLAN, poll_dev->input->keybit);
|
||||
|
||||
return poll_dev;
|
||||
}
|
||||
|
||||
void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
|
||||
|
@ -153,14 +141,9 @@ void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
|
|||
rt2x00dev->rfkill->data = rt2x00dev;
|
||||
rt2x00dev->rfkill->state = -1;
|
||||
rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio;
|
||||
rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state;
|
||||
|
||||
rt2x00dev->poll_dev = rt2x00rfkill_allocate_polldev(rt2x00dev);
|
||||
if (!rt2x00dev->poll_dev) {
|
||||
ERROR(rt2x00dev, "Failed to allocate polled device.\n");
|
||||
rfkill_free(rt2x00dev->rfkill);
|
||||
rt2x00dev->rfkill = NULL;
|
||||
return;
|
||||
}
|
||||
INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -171,32 +154,8 @@ void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
|
|||
!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state))
|
||||
return;
|
||||
|
||||
input_free_polled_device(rt2x00dev->poll_dev);
|
||||
rt2x00dev->poll_dev = NULL;
|
||||
cancel_delayed_work_sync(&rt2x00dev->rfkill_work);
|
||||
|
||||
rfkill_free(rt2x00dev->rfkill);
|
||||
rt2x00dev->rfkill = NULL;
|
||||
}
|
||||
|
||||
void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) ||
|
||||
!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state))
|
||||
return;
|
||||
|
||||
input_free_polled_device(rt2x00dev->poll_dev);
|
||||
rt2x00dev->poll_dev = NULL;
|
||||
}
|
||||
|
||||
void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) ||
|
||||
!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state))
|
||||
return;
|
||||
|
||||
rt2x00dev->poll_dev = rt2x00rfkill_allocate_polldev(rt2x00dev);
|
||||
if (!rt2x00dev->poll_dev) {
|
||||
ERROR(rt2x00dev, "Failed to allocate polled device.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,17 +44,48 @@ struct rtl8187_rx_hdr {
|
|||
__le64 mac_time;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct rtl8187_tx_hdr {
|
||||
struct rtl8187b_rx_hdr {
|
||||
__le32 flags;
|
||||
__le64 mac_time;
|
||||
u8 noise;
|
||||
u8 signal;
|
||||
u8 agc;
|
||||
u8 reserved;
|
||||
__le32 unused;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* {rtl8187,rtl8187b}_tx_info is in skb */
|
||||
|
||||
/* Tx flags are common between rtl8187 and rtl8187b */
|
||||
#define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15)
|
||||
#define RTL8187_TX_FLAG_MORE_FRAG (1 << 17)
|
||||
#define RTL8187_TX_FLAG_CTS (1 << 18)
|
||||
#define RTL8187_TX_FLAG_RTS (1 << 23)
|
||||
|
||||
struct rtl8187_tx_hdr {
|
||||
__le32 flags;
|
||||
__le16 rts_duration;
|
||||
__le16 len;
|
||||
__le32 retry;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct rtl8187b_tx_hdr {
|
||||
__le32 flags;
|
||||
__le16 rts_duration;
|
||||
__le16 len;
|
||||
__le32 unused_1;
|
||||
__le16 unused_2;
|
||||
__le16 tx_duration;
|
||||
__le32 unused_3;
|
||||
__le32 retry;
|
||||
__le32 unused_4[2];
|
||||
} __attribute__((packed));
|
||||
|
||||
enum {
|
||||
DEVICE_RTL8187,
|
||||
DEVICE_RTL8187B
|
||||
};
|
||||
|
||||
struct rtl8187_priv {
|
||||
/* common between rtl818x drivers */
|
||||
struct rtl818x_csr *map;
|
||||
|
@ -70,70 +101,120 @@ struct rtl8187_priv {
|
|||
u32 rx_conf;
|
||||
u16 txpwr_base;
|
||||
u8 asic_rev;
|
||||
u8 is_rtl8187b;
|
||||
enum {
|
||||
RTL8187BvB,
|
||||
RTL8187BvD,
|
||||
RTL8187BvE
|
||||
} hw_rev;
|
||||
struct sk_buff_head rx_queue;
|
||||
u8 signal;
|
||||
u8 quality;
|
||||
u8 noise;
|
||||
};
|
||||
|
||||
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
|
||||
|
||||
static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr)
|
||||
static inline u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 idx)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
|
||||
(unsigned long)addr, idx & 0x03, &val,
|
||||
sizeof(val), HZ / 2);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr)
|
||||
static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr)
|
||||
{
|
||||
return rtl818x_ioread8_idx(priv, addr, 0);
|
||||
}
|
||||
|
||||
static inline u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u8 idx)
|
||||
{
|
||||
__le16 val;
|
||||
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
|
||||
(unsigned long)addr, idx & 0x03, &val,
|
||||
sizeof(val), HZ / 2);
|
||||
|
||||
return le16_to_cpu(val);
|
||||
}
|
||||
|
||||
static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr)
|
||||
static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr)
|
||||
{
|
||||
return rtl818x_ioread16_idx(priv, addr, 0);
|
||||
}
|
||||
|
||||
static inline u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u8 idx)
|
||||
{
|
||||
__le32 val;
|
||||
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
|
||||
(unsigned long)addr, idx & 0x03, &val,
|
||||
sizeof(val), HZ / 2);
|
||||
|
||||
return le32_to_cpu(val);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite8(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 val)
|
||||
static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr)
|
||||
{
|
||||
return rtl818x_ioread32_idx(priv, addr, 0);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite8_idx(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 val, u8 idx)
|
||||
{
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
|
||||
(unsigned long)addr, idx & 0x03, &val,
|
||||
sizeof(val), HZ / 2);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite16(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u16 val)
|
||||
static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, u8 *addr, u8 val)
|
||||
{
|
||||
rtl818x_iowrite8_idx(priv, addr, val, 0);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite16_idx(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u16 val, u8 idx)
|
||||
{
|
||||
__le16 buf = cpu_to_le16(val);
|
||||
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
|
||||
(unsigned long)addr, idx & 0x03, &buf, sizeof(buf),
|
||||
HZ / 2);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite32(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u32 val)
|
||||
static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, __le16 *addr,
|
||||
u16 val)
|
||||
{
|
||||
rtl818x_iowrite16_idx(priv, addr, val, 0);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite32_idx(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u32 val, u8 idx)
|
||||
{
|
||||
__le32 buf = cpu_to_le32(val);
|
||||
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
|
||||
(unsigned long)addr, idx & 0x03, &buf, sizeof(buf),
|
||||
HZ / 2);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, __le32 *addr,
|
||||
u32 val)
|
||||
{
|
||||
rtl818x_iowrite32_idx(priv, addr, val, 0);
|
||||
}
|
||||
|
||||
#endif /* RTL8187_H */
|
||||
|
|
|
@ -27,19 +27,21 @@
|
|||
|
||||
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
|
||||
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
|
||||
MODULE_DESCRIPTION("RTL8187 USB wireless driver");
|
||||
MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static struct usb_device_id rtl8187_table[] __devinitdata = {
|
||||
/* Realtek */
|
||||
{USB_DEVICE(0x0bda, 0x8187)},
|
||||
{USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187},
|
||||
{USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B},
|
||||
{USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B},
|
||||
/* Netgear */
|
||||
{USB_DEVICE(0x0846, 0x6100)},
|
||||
{USB_DEVICE(0x0846, 0x6a00)},
|
||||
{USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187},
|
||||
{USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187},
|
||||
/* HP */
|
||||
{USB_DEVICE(0x03f0, 0xca02)},
|
||||
{USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187},
|
||||
/* Sitecom */
|
||||
{USB_DEVICE(0x0df6, 0x000d)},
|
||||
{USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -153,9 +155,11 @@ static void rtl8187_tx_cb(struct urb *urb)
|
|||
struct sk_buff *skb = (struct sk_buff *)urb->context;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hw *hw = info->driver_data[0];
|
||||
struct rtl8187_priv *priv = hw->priv;
|
||||
|
||||
usb_free_urb(info->driver_data[1]);
|
||||
skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
|
||||
skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
|
||||
sizeof(struct rtl8187_tx_hdr));
|
||||
memset(&info->status, 0, sizeof(info->status));
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
ieee80211_tx_status_irqsafe(hw, skb);
|
||||
|
@ -165,7 +169,8 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct rtl8187_tx_hdr *hdr;
|
||||
unsigned int ep;
|
||||
void *buf;
|
||||
struct urb *urb;
|
||||
__le16 rts_dur = 0;
|
||||
u32 flags;
|
||||
|
@ -193,16 +198,47 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
|
||||
}
|
||||
|
||||
hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
|
||||
hdr->flags = cpu_to_le32(flags);
|
||||
hdr->len = 0;
|
||||
hdr->rts_duration = rts_dur;
|
||||
hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
|
||||
if (!priv->is_rtl8187b) {
|
||||
struct rtl8187_tx_hdr *hdr =
|
||||
(struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
|
||||
hdr->flags = cpu_to_le32(flags);
|
||||
hdr->len = 0;
|
||||
hdr->rts_duration = rts_dur;
|
||||
hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
|
||||
buf = hdr;
|
||||
|
||||
ep = 2;
|
||||
} else {
|
||||
/* fc needs to be calculated before skb_push() */
|
||||
unsigned int epmap[4] = { 6, 7, 5, 4 };
|
||||
struct ieee80211_hdr *tx_hdr =
|
||||
(struct ieee80211_hdr *)(skb->data);
|
||||
u16 fc = le16_to_cpu(tx_hdr->frame_control);
|
||||
|
||||
struct rtl8187b_tx_hdr *hdr =
|
||||
(struct rtl8187b_tx_hdr *)skb_push(skb, sizeof(*hdr));
|
||||
struct ieee80211_rate *txrate =
|
||||
ieee80211_get_tx_rate(dev, info);
|
||||
memset(hdr, 0, sizeof(*hdr));
|
||||
hdr->flags = cpu_to_le32(flags);
|
||||
hdr->rts_duration = rts_dur;
|
||||
hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
|
||||
hdr->tx_duration =
|
||||
ieee80211_generic_frame_duration(dev, priv->vif,
|
||||
skb->len, txrate);
|
||||
buf = hdr;
|
||||
|
||||
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
|
||||
ep = 12;
|
||||
else
|
||||
ep = epmap[skb_get_queue_mapping(skb)];
|
||||
}
|
||||
|
||||
info->driver_data[0] = dev;
|
||||
info->driver_data[1] = urb;
|
||||
usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
|
||||
hdr, skb->len, rtl8187_tx_cb, skb);
|
||||
|
||||
usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep),
|
||||
buf, skb->len, rtl8187_tx_cb, skb);
|
||||
rc = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (rc < 0) {
|
||||
usb_free_urb(urb);
|
||||
|
@ -218,7 +254,6 @@ static void rtl8187_rx_cb(struct urb *urb)
|
|||
struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb;
|
||||
struct ieee80211_hw *dev = info->dev;
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
struct rtl8187_rx_hdr *hdr;
|
||||
struct ieee80211_rx_status rx_status = { 0 };
|
||||
int rate, signal;
|
||||
u32 flags;
|
||||
|
@ -239,11 +274,33 @@ static void rtl8187_rx_cb(struct urb *urb)
|
|||
}
|
||||
|
||||
skb_put(skb, urb->actual_length);
|
||||
hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
|
||||
flags = le32_to_cpu(hdr->flags);
|
||||
skb_trim(skb, flags & 0x0FFF);
|
||||
if (!priv->is_rtl8187b) {
|
||||
struct rtl8187_rx_hdr *hdr =
|
||||
(typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
|
||||
flags = le32_to_cpu(hdr->flags);
|
||||
signal = hdr->signal & 0x7f;
|
||||
rx_status.antenna = (hdr->signal >> 7) & 1;
|
||||
rx_status.signal = signal;
|
||||
rx_status.noise = hdr->noise;
|
||||
rx_status.mactime = le64_to_cpu(hdr->mac_time);
|
||||
priv->signal = signal;
|
||||
priv->quality = signal;
|
||||
priv->noise = hdr->noise;
|
||||
} else {
|
||||
struct rtl8187b_rx_hdr *hdr =
|
||||
(typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
|
||||
flags = le32_to_cpu(hdr->flags);
|
||||
signal = hdr->agc >> 1;
|
||||
rx_status.antenna = (hdr->signal >> 7) & 1;
|
||||
rx_status.signal = 64 - min(hdr->noise, (u8)64);
|
||||
rx_status.noise = hdr->noise;
|
||||
rx_status.mactime = le64_to_cpu(hdr->mac_time);
|
||||
priv->signal = hdr->signal;
|
||||
priv->quality = hdr->agc >> 1;
|
||||
priv->noise = hdr->noise;
|
||||
}
|
||||
|
||||
signal = hdr->agc >> 1;
|
||||
skb_trim(skb, flags & 0x0FFF);
|
||||
rate = (flags >> 20) & 0xF;
|
||||
if (rate > 3) { /* OFDM rate */
|
||||
if (signal > 90)
|
||||
|
@ -259,13 +316,11 @@ static void rtl8187_rx_cb(struct urb *urb)
|
|||
signal = 95 - signal;
|
||||
}
|
||||
|
||||
rx_status.antenna = (hdr->signal >> 7) & 1;
|
||||
rx_status.qual = 64 - min(hdr->noise, (u8)64);
|
||||
rx_status.qual = priv->quality;
|
||||
rx_status.signal = signal;
|
||||
rx_status.rate_idx = rate;
|
||||
rx_status.freq = dev->conf.channel->center_freq;
|
||||
rx_status.band = dev->conf.channel->band;
|
||||
rx_status.mactime = le64_to_cpu(hdr->mac_time);
|
||||
rx_status.flag |= RX_FLAG_TSFT;
|
||||
if (flags & (1 << 13))
|
||||
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
|
@ -305,7 +360,8 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
|
|||
break;
|
||||
}
|
||||
usb_fill_bulk_urb(entry, priv->udev,
|
||||
usb_rcvbulkpipe(priv->udev, 1),
|
||||
usb_rcvbulkpipe(priv->udev,
|
||||
priv->is_rtl8187b ? 3 : 1),
|
||||
skb_tail_pointer(skb),
|
||||
RTL8187_MAX_RX, rtl8187_rx_cb, skb);
|
||||
info = (struct rtl8187_rx_info *)skb->cb;
|
||||
|
@ -318,29 +374,12 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8187_init_hw(struct ieee80211_hw *dev)
|
||||
static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
u8 reg;
|
||||
int i;
|
||||
|
||||
/* reset */
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
|
||||
|
||||
msleep(200);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00);
|
||||
msleep(200);
|
||||
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CMD);
|
||||
reg &= (1 << 1);
|
||||
reg |= RTL818X_CMD_RESET;
|
||||
|
@ -376,12 +415,48 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8187_init_hw(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
u8 reg;
|
||||
int res;
|
||||
|
||||
/* reset */
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_CONFIG);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg |
|
||||
RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg &
|
||||
~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
|
||||
|
||||
msleep(200);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00);
|
||||
msleep(200);
|
||||
|
||||
res = rtl8187_cmd_reset(dev);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
|
||||
reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
|
||||
reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
/* setup card */
|
||||
|
@ -426,9 +501,11 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
|
|||
rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
|
||||
rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
|
||||
rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_CONFIG);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_NORMAL);
|
||||
rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7);
|
||||
msleep(100);
|
||||
|
||||
|
@ -445,16 +522,198 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const u8 rtl8187b_reg_table[][3] = {
|
||||
{0xF0, 0x32, 0}, {0xF1, 0x32, 0}, {0xF2, 0x00, 0}, {0xF3, 0x00, 0},
|
||||
{0xF4, 0x32, 0}, {0xF5, 0x43, 0}, {0xF6, 0x00, 0}, {0xF7, 0x00, 0},
|
||||
{0xF8, 0x46, 0}, {0xF9, 0xA4, 0}, {0xFA, 0x00, 0}, {0xFB, 0x00, 0},
|
||||
{0xFC, 0x96, 0}, {0xFD, 0xA4, 0}, {0xFE, 0x00, 0}, {0xFF, 0x00, 0},
|
||||
|
||||
{0x58, 0x4B, 1}, {0x59, 0x00, 1}, {0x5A, 0x4B, 1}, {0x5B, 0x00, 1},
|
||||
{0x60, 0x4B, 1}, {0x61, 0x09, 1}, {0x62, 0x4B, 1}, {0x63, 0x09, 1},
|
||||
{0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xE0, 0xFF, 1}, {0xE1, 0x0F, 1},
|
||||
{0xE2, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, {0xF2, 0x02, 1},
|
||||
{0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, {0xF6, 0x06, 1},
|
||||
{0xF7, 0x07, 1}, {0xF8, 0x08, 1},
|
||||
|
||||
{0x4E, 0x00, 2}, {0x0C, 0x04, 2}, {0x21, 0x61, 2}, {0x22, 0x68, 2},
|
||||
{0x23, 0x6F, 2}, {0x24, 0x76, 2}, {0x25, 0x7D, 2}, {0x26, 0x84, 2},
|
||||
{0x27, 0x8D, 2}, {0x4D, 0x08, 2}, {0x50, 0x05, 2}, {0x51, 0xF5, 2},
|
||||
{0x52, 0x04, 2}, {0x53, 0xA0, 2}, {0x54, 0x1F, 2}, {0x55, 0x23, 2},
|
||||
{0x56, 0x45, 2}, {0x57, 0x67, 2}, {0x58, 0x08, 2}, {0x59, 0x08, 2},
|
||||
{0x5A, 0x08, 2}, {0x5B, 0x08, 2}, {0x60, 0x08, 2}, {0x61, 0x08, 2},
|
||||
{0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2},
|
||||
{0x73, 0x9A, 2},
|
||||
|
||||
{0x34, 0xF0, 0}, {0x35, 0x0F, 0}, {0x5B, 0x40, 0}, {0x84, 0x88, 0},
|
||||
{0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0},
|
||||
{0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0},
|
||||
{0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0},
|
||||
{0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0},
|
||||
|
||||
{0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0},
|
||||
{0x8E, 0x08, 0}, {0x8F, 0x00, 0}
|
||||
};
|
||||
|
||||
static int rtl8187b_init_hw(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
int res, i;
|
||||
u8 reg;
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_CONFIG);
|
||||
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT;
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, 0x727f3f52);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM, 0x45090658);
|
||||
rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, 0);
|
||||
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10);
|
||||
reg = rtl818x_ioread8(priv, (u8 *)0xFF62);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5));
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5));
|
||||
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE;
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
res = rtl8187_cmd_reset(dev);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
rtl818x_iowrite16(priv, (__le16 *)0xFF2D, 0x0FFF);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
|
||||
reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
|
||||
rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
|
||||
reg |= RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT |
|
||||
RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
|
||||
rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
|
||||
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->RATE_FALLBACK);
|
||||
reg |= RTL818X_RATE_FALLBACK_ENABLE;
|
||||
rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, reg);
|
||||
|
||||
rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
|
||||
rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFFD4, 0xFFFF, 1);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_CONFIG);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG1, (reg & 0x3F) | 0x80);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
|
||||
for (i = 0; i < ARRAY_SIZE(rtl8187b_reg_table); i++) {
|
||||
rtl818x_iowrite8_idx(priv,
|
||||
(u8 *)(uintptr_t)
|
||||
(rtl8187b_reg_table[i][0] | 0xFF00),
|
||||
rtl8187b_reg_table[i][1],
|
||||
rtl8187b_reg_table[i][2]);
|
||||
}
|
||||
|
||||
rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50);
|
||||
rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0);
|
||||
|
||||
rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF0, 0, 1);
|
||||
rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF4, 0, 1);
|
||||
rtl818x_iowrite8_idx(priv, (u8 *)0xFFF8, 0, 1);
|
||||
|
||||
rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00004001);
|
||||
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_CONFIG);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
reg |= RTL818X_CONFIG3_ANAPARAM_WRITE;
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
|
||||
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488);
|
||||
rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
|
||||
msleep(1100);
|
||||
|
||||
priv->rf->init(dev);
|
||||
|
||||
reg = RTL818X_CMD_TX_ENABLE | RTL818X_CMD_RX_ENABLE;
|
||||
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
|
||||
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
|
||||
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE41, 0xF4);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x00);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x0F);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01);
|
||||
|
||||
reg = rtl818x_ioread8(priv, (u8 *)0xFFDB);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFFDB, reg | (1 << 2));
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x59FA, 3);
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFF74, 0x59D2, 3);
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFF76, 0x59D2, 3);
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFF78, 0x19FA, 3);
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7A, 0x19FA, 3);
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7C, 0x00D0, 3);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFF61, 0);
|
||||
rtl818x_iowrite8_idx(priv, (u8 *)0xFF80, 0x0F, 1);
|
||||
rtl818x_iowrite8_idx(priv, (u8 *)0xFF83, 0x03, 1);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFFDA, 0x10);
|
||||
rtl818x_iowrite8_idx(priv, (u8 *)0xFF4D, 0x08, 2);
|
||||
|
||||
rtl818x_iowrite32(priv, &priv->map->HSSI_PARA, 0x0600321B);
|
||||
|
||||
rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8187_start(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
ret = rtl8187_init_hw(dev);
|
||||
ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) :
|
||||
rtl8187b_init_hw(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->is_rtl8187b) {
|
||||
reg = RTL818X_RX_CONF_MGMT |
|
||||
RTL818X_RX_CONF_DATA |
|
||||
RTL818X_RX_CONF_BROADCAST |
|
||||
RTL818X_RX_CONF_NICMAC |
|
||||
RTL818X_RX_CONF_BSSID |
|
||||
(7 << 13 /* RX FIFO threshold NONE */) |
|
||||
(7 << 10 /* MAX RX DMA */) |
|
||||
RTL818X_RX_CONF_RX_AUTORESETPHY |
|
||||
RTL818X_RX_CONF_ONLYERLPKT |
|
||||
RTL818X_RX_CONF_MULTICAST;
|
||||
priv->rx_conf = reg;
|
||||
rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
|
||||
|
||||
rtl818x_iowrite32(priv, &priv->map->TX_CONF,
|
||||
RTL818X_TX_CONF_HW_SEQNUM |
|
||||
RTL818X_TX_CONF_DISREQQSIZE |
|
||||
(7 << 8 /* short retry limit */) |
|
||||
(7 << 0 /* long retry limit */) |
|
||||
(7 << 21 /* MAX TX DMA */));
|
||||
rtl8187_init_urbs(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
|
||||
|
||||
rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
|
||||
|
@ -581,18 +840,20 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
|
|||
msleep(10);
|
||||
rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
|
||||
if (!priv->is_rtl8187b) {
|
||||
rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
|
||||
|
||||
if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
|
||||
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
|
||||
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
|
||||
rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
|
||||
rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
|
||||
} else {
|
||||
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
|
||||
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
|
||||
rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
|
||||
rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
|
||||
if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
|
||||
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
|
||||
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
|
||||
rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
|
||||
rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
|
||||
} else {
|
||||
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
|
||||
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
|
||||
rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
|
||||
rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
|
||||
}
|
||||
}
|
||||
|
||||
rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
|
||||
|
@ -608,14 +869,20 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
|
|||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
int i;
|
||||
u8 reg;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
|
||||
|
||||
if (is_valid_ether_addr(conf->bssid))
|
||||
rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA);
|
||||
else
|
||||
rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK);
|
||||
if (is_valid_ether_addr(conf->bssid)) {
|
||||
reg = RTL818X_MSR_INFRA;
|
||||
if (priv->is_rtl8187b)
|
||||
reg |= RTL818X_MSR_ENEDCA;
|
||||
rtl818x_iowrite8(priv, &priv->map->MSR, reg);
|
||||
} else {
|
||||
reg = RTL818X_MSR_NO_LINK;
|
||||
rtl818x_iowrite8(priv, &priv->map->MSR, reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -702,6 +969,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
|
|||
struct rtl8187_priv *priv;
|
||||
struct eeprom_93cx6 eeprom;
|
||||
struct ieee80211_channel *channel;
|
||||
const char *chip_name;
|
||||
u16 txpwr, reg;
|
||||
int err, i;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
@ -713,6 +981,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
|
|||
}
|
||||
|
||||
priv = dev->priv;
|
||||
priv->is_rtl8187b = (id->driver_info == DEVICE_RTL8187B);
|
||||
|
||||
SET_IEEE80211_DEV(dev, &intf->dev);
|
||||
usb_set_intfdata(intf, dev);
|
||||
|
@ -741,8 +1010,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
|
|||
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
|
||||
IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
IEEE80211_HW_SIGNAL_UNSPEC;
|
||||
dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
|
||||
dev->queues = 1;
|
||||
dev->max_signal = 65;
|
||||
|
||||
eeprom.data = dev;
|
||||
|
@ -777,12 +1044,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
|
|||
(*channel++).hw_value = txpwr & 0xFF;
|
||||
(*channel++).hw_value = txpwr >> 8;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6 + i,
|
||||
&txpwr);
|
||||
(*channel++).hw_value = txpwr & 0xFF;
|
||||
(*channel++).hw_value = txpwr >> 8;
|
||||
}
|
||||
|
||||
eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE,
|
||||
&priv->txpwr_base);
|
||||
|
@ -796,7 +1057,90 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
|
|||
rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
if (!priv->is_rtl8187b) {
|
||||
u32 reg32;
|
||||
reg32 = rtl818x_ioread32(priv, &priv->map->TX_CONF);
|
||||
reg32 &= RTL818X_TX_CONF_HWVER_MASK;
|
||||
switch (reg32) {
|
||||
case RTL818X_TX_CONF_R8187vD_B:
|
||||
/* Some RTL8187B devices have a USB ID of 0x8187
|
||||
* detect them here */
|
||||
chip_name = "RTL8187BvB(early)";
|
||||
priv->is_rtl8187b = 1;
|
||||
priv->hw_rev = RTL8187BvB;
|
||||
break;
|
||||
case RTL818X_TX_CONF_R8187vD:
|
||||
chip_name = "RTL8187vD";
|
||||
break;
|
||||
default:
|
||||
chip_name = "RTL8187vB (default)";
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Force USB request to write radio registers for 8187B, Realtek
|
||||
* only uses it in their sources
|
||||
*/
|
||||
/*if (priv->asic_rev == 0) {
|
||||
printk(KERN_WARNING "rtl8187: Forcing use of USB "
|
||||
"requests to write to radio registers\n");
|
||||
priv->asic_rev = 1;
|
||||
}*/
|
||||
switch (rtl818x_ioread8(priv, (u8 *)0xFFE1)) {
|
||||
case RTL818X_R8187B_B:
|
||||
chip_name = "RTL8187BvB";
|
||||
priv->hw_rev = RTL8187BvB;
|
||||
break;
|
||||
case RTL818X_R8187B_D:
|
||||
chip_name = "RTL8187BvD";
|
||||
priv->hw_rev = RTL8187BvD;
|
||||
break;
|
||||
case RTL818X_R8187B_E:
|
||||
chip_name = "RTL8187BvE";
|
||||
priv->hw_rev = RTL8187BvE;
|
||||
break;
|
||||
default:
|
||||
chip_name = "RTL8187BvB (default)";
|
||||
priv->hw_rev = RTL8187BvB;
|
||||
}
|
||||
}
|
||||
|
||||
if (!priv->is_rtl8187b) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
eeprom_93cx6_read(&eeprom,
|
||||
RTL8187_EEPROM_TXPWR_CHAN_6 + i,
|
||||
&txpwr);
|
||||
(*channel++).hw_value = txpwr & 0xFF;
|
||||
(*channel++).hw_value = txpwr >> 8;
|
||||
}
|
||||
} else {
|
||||
eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6,
|
||||
&txpwr);
|
||||
(*channel++).hw_value = txpwr & 0xFF;
|
||||
|
||||
eeprom_93cx6_read(&eeprom, 0x0A, &txpwr);
|
||||
(*channel++).hw_value = txpwr & 0xFF;
|
||||
|
||||
eeprom_93cx6_read(&eeprom, 0x1C, &txpwr);
|
||||
(*channel++).hw_value = txpwr & 0xFF;
|
||||
(*channel++).hw_value = txpwr >> 8;
|
||||
}
|
||||
|
||||
if (priv->is_rtl8187b)
|
||||
printk(KERN_WARNING "rtl8187: 8187B chip detected. Support "
|
||||
"is EXPERIMENTAL, and could damage your\n"
|
||||
" hardware, use at your own risk\n");
|
||||
if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
|
||||
printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
|
||||
" info!\n");
|
||||
|
||||
priv->rf = rtl8187_detect_rf(dev);
|
||||
dev->extra_tx_headroom = (!priv->is_rtl8187b) ?
|
||||
sizeof(struct rtl8187_tx_hdr) :
|
||||
sizeof(struct rtl8187b_tx_hdr);
|
||||
if (!priv->is_rtl8187b)
|
||||
dev->queues = 1;
|
||||
else
|
||||
dev->queues = 4;
|
||||
|
||||
err = ieee80211_register_hw(dev);
|
||||
if (err) {
|
||||
|
@ -804,9 +1148,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
|
|||
goto err_free_dev;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n",
|
||||
printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n",
|
||||
wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
|
||||
priv->asic_rev, priv->rf->name);
|
||||
chip_name, priv->asic_rev, priv->rf->name);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -305,9 +305,11 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
|
|||
/* anaparam2 on */
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
|
||||
reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
|
||||
reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
rtl8225_write_phy_ofdm(dev, 2, 0x42);
|
||||
|
@ -471,12 +473,42 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev)
|
|||
rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
|
||||
}
|
||||
|
||||
static const u8 rtl8225z2_agc[] = {
|
||||
0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f,
|
||||
0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,
|
||||
0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f,
|
||||
0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,
|
||||
0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
|
||||
0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28,
|
||||
0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30,
|
||||
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
|
||||
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
|
||||
};
|
||||
static const u8 rtl8225z2_ofdm[] = {
|
||||
0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,
|
||||
0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,
|
||||
0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,
|
||||
0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f,
|
||||
0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,
|
||||
0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,
|
||||
0x6d, 0x3c, 0xfb, 0x07
|
||||
};
|
||||
|
||||
static const u8 rtl8225z2_tx_power_cck_ch14[] = {
|
||||
0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
|
||||
0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const u8 rtl8225z2_tx_power_cck[] = {
|
||||
0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
|
||||
0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
|
||||
0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
|
||||
0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
|
||||
0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
|
||||
};
|
||||
|
||||
static const u8 rtl8225z2_tx_power_ofdm[] = {
|
||||
|
@ -526,9 +558,11 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
|
|||
/* anaparam2 on */
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
|
||||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
|
||||
reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
|
||||
reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
|
||||
|
||||
rtl8225_write_phy_ofdm(dev, 2, 0x42);
|
||||
|
@ -542,6 +576,85 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
|
|||
msleep(1);
|
||||
}
|
||||
|
||||
static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
|
||||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
u8 cck_power, ofdm_power;
|
||||
const u8 *tmp;
|
||||
int i;
|
||||
|
||||
cck_power = priv->channels[channel - 1].hw_value & 0xF;
|
||||
ofdm_power = priv->channels[channel - 1].hw_value >> 4;
|
||||
|
||||
if (cck_power > 15)
|
||||
cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22;
|
||||
else
|
||||
cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7;
|
||||
cck_power += priv->txpwr_base & 0xF;
|
||||
cck_power = min(cck_power, (u8)35);
|
||||
|
||||
if (ofdm_power > 15)
|
||||
ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25;
|
||||
else
|
||||
ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10;
|
||||
ofdm_power += (priv->txpwr_base >> 4) & 0xF;
|
||||
ofdm_power = min(ofdm_power, (u8)35);
|
||||
|
||||
if (channel == 14)
|
||||
tmp = rtl8225z2_tx_power_cck_ch14;
|
||||
else
|
||||
tmp = rtl8225z2_tx_power_cck;
|
||||
|
||||
if (priv->hw_rev == RTL8187BvB) {
|
||||
if (cck_power <= 6)
|
||||
; /* do nothing */
|
||||
else if (cck_power <= 11)
|
||||
tmp += 8;
|
||||
else
|
||||
tmp += 16;
|
||||
} else {
|
||||
if (cck_power <= 5)
|
||||
; /* do nothing */
|
||||
else if (cck_power <= 11)
|
||||
tmp += 8;
|
||||
else if (cck_power <= 17)
|
||||
tmp += 16;
|
||||
else
|
||||
tmp += 24;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
|
||||
rtl8225z2_tx_gain_cck_ofdm[cck_power]);
|
||||
msleep(1);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
|
||||
rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1);
|
||||
if (priv->hw_rev == RTL8187BvB) {
|
||||
if (ofdm_power <= 11) {
|
||||
rtl8225_write_phy_ofdm(dev, 0x87, 0x60);
|
||||
rtl8225_write_phy_ofdm(dev, 0x89, 0x60);
|
||||
} else {
|
||||
rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);
|
||||
rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);
|
||||
}
|
||||
} else {
|
||||
if (ofdm_power <= 11) {
|
||||
rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);
|
||||
rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);
|
||||
} else if (ofdm_power <= 17) {
|
||||
rtl8225_write_phy_ofdm(dev, 0x87, 0x54);
|
||||
rtl8225_write_phy_ofdm(dev, 0x89, 0x54);
|
||||
} else {
|
||||
rtl8225_write_phy_ofdm(dev, 0x87, 0x50);
|
||||
rtl8225_write_phy_ofdm(dev, 0x89, 0x50);
|
||||
}
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
static const u16 rtl8225z2_rxgain[] = {
|
||||
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
|
||||
0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
|
||||
|
@ -715,6 +828,81 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
|
|||
rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
|
||||
}
|
||||
|
||||
static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
int i;
|
||||
|
||||
rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
|
||||
rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
|
||||
rtl8225_write(dev, 0x2, 0x44D); msleep(1);
|
||||
rtl8225_write(dev, 0x3, 0x441); msleep(1);
|
||||
rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
|
||||
rtl8225_write(dev, 0x5, 0xC72); msleep(1);
|
||||
rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
|
||||
rtl8225_write(dev, 0x7, 0x82A); msleep(1);
|
||||
rtl8225_write(dev, 0x8, 0x03F); msleep(1);
|
||||
rtl8225_write(dev, 0x9, 0x335); msleep(1);
|
||||
rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
|
||||
rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
|
||||
rtl8225_write(dev, 0xc, 0x850); msleep(1);
|
||||
rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
|
||||
rtl8225_write(dev, 0xe, 0x02B); msleep(1);
|
||||
rtl8225_write(dev, 0xf, 0x114); msleep(1);
|
||||
|
||||
rtl8225_write(dev, 0x0, 0x1B7); msleep(1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
|
||||
rtl8225_write(dev, 0x1, i + 1); msleep(1);
|
||||
rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1);
|
||||
}
|
||||
|
||||
rtl8225_write(dev, 0x3, 0x080); msleep(1);
|
||||
rtl8225_write(dev, 0x5, 0x004); msleep(1);
|
||||
rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
|
||||
msleep(3000);
|
||||
|
||||
rtl8225_write(dev, 0x2, 0xC4D); msleep(1);
|
||||
msleep(2000);
|
||||
|
||||
rtl8225_write(dev, 0x2, 0x44D); msleep(1);
|
||||
rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);
|
||||
rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);
|
||||
rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
|
||||
|
||||
rtl8225_write_phy_ofdm(dev, 0x80, 0x12);
|
||||
for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) {
|
||||
rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]);
|
||||
rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i);
|
||||
rtl8225_write_phy_ofdm(dev, 0xE, 0);
|
||||
}
|
||||
rtl8225_write_phy_ofdm(dev, 0x80, 0x10);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
|
||||
rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);
|
||||
|
||||
rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
|
||||
rtl818x_iowrite8(priv, &priv->map->SLOT, 9);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFFF0, 28);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFFF4, 28);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFFF8, 28);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFFFC, 28);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFF2D, 0x5B);
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFF79, 0x5B);
|
||||
rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28);
|
||||
rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28);
|
||||
rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28);
|
||||
rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28);
|
||||
rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
|
||||
|
||||
rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1);
|
||||
rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1);
|
||||
rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1);
|
||||
rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1);
|
||||
}
|
||||
|
||||
static void rtl8225_rf_stop(struct ieee80211_hw *dev)
|
||||
{
|
||||
u8 reg;
|
||||
|
@ -739,8 +927,10 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
|
|||
|
||||
if (priv->rf->init == rtl8225_rf_init)
|
||||
rtl8225_rf_set_tx_power(dev, chan);
|
||||
else
|
||||
else if (priv->rf->init == rtl8225z2_rf_init)
|
||||
rtl8225z2_rf_set_tx_power(dev, chan);
|
||||
else
|
||||
rtl8225z2_b_rf_set_tx_power(dev, chan);
|
||||
|
||||
rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
|
||||
msleep(10);
|
||||
|
@ -760,19 +950,30 @@ static const struct rtl818x_rf_ops rtl8225z2_ops = {
|
|||
.set_chan = rtl8225_rf_set_channel
|
||||
};
|
||||
|
||||
static const struct rtl818x_rf_ops rtl8225z2_b_ops = {
|
||||
.name = "rtl8225z2",
|
||||
.init = rtl8225z2_b_rf_init,
|
||||
.stop = rtl8225_rf_stop,
|
||||
.set_chan = rtl8225_rf_set_channel
|
||||
};
|
||||
|
||||
const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev)
|
||||
{
|
||||
u16 reg8, reg9;
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
|
||||
rtl8225_write(dev, 0, 0x1B7);
|
||||
if (!priv->is_rtl8187b) {
|
||||
rtl8225_write(dev, 0, 0x1B7);
|
||||
|
||||
reg8 = rtl8225_read(dev, 8);
|
||||
reg9 = rtl8225_read(dev, 9);
|
||||
reg8 = rtl8225_read(dev, 8);
|
||||
reg9 = rtl8225_read(dev, 9);
|
||||
|
||||
rtl8225_write(dev, 0, 0x0B7);
|
||||
rtl8225_write(dev, 0, 0x0B7);
|
||||
|
||||
if (reg8 != 0x588 || reg9 != 0x700)
|
||||
return &rtl8225_ops;
|
||||
if (reg8 != 0x588 || reg9 != 0x700)
|
||||
return &rtl8225_ops;
|
||||
|
||||
return &rtl8225z2_ops;
|
||||
return &rtl8225z2_ops;
|
||||
} else
|
||||
return &rtl8225z2_b_ops;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,10 @@ struct rtl818x_csr {
|
|||
#define RTL818X_TX_CONF_R8180_F (3 << 25)
|
||||
#define RTL818X_TX_CONF_R8185_ABC (4 << 25)
|
||||
#define RTL818X_TX_CONF_R8185_D (5 << 25)
|
||||
#define RTL818X_TX_CONF_R8187vD (5 << 25)
|
||||
#define RTL818X_TX_CONF_R8187vD_B (6 << 25)
|
||||
#define RTL818X_TX_CONF_HWVER_MASK (7 << 25)
|
||||
#define RTL818X_TX_CONF_DISREQQSIZE (1 << 28)
|
||||
#define RTL818X_TX_CONF_PROBE_DTS (1 << 29)
|
||||
#define RTL818X_TX_CONF_HW_SEQNUM (1 << 30)
|
||||
#define RTL818X_TX_CONF_CW_MIN (1 << 31)
|
||||
|
@ -106,8 +109,11 @@ struct rtl818x_csr {
|
|||
#define RTL818X_MSR_NO_LINK (0 << 2)
|
||||
#define RTL818X_MSR_ADHOC (1 << 2)
|
||||
#define RTL818X_MSR_INFRA (2 << 2)
|
||||
#define RTL818X_MSR_MASTER (3 << 2)
|
||||
#define RTL818X_MSR_ENEDCA (4 << 2)
|
||||
u8 CONFIG3;
|
||||
#define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6)
|
||||
#define RTL818X_CONFIG3_GNT_SELECT (1 << 7)
|
||||
u8 CONFIG4;
|
||||
#define RTL818X_CONFIG4_POWEROFF (1 << 6)
|
||||
#define RTL818X_CONFIG4_VCOOFF (1 << 7)
|
||||
|
@ -133,7 +139,9 @@ struct rtl818x_csr {
|
|||
__le32 RF_TIMING;
|
||||
u8 GP_ENABLE;
|
||||
u8 GPIO;
|
||||
u8 reserved_12[10];
|
||||
u8 reserved_12[2];
|
||||
__le32 HSSI_PARA;
|
||||
u8 reserved_13[4];
|
||||
u8 TX_AGC_CTL;
|
||||
#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0)
|
||||
#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1)
|
||||
|
@ -141,29 +149,39 @@ struct rtl818x_csr {
|
|||
u8 TX_GAIN_CCK;
|
||||
u8 TX_GAIN_OFDM;
|
||||
u8 TX_ANTENNA;
|
||||
u8 reserved_13[16];
|
||||
u8 reserved_14[16];
|
||||
u8 WPA_CONF;
|
||||
u8 reserved_14[3];
|
||||
u8 reserved_15[3];
|
||||
u8 SIFS;
|
||||
u8 DIFS;
|
||||
u8 SLOT;
|
||||
u8 reserved_15[5];
|
||||
u8 reserved_16[5];
|
||||
u8 CW_CONF;
|
||||
#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0)
|
||||
#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1)
|
||||
u8 CW_VAL;
|
||||
u8 RATE_FALLBACK;
|
||||
u8 reserved_16[25];
|
||||
#define RTL818X_RATE_FALLBACK_ENABLE (1 << 7)
|
||||
u8 ACM_CONTROL;
|
||||
u8 reserved_17[24];
|
||||
u8 CONFIG5;
|
||||
u8 TX_DMA_POLLING;
|
||||
u8 reserved_17[2];
|
||||
u8 reserved_18[2];
|
||||
__le16 CWR;
|
||||
u8 RETRY_CTR;
|
||||
u8 reserved_18[5];
|
||||
u8 reserved_19[3];
|
||||
__le16 INT_MIG;
|
||||
/* RTL818X_R8187B_*: magic numbers from ioregisters */
|
||||
#define RTL818X_R8187B_B 0
|
||||
#define RTL818X_R8187B_D 1
|
||||
#define RTL818X_R8187B_E 2
|
||||
__le32 RDSAR;
|
||||
u8 reserved_19[12];
|
||||
__le16 FEMR;
|
||||
__le16 TID_AC_MAP;
|
||||
u8 reserved_20[4];
|
||||
u8 ANAPARAM3;
|
||||
u8 reserved_21[5];
|
||||
__le16 FEMR;
|
||||
u8 reserved_22[4];
|
||||
__le16 TALLY_CNT;
|
||||
u8 TALLY_SEL;
|
||||
} __attribute__((packed));
|
||||
|
|
|
@ -405,43 +405,66 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
|
|||
/* FIXME: Management frame? */
|
||||
}
|
||||
|
||||
void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
|
||||
static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
|
||||
{
|
||||
struct zd_mac *mac = zd_hw_mac(hw);
|
||||
int r;
|
||||
u32 tmp, j = 0;
|
||||
/* 4 more bytes for tail CRC */
|
||||
u32 full_len = beacon->len + 4;
|
||||
zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0);
|
||||
zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
|
||||
|
||||
r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (tmp & 0x2) {
|
||||
zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
|
||||
r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if ((++j % 100) == 0) {
|
||||
printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n");
|
||||
if (j >= 500) {
|
||||
printk(KERN_ERR "Giving up beacon config.\n");
|
||||
return;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1);
|
||||
if (zd_chip_is_zd1211b(&mac->chip))
|
||||
zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1);
|
||||
r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (zd_chip_is_zd1211b(&mac->chip)) {
|
||||
r = zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
for (j = 0 ; j < beacon->len; j++)
|
||||
zd_iowrite32(&mac->chip, CR_BCN_FIFO,
|
||||
for (j = 0 ; j < beacon->len; j++) {
|
||||
r = zd_iowrite32(&mac->chip, CR_BCN_FIFO,
|
||||
*((u8 *)(beacon->data + j)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0);
|
||||
for (j = 0; j < 4; j++) {
|
||||
r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1);
|
||||
/* 802.11b/g 2.4G CCK 1Mb
|
||||
* 802.11a, not yet implemented, uses different values (see GPL vendor
|
||||
* driver)
|
||||
*/
|
||||
zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 |
|
||||
return zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 |
|
||||
(full_len << 19));
|
||||
}
|
||||
|
||||
|
@ -699,15 +722,20 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct zd_mac *mac = zd_hw_mac(hw);
|
||||
int associated;
|
||||
int r;
|
||||
|
||||
if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
|
||||
mac->type == IEEE80211_IF_TYPE_IBSS) {
|
||||
associated = true;
|
||||
if (conf->beacon) {
|
||||
zd_mac_config_beacon(hw, conf->beacon);
|
||||
kfree_skb(conf->beacon);
|
||||
zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
|
||||
r = zd_mac_config_beacon(hw, conf->beacon);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
|
||||
hw->conf.beacon_int);
|
||||
if (r < 0)
|
||||
return r;
|
||||
kfree_skb(conf->beacon);
|
||||
}
|
||||
} else
|
||||
associated = is_valid_ether_addr(conf->bssid);
|
||||
|
|
|
@ -99,6 +99,8 @@
|
|||
#define IEEE80211_MAX_SSID_LEN 32
|
||||
#define IEEE80211_MAX_MESH_ID_LEN 32
|
||||
#define IEEE80211_QOS_CTL_LEN 2
|
||||
#define IEEE80211_QOS_CTL_TID_MASK 0x000F
|
||||
#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007
|
||||
|
||||
struct ieee80211_hdr {
|
||||
__le16 frame_control;
|
||||
|
@ -658,6 +660,10 @@ struct ieee80211_bar {
|
|||
__le16 start_seq_num;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 802.11 BAR control masks */
|
||||
#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000
|
||||
#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004
|
||||
|
||||
/**
|
||||
* struct ieee80211_ht_cap - HT capabilities
|
||||
*
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
* tasklet function.
|
||||
*
|
||||
* NOTE: If the driver opts to use the _irqsafe() functions, it may not also
|
||||
* use the non-irqsafe functions!
|
||||
* use the non-IRQ-safe functions!
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -85,7 +85,7 @@ enum ieee80211_notification_types {
|
|||
* struct ieee80211_ht_bss_info - describing BSS's HT characteristics
|
||||
*
|
||||
* This structure describes most essential parameters needed
|
||||
* to describe 802.11n HT characteristics in a BSS
|
||||
* to describe 802.11n HT characteristics in a BSS.
|
||||
*
|
||||
* @primary_channel: channel number of primery channel
|
||||
* @bss_cap: 802.11n's general BSS capabilities (e.g. channel width)
|
||||
|
@ -201,9 +201,9 @@ struct ieee80211_bss_conf {
|
|||
};
|
||||
|
||||
/**
|
||||
* enum mac80211_tx_flags - flags to transmission information/status
|
||||
* enum mac80211_tx_control_flags - flags to describe transmission information/status
|
||||
*
|
||||
* These flags are used with the @flags member of &ieee80211_tx_info
|
||||
* These flags are used with the @flags member of &ieee80211_tx_info.
|
||||
*
|
||||
* @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
|
||||
* @IEEE80211_TX_CTL_DO_NOT_ENCRYPT: send this frame without encryption;
|
||||
|
@ -212,11 +212,12 @@ struct ieee80211_bss_conf {
|
|||
* @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
|
||||
* for combined 802.11g / 802.11b networks)
|
||||
* @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack
|
||||
* @IEEE80211_TX_CTL_RATE_CTRL_PROBE
|
||||
* @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD
|
||||
* @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination
|
||||
* station
|
||||
* @IEEE80211_TX_CTL_REQUEUE:
|
||||
* @IEEE80211_TX_CTL_REQUEUE: TBD
|
||||
* @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame
|
||||
* @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD
|
||||
* @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the
|
||||
* through set_retry_limit configured long retry value
|
||||
* @IEEE80211_TX_CTL_EAPOL_FRAME: internal to mac80211
|
||||
|
@ -230,11 +231,14 @@ struct ieee80211_bss_conf {
|
|||
* @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
|
||||
* @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
|
||||
* @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval
|
||||
* @IEEE80211_TX_CTL_INJECTED: TBD
|
||||
* @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted
|
||||
* because the destination STA was in powersave mode.
|
||||
* @IEEE80211_TX_STAT_ACK: Frame was acknowledged
|
||||
* @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status
|
||||
* is for the whole aggregation.
|
||||
* @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
|
||||
* so consider using block ack request (BAR).
|
||||
*/
|
||||
enum mac80211_tx_control_flags {
|
||||
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
|
||||
|
@ -260,6 +264,7 @@ enum mac80211_tx_control_flags {
|
|||
IEEE80211_TX_STAT_TX_FILTERED = BIT(20),
|
||||
IEEE80211_TX_STAT_ACK = BIT(21),
|
||||
IEEE80211_TX_STAT_AMPDU = BIT(22),
|
||||
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(23),
|
||||
};
|
||||
|
||||
|
||||
|
@ -277,6 +282,12 @@ enum mac80211_tx_control_flags {
|
|||
* (3) TX status information - driver tells mac80211 what happened
|
||||
*
|
||||
* @flags: transmit info flags, defined above
|
||||
* @band: TBD
|
||||
* @tx_rate_idx: TBD
|
||||
* @antenna_sel_tx: TBD
|
||||
* @control: union for control data
|
||||
* @status: union for status data
|
||||
* @driver_data: array of driver_data pointers
|
||||
* @retry_count: number of retries
|
||||
* @excessive_retries: set to 1 if the frame was retried many times
|
||||
* but not acknowledged
|
||||
|
@ -559,8 +570,8 @@ enum ieee80211_key_alg {
|
|||
|
||||
/**
|
||||
* enum ieee80211_key_len - key length
|
||||
* @WEP40: WEP 5 byte long key
|
||||
* @WEP104: WEP 13 byte long key
|
||||
* @LEN_WEP40: WEP 5-byte long key
|
||||
* @LEN_WEP104: WEP 13-byte long key
|
||||
*/
|
||||
enum ieee80211_key_len {
|
||||
LEN_WEP40 = 5,
|
||||
|
@ -637,7 +648,7 @@ enum set_key_cmd {
|
|||
* enum sta_notify_cmd - sta notify command
|
||||
*
|
||||
* Used with the sta_notify() callback in &struct ieee80211_ops, this
|
||||
* indicates addition and removal of a station to station table
|
||||
* indicates addition and removal of a station to station table.
|
||||
*
|
||||
* @STA_NOTIFY_ADD: a station was added to the station table
|
||||
* @STA_NOTIFY_REMOVE: a station being removed from the station table
|
||||
|
@ -1337,7 +1348,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw);
|
|||
*
|
||||
* This function frees everything that was allocated, including the
|
||||
* private data for the driver. You must call ieee80211_unregister_hw()
|
||||
* before calling this function
|
||||
* before calling this function.
|
||||
*
|
||||
* @hw: the hardware to free
|
||||
*/
|
||||
|
@ -1408,7 +1419,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw,
|
|||
struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* ieee80211_tx_status_irqsafe - irq-safe transmit status callback
|
||||
* ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback
|
||||
*
|
||||
* Like ieee80211_tx_status() but can be called in IRQ context
|
||||
* (internally defers to a tasklet.)
|
||||
|
@ -1586,6 +1597,8 @@ unsigned int ieee80211_hdrlen(__le16 fc);
|
|||
* @keyconf: the parameter passed with the set key
|
||||
* @skb: the skb for which the key is needed
|
||||
* @rc4key: a buffer to which the key will be written
|
||||
* @type: TBD
|
||||
* @key: TBD
|
||||
*/
|
||||
void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
|
||||
struct sk_buff *skb,
|
||||
|
@ -1636,7 +1649,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
|
|||
void ieee80211_scan_completed(struct ieee80211_hw *hw);
|
||||
|
||||
/**
|
||||
* ieee80211_iterate_active_interfaces- iterate active interfaces
|
||||
* ieee80211_iterate_active_interfaces - iterate active interfaces
|
||||
*
|
||||
* This function iterates over the interfaces associated with a given
|
||||
* hardware that are currently active and calls the callback for them.
|
||||
|
@ -1703,7 +1716,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
|
|||
*
|
||||
* This function must be called by low level driver once it has
|
||||
* finished with preparations for the BA session.
|
||||
* This version of the function is irq safe.
|
||||
* This version of the function is IRQ-safe.
|
||||
*/
|
||||
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
|
||||
u16 tid);
|
||||
|
@ -1743,7 +1756,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
|
|||
*
|
||||
* This function must be called by low level driver once it has
|
||||
* finished with preparations for the BA session tear down.
|
||||
* This version of the function is irq safe.
|
||||
* This version of the function is IRQ-safe.
|
||||
*/
|
||||
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
|
||||
u16 tid);
|
||||
|
@ -1751,7 +1764,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
|
|||
/**
|
||||
* ieee80211_notify_mac - low level driver notification
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @notification_types: enum ieee80211_notification_types
|
||||
* @notif_type: enum ieee80211_notification_types
|
||||
*
|
||||
* This function must be called by low level driver to inform mac80211 of
|
||||
* low level driver status change or force mac80211 to re-assoc for low
|
||||
|
|
|
@ -207,7 +207,6 @@ config MAC80211_LOWTX_FRAME_DUMP
|
|||
|
||||
config MAC80211_DEBUG_COUNTERS
|
||||
bool "Extra statistics for TX/RX debugging"
|
||||
depends on MAC80211_DEBUG
|
||||
depends on MAC80211_DEBUG_MENU
|
||||
depends on MAC80211_DEBUGFS
|
||||
---help---
|
||||
|
@ -219,7 +218,7 @@ config MAC80211_DEBUG_COUNTERS
|
|||
|
||||
config MAC80211_VERBOSE_SPECT_MGMT_DEBUG
|
||||
bool "Verbose Spectrum Management (IEEE 802.11h)debugging"
|
||||
depends on MAC80211_DEBUG
|
||||
depends on MAC80211_DEBUG_MENU
|
||||
---help---
|
||||
Say Y here to print out verbose Spectrum Management (IEEE 802.11h)
|
||||
debug messages.
|
||||
|
|
|
@ -16,31 +16,28 @@
|
|||
#include "key.h"
|
||||
#include "aes_ccm.h"
|
||||
|
||||
|
||||
static void ieee80211_aes_encrypt(struct crypto_cipher *tfm,
|
||||
const u8 pt[16], u8 ct[16])
|
||||
{
|
||||
crypto_cipher_encrypt_one(tfm, ct, pt);
|
||||
}
|
||||
|
||||
|
||||
static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *b, u8 *s_0, u8 *a)
|
||||
static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a)
|
||||
{
|
||||
int i;
|
||||
u8 *b_0, *aad, *b, *s_0;
|
||||
|
||||
ieee80211_aes_encrypt(tfm, b_0, b);
|
||||
b_0 = scratch + 3 * AES_BLOCK_LEN;
|
||||
aad = scratch + 4 * AES_BLOCK_LEN;
|
||||
b = scratch;
|
||||
s_0 = scratch + AES_BLOCK_LEN;
|
||||
|
||||
crypto_cipher_encrypt_one(tfm, b, b_0);
|
||||
|
||||
/* Extra Authenticate-only data (always two AES blocks) */
|
||||
for (i = 0; i < AES_BLOCK_LEN; i++)
|
||||
aad[i] ^= b[i];
|
||||
ieee80211_aes_encrypt(tfm, aad, b);
|
||||
crypto_cipher_encrypt_one(tfm, b, aad);
|
||||
|
||||
aad += AES_BLOCK_LEN;
|
||||
|
||||
for (i = 0; i < AES_BLOCK_LEN; i++)
|
||||
aad[i] ^= b[i];
|
||||
ieee80211_aes_encrypt(tfm, aad, a);
|
||||
crypto_cipher_encrypt_one(tfm, a, aad);
|
||||
|
||||
/* Mask out bits from auth-only-b_0 */
|
||||
b_0[0] &= 0x07;
|
||||
|
@ -48,24 +45,26 @@ static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
|||
/* S_0 is used to encrypt T (= MIC) */
|
||||
b_0[14] = 0;
|
||||
b_0[15] = 0;
|
||||
ieee80211_aes_encrypt(tfm, b_0, s_0);
|
||||
crypto_cipher_encrypt_one(tfm, s_0, b_0);
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *b_0, u8 *aad, u8 *data, size_t data_len,
|
||||
u8 *data, size_t data_len,
|
||||
u8 *cdata, u8 *mic)
|
||||
{
|
||||
int i, j, last_len, num_blocks;
|
||||
u8 *pos, *cpos, *b, *s_0, *e;
|
||||
u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad;
|
||||
|
||||
b = scratch;
|
||||
s_0 = scratch + AES_BLOCK_LEN;
|
||||
e = scratch + 2 * AES_BLOCK_LEN;
|
||||
b_0 = scratch + 3 * AES_BLOCK_LEN;
|
||||
aad = scratch + 4 * AES_BLOCK_LEN;
|
||||
|
||||
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
|
||||
last_len = data_len % AES_BLOCK_LEN;
|
||||
aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
|
||||
aes_ccm_prepare(tfm, scratch, b);
|
||||
|
||||
/* Process payload blocks */
|
||||
pos = data;
|
||||
|
@ -77,11 +76,11 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
|||
/* Authentication followed by encryption */
|
||||
for (i = 0; i < blen; i++)
|
||||
b[i] ^= pos[i];
|
||||
ieee80211_aes_encrypt(tfm, b, b);
|
||||
crypto_cipher_encrypt_one(tfm, b, b);
|
||||
|
||||
b_0[14] = (j >> 8) & 0xff;
|
||||
b_0[15] = j & 0xff;
|
||||
ieee80211_aes_encrypt(tfm, b_0, e);
|
||||
crypto_cipher_encrypt_one(tfm, e, b_0);
|
||||
for (i = 0; i < blen; i++)
|
||||
*cpos++ = *pos++ ^ e[i];
|
||||
}
|
||||
|
@ -92,19 +91,20 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
|||
|
||||
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
|
||||
u8 *mic, u8 *data)
|
||||
u8 *cdata, size_t data_len, u8 *mic, u8 *data)
|
||||
{
|
||||
int i, j, last_len, num_blocks;
|
||||
u8 *pos, *cpos, *b, *s_0, *a;
|
||||
u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad;
|
||||
|
||||
b = scratch;
|
||||
s_0 = scratch + AES_BLOCK_LEN;
|
||||
a = scratch + 2 * AES_BLOCK_LEN;
|
||||
b_0 = scratch + 3 * AES_BLOCK_LEN;
|
||||
aad = scratch + 4 * AES_BLOCK_LEN;
|
||||
|
||||
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
|
||||
last_len = data_len % AES_BLOCK_LEN;
|
||||
aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
|
||||
aes_ccm_prepare(tfm, scratch, a);
|
||||
|
||||
/* Process payload blocks */
|
||||
cpos = cdata;
|
||||
|
@ -116,13 +116,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
|||
/* Decryption followed by authentication */
|
||||
b_0[14] = (j >> 8) & 0xff;
|
||||
b_0[15] = j & 0xff;
|
||||
ieee80211_aes_encrypt(tfm, b_0, b);
|
||||
crypto_cipher_encrypt_one(tfm, b, b_0);
|
||||
for (i = 0; i < blen; i++) {
|
||||
*pos = *cpos++ ^ b[i];
|
||||
a[i] ^= *pos++;
|
||||
}
|
||||
|
||||
ieee80211_aes_encrypt(tfm, a, a);
|
||||
crypto_cipher_encrypt_one(tfm, a, a);
|
||||
}
|
||||
|
||||
for (i = 0; i < CCMP_MIC_LEN; i++) {
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
|
||||
struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]);
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *b_0, u8 *aad, u8 *data, size_t data_len,
|
||||
u8 *data, size_t data_len,
|
||||
u8 *cdata, u8 *mic);
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
|
||||
u8 *cdata, size_t data_len,
|
||||
u8 *mic, u8 *data);
|
||||
void ieee80211_aes_key_free(struct crypto_cipher *tfm);
|
||||
|
||||
|
|
|
@ -893,7 +893,7 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
|
|||
int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
|
||||
void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
u32 changed);
|
||||
void ieee80211_reset_erp_info(struct net_device *dev);
|
||||
u32 ieee80211_reset_erp_info(struct net_device *dev);
|
||||
int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
|
||||
struct ieee80211_ht_info *ht_info);
|
||||
int ieee80211_ht_addt_info_ie_to_ht_bss_info(
|
||||
|
@ -904,6 +904,7 @@ void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
|
|||
u16 agg_size, u16 timeout);
|
||||
void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
|
||||
u16 initiator, u16 reason_code);
|
||||
void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn);
|
||||
|
||||
void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
|
||||
u16 tid, u16 initiator, u16 reason);
|
||||
|
|
|
@ -182,10 +182,11 @@ static int ieee80211_open(struct net_device *dev)
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata, *nsdata;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_if_init_conf conf;
|
||||
u32 changed = 0;
|
||||
int res;
|
||||
bool need_hw_reconfig = 0;
|
||||
struct sta_info *sta;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
|
@ -329,7 +330,8 @@ static int ieee80211_open(struct net_device *dev)
|
|||
goto err_stop;
|
||||
|
||||
ieee80211_if_config(dev);
|
||||
ieee80211_reset_erp_info(dev);
|
||||
changed |= ieee80211_reset_erp_info(dev);
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
ieee80211_enable_keys(sdata);
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
|
||||
|
@ -1190,15 +1192,13 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
|||
changed);
|
||||
}
|
||||
|
||||
void ieee80211_reset_erp_info(struct net_device *dev)
|
||||
u32 ieee80211_reset_erp_info(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
sdata->bss_conf.use_cts_prot = 0;
|
||||
sdata->bss_conf.use_short_preamble = 0;
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
BSS_CHANGED_ERP_CTS_PROT |
|
||||
BSS_CHANGED_ERP_PREAMBLE);
|
||||
return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE;
|
||||
}
|
||||
|
||||
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
|
||||
|
@ -1404,14 +1404,15 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
u16 frag, type;
|
||||
__le16 fc;
|
||||
struct ieee80211_tx_status_rtap_hdr *rthdr;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct net_device *prev_dev = NULL;
|
||||
struct sta_info *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (info->status.excessive_retries) {
|
||||
struct sta_info *sta;
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
if (sta) {
|
||||
if (test_sta_flags(sta, WLAN_STA_PS)) {
|
||||
|
@ -1426,8 +1427,24 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
fc = hdr->frame_control;
|
||||
|
||||
if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
|
||||
(ieee80211_is_data_qos(fc))) {
|
||||
u16 tid, ssn;
|
||||
u8 *qc;
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
if (sta) {
|
||||
qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = qc[0] & 0xf;
|
||||
ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
|
||||
& IEEE80211_SCTL_SEQ);
|
||||
ieee80211_send_bar(sta->sdata->dev, hdr->addr1,
|
||||
tid, ssn);
|
||||
}
|
||||
}
|
||||
|
||||
if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
|
||||
struct sta_info *sta;
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
if (sta) {
|
||||
ieee80211_handle_filtered_frame(local, sta, skb);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "michael.h"
|
||||
|
@ -26,9 +27,18 @@ static void michael_block(struct michael_mic_ctx *mctx, u32 val)
|
|||
mctx->l += mctx->r;
|
||||
}
|
||||
|
||||
static void michael_mic_hdr(struct michael_mic_ctx *mctx,
|
||||
const u8 *key, const u8 *da, const u8 *sa, u8 priority)
|
||||
static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key,
|
||||
struct ieee80211_hdr *hdr)
|
||||
{
|
||||
u8 *da, *sa, tid;
|
||||
|
||||
da = ieee80211_get_DA(hdr);
|
||||
sa = ieee80211_get_SA(hdr);
|
||||
if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
else
|
||||
tid = 0;
|
||||
|
||||
mctx->l = get_unaligned_le32(key);
|
||||
mctx->r = get_unaligned_le32(key + 4);
|
||||
|
||||
|
@ -40,17 +50,17 @@ static void michael_mic_hdr(struct michael_mic_ctx *mctx,
|
|||
michael_block(mctx, get_unaligned_le16(&da[4]) |
|
||||
(get_unaligned_le16(sa) << 16));
|
||||
michael_block(mctx, get_unaligned_le32(&sa[2]));
|
||||
michael_block(mctx, priority);
|
||||
michael_block(mctx, tid);
|
||||
}
|
||||
|
||||
void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority,
|
||||
void michael_mic(const u8 *key, struct ieee80211_hdr *hdr,
|
||||
const u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
u32 val;
|
||||
size_t block, blocks, left;
|
||||
struct michael_mic_ctx mctx;
|
||||
|
||||
michael_mic_hdr(&mctx, key, da, sa, priority);
|
||||
michael_mic_hdr(&mctx, key, hdr);
|
||||
|
||||
/* Real data */
|
||||
blocks = data_len / 4;
|
||||
|
|
|
@ -18,7 +18,7 @@ struct michael_mic_ctx {
|
|||
u32 l, r;
|
||||
};
|
||||
|
||||
void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority,
|
||||
void michael_mic(const u8 *key, struct ieee80211_hdr *hdr,
|
||||
const u8 *data, size_t data_len, u8 *mic);
|
||||
|
||||
#endif /* MICHAEL_H */
|
||||
|
|
|
@ -366,8 +366,10 @@ static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
|
|||
bool use_short_preamble)
|
||||
{
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
#endif
|
||||
u32 changed = 0;
|
||||
|
||||
if (use_protection != bss_conf->use_cts_prot) {
|
||||
|
@ -571,7 +573,7 @@ static void ieee80211_set_associated(struct net_device *dev,
|
|||
ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid);
|
||||
ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
|
||||
netif_carrier_off(dev);
|
||||
ieee80211_reset_erp_info(dev);
|
||||
changed |= ieee80211_reset_erp_info(dev);
|
||||
|
||||
sdata->bss_conf.assoc_ht = 0;
|
||||
sdata->bss_conf.ht_conf = NULL;
|
||||
|
@ -1536,6 +1538,35 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
|
|||
ieee80211_sta_tx(dev, skb, 0);
|
||||
}
|
||||
|
||||
void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_bar *bar;
|
||||
u16 bar_control = 0;
|
||||
|
||||
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", dev->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
|
||||
memset(bar, 0, sizeof(*bar));
|
||||
bar->frame_control = IEEE80211_FC(IEEE80211_FTYPE_CTL,
|
||||
IEEE80211_STYPE_BACK_REQ);
|
||||
memcpy(bar->ra, ra, ETH_ALEN);
|
||||
memcpy(bar->ta, dev->dev_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);
|
||||
bar->control = cpu_to_le16(bar_control);
|
||||
bar->start_seq_num = cpu_to_le16(ssn);
|
||||
|
||||
ieee80211_sta_tx(dev, skb, 0);
|
||||
}
|
||||
|
||||
void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
|
||||
u16 initiator, u16 reason)
|
||||
{
|
||||
|
@ -2481,6 +2512,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
|
|||
control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
|
||||
control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
|
||||
control->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
control->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
|
||||
control->control.retry_limit = 1;
|
||||
|
||||
ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
|
||||
|
|
|
@ -321,20 +321,20 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
|||
|
||||
static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
u8 *data = rx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
int tid;
|
||||
|
||||
/* does the frame have a qos control field? */
|
||||
if (WLAN_FC_IS_QOS_DATA(rx->fc)) {
|
||||
u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
|
||||
if (ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
u8 *qc = ieee80211_get_qos_ctl(hdr);
|
||||
/* frame has qos control */
|
||||
tid = qc[0] & QOS_CONTROL_TID_MASK;
|
||||
if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
|
||||
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
||||
if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
|
||||
rx->flags |= IEEE80211_RX_AMSDU;
|
||||
else
|
||||
rx->flags &= ~IEEE80211_RX_AMSDU;
|
||||
} else {
|
||||
if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
|
||||
if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
|
||||
/* Separate TID for management frames */
|
||||
tid = NUM_RX_DATA_QUEUES - 1;
|
||||
} else {
|
||||
|
@ -352,9 +352,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
|||
static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
int hdrlen;
|
||||
|
||||
if (!WLAN_FC_DATA_PRESENT(rx->fc))
|
||||
if (!ieee80211_is_data_present(hdr->frame_control))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -376,7 +377,7 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx)
|
|||
* header and the payload is not supported, the driver is required
|
||||
* to move the 802.11 header further back in that case.
|
||||
*/
|
||||
hdrlen = ieee80211_get_hdrlen(rx->fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (rx->flags & IEEE80211_RX_AMSDU)
|
||||
hdrlen += ETH_HLEN;
|
||||
WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
|
||||
|
@ -415,14 +416,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
|
|||
static ieee80211_rx_result
|
||||
ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
int hdrlen = ieee80211_get_hdrlen(rx->fc);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
|
||||
|
||||
if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
|
||||
if (!((rx->fc & IEEE80211_FCTL_FROMDS) &&
|
||||
(rx->fc & IEEE80211_FCTL_TODS)))
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
if (!ieee80211_has_a4(hdr->frame_control))
|
||||
return RX_DROP_MONITOR;
|
||||
if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
|
||||
return RX_DROP_MONITOR;
|
||||
|
@ -435,27 +433,30 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
|||
if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) {
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
|
||||
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
|
||||
if (!ieee80211_is_mgmt(hdr->frame_control))
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
switch (rx->fc & IEEE80211_FCTL_STYPE) {
|
||||
case IEEE80211_STYPE_ACTION:
|
||||
if (ieee80211_is_action(hdr->frame_control)) {
|
||||
mgmt = (struct ieee80211_mgmt *)hdr;
|
||||
if (mgmt->u.action.category != PLINK_CATEGORY)
|
||||
return RX_DROP_MONITOR;
|
||||
/* fall through on else */
|
||||
case IEEE80211_STYPE_PROBE_REQ:
|
||||
case IEEE80211_STYPE_PROBE_RESP:
|
||||
case IEEE80211_STYPE_BEACON:
|
||||
return RX_CONTINUE;
|
||||
break;
|
||||
default:
|
||||
return RX_DROP_MONITOR;
|
||||
}
|
||||
|
||||
} else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
|
||||
is_multicast_ether_addr(hdr->addr1) &&
|
||||
mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev))
|
||||
if (ieee80211_is_probe_req(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control) ||
|
||||
ieee80211_is_beacon(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
}
|
||||
|
||||
#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
|
||||
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
is_multicast_ether_addr(hdr->addr1) &&
|
||||
mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev))
|
||||
return RX_DROP_MONITOR;
|
||||
#undef msh_h_get
|
||||
|
||||
|
@ -466,13 +467,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
|||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) rx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
|
||||
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
|
||||
if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
|
||||
if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&
|
||||
if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
|
||||
rx->sta->last_seq_ctrl[rx->queue] ==
|
||||
hdr->seq_ctrl)) {
|
||||
if (rx->flags & IEEE80211_RX_RA_MATCH) {
|
||||
|
@ -501,15 +500,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
|
|||
if (ieee80211_vif_is_mesh(&rx->sdata->vif))
|
||||
return ieee80211_rx_mesh_check(rx);
|
||||
|
||||
if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
|
||||
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
|
||||
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
|
||||
if (unlikely((ieee80211_is_data(hdr->frame_control) ||
|
||||
ieee80211_is_pspoll(hdr->frame_control)) &&
|
||||
rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
|
||||
(!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
|
||||
if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
|
||||
!(rx->fc & IEEE80211_FCTL_TODS) &&
|
||||
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
|
||||
|| !(rx->flags & IEEE80211_RX_RA_MATCH)) {
|
||||
if ((!ieee80211_has_fromds(hdr->frame_control) &&
|
||||
!ieee80211_has_tods(hdr->frame_control) &&
|
||||
ieee80211_is_data(hdr->frame_control)) ||
|
||||
!(rx->flags & IEEE80211_RX_RA_MATCH)) {
|
||||
/* Drop IBSS frames and frames for other hosts
|
||||
* silently. */
|
||||
return RX_DROP_MONITOR;
|
||||
|
@ -525,7 +523,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
|
|||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
int keyidx;
|
||||
int hdrlen;
|
||||
ieee80211_rx_result result = RX_DROP_UNUSABLE;
|
||||
|
@ -557,7 +555,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
* possible.
|
||||
*/
|
||||
|
||||
if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
/*
|
||||
|
@ -586,7 +584,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
(rx->status->flag & RX_FLAG_IV_STRIPPED))
|
||||
return RX_CONTINUE;
|
||||
|
||||
hdrlen = ieee80211_get_hdrlen(rx->fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if (rx->skb->len < 8 + hdrlen)
|
||||
return RX_DROP_UNUSABLE; /* TODO: count this? */
|
||||
|
@ -618,7 +616,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
|
||||
/* Check for weak IVs if possible */
|
||||
if (rx->sta && rx->key->conf.alg == ALG_WEP &&
|
||||
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
|
||||
ieee80211_is_data(hdr->frame_control) &&
|
||||
(!(rx->status->flag & RX_FLAG_IV_STRIPPED) ||
|
||||
!(rx->status->flag & RX_FLAG_DECRYPTED)) &&
|
||||
ieee80211_wep_is_weak_iv(rx->skb, rx->key))
|
||||
|
@ -710,7 +708,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
|||
{
|
||||
struct sta_info *sta = rx->sta;
|
||||
struct net_device *dev = rx->dev;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
|
||||
if (!sta)
|
||||
return RX_CONTINUE;
|
||||
|
@ -744,21 +742,20 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
|||
sta->last_qual = rx->status->qual;
|
||||
sta->last_noise = rx->status->noise;
|
||||
|
||||
if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
|
||||
if (!ieee80211_has_morefrags(hdr->frame_control)) {
|
||||
/* Change STA power saving mode only in the end of a frame
|
||||
* exchange sequence */
|
||||
if (test_sta_flags(sta, WLAN_STA_PS) &&
|
||||
!(rx->fc & IEEE80211_FCTL_PM))
|
||||
!ieee80211_has_pm(hdr->frame_control))
|
||||
rx->sent_ps_buffered += ap_sta_ps_end(dev, sta);
|
||||
else if (!test_sta_flags(sta, WLAN_STA_PS) &&
|
||||
(rx->fc & IEEE80211_FCTL_PM))
|
||||
ieee80211_has_pm(hdr->frame_control))
|
||||
ap_sta_ps_start(dev, sta);
|
||||
}
|
||||
|
||||
/* Drop data::nullfunc frames silently, since they are used only to
|
||||
* control station power saving mode. */
|
||||
if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
|
||||
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) {
|
||||
if (ieee80211_is_nullfunc(hdr->frame_control)) {
|
||||
I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
|
||||
/* Update counter and free packet here to avoid counting this
|
||||
* as a dropped packed. */
|
||||
|
@ -1037,19 +1034,19 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
|
|||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
u16 fc = rx->fc;
|
||||
u8 *data = rx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
|
||||
|
||||
if (!WLAN_FC_IS_QOS_DATA(fc))
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
/* remove the qos control field, update frame type and meta-data */
|
||||
memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
|
||||
hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2);
|
||||
memmove(data + IEEE80211_QOS_CTL_LEN, data,
|
||||
ieee80211_hdrlen(hdr->frame_control) - IEEE80211_QOS_CTL_LEN);
|
||||
hdr = (struct ieee80211_hdr *)skb_pull(rx->skb, IEEE80211_QOS_CTL_LEN);
|
||||
/* change frame type to non QOS */
|
||||
rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
|
||||
hdr->frame_control = cpu_to_le16(fc);
|
||||
rx->fc &= ~IEEE80211_STYPE_QOS_DATA;
|
||||
hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
@ -1465,15 +1462,15 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
|
|||
struct ieee80211_local *local = rx->local;
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data;
|
||||
struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
|
||||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
u16 start_seq_num;
|
||||
u16 tid;
|
||||
|
||||
if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL))
|
||||
if (likely(!ieee80211_is_ctl(bar->frame_control)))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) {
|
||||
if (ieee80211_is_back_req(bar->frame_control)) {
|
||||
if (!rx->sta)
|
||||
return RX_CONTINUE;
|
||||
tid = le16_to_cpu(bar->control) >> 12;
|
||||
|
@ -1527,11 +1524,12 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
|
|||
struct ieee80211_hdr *hdr,
|
||||
struct ieee80211_rx_data *rx)
|
||||
{
|
||||
int keyidx, hdrlen;
|
||||
int keyidx;
|
||||
unsigned int hdrlen;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
DECLARE_MAC_BUF(mac2);
|
||||
|
||||
hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (rx->skb->len >= hdrlen + 4)
|
||||
keyidx = rx->skb->data[hdrlen + 3] >> 6;
|
||||
else
|
||||
|
@ -1545,7 +1543,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
|
|||
goto ignore;
|
||||
}
|
||||
|
||||
if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
goto ignore;
|
||||
|
||||
if (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP && keyidx) {
|
||||
|
@ -1558,9 +1556,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
|
|||
goto ignore;
|
||||
}
|
||||
|
||||
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
|
||||
((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
|
||||
(rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))
|
||||
if (!ieee80211_is_data(hdr->frame_control) &&
|
||||
!ieee80211_is_auth(hdr->frame_control))
|
||||
goto ignore;
|
||||
|
||||
mac80211_ev_michael_mic_failure(rx->dev, keyidx, hdr);
|
||||
|
@ -1731,8 +1728,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|||
case IEEE80211_IF_TYPE_IBSS:
|
||||
if (!bssid)
|
||||
return 0;
|
||||
if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
|
||||
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
|
||||
if (ieee80211_is_beacon(hdr->frame_control)) {
|
||||
if (!rx->sta)
|
||||
rx->sta = ieee80211_ibss_add_sta(sdata->dev,
|
||||
rx->skb, bssid, hdr->addr2,
|
||||
|
@ -1783,8 +1779,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
if (bssid ||
|
||||
(rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
|
||||
if (bssid || !ieee80211_is_data(hdr->frame_control))
|
||||
return 0;
|
||||
if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
|
||||
return 0;
|
||||
|
@ -2044,7 +2039,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
|
|||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
goto end_reorder;
|
||||
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & QOS_CONTROL_TID_MASK;
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
|
||||
goto end_reorder;
|
||||
|
|
|
@ -135,6 +135,7 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
|
|||
/**
|
||||
* __sta_info_free - internal STA free helper
|
||||
*
|
||||
* @local: pointer to the global information
|
||||
* @sta: STA info to free
|
||||
*
|
||||
* This function must undo everything done by sta_info_alloc()
|
||||
|
|
|
@ -160,11 +160,21 @@ struct sta_ampdu_mlme {
|
|||
* @list: global linked list entry
|
||||
* @hnext: hash table linked list pointer
|
||||
* @local: pointer to the global information
|
||||
* @sdata: TBD
|
||||
* @key: TBD
|
||||
* @rate_ctrl: TBD
|
||||
* @rate_ctrl_priv: TBD
|
||||
* @lock: used for locking all fields that require locking, see comments
|
||||
* in the header file.
|
||||
* @flaglock: spinlock for flags accesses
|
||||
* @ht_info: HT capabilities of this STA
|
||||
* @supp_rates: Bitmap of supported rates (per band)
|
||||
* @addr: MAC address of this STA
|
||||
* @aid: STA's unique AID (1..2007, 0 = not assigned yet),
|
||||
* only used in AP (and IBSS?) mode
|
||||
* @listen_interval: TBD
|
||||
* @pin_status: TBD
|
||||
* @flags: STA flags, see &enum ieee80211_sta_info_flags
|
||||
* @flaglock: spinlock for flags accesses
|
||||
* @ps_tx_buf: buffer of frames to transmit to this station
|
||||
* when it leaves power saving state
|
||||
* @tx_filtered: buffer of frames we already tried to transmit
|
||||
|
@ -172,10 +182,41 @@ struct sta_ampdu_mlme {
|
|||
* power saving state
|
||||
* @rx_packets: Number of MSDUs received from this STA
|
||||
* @rx_bytes: Number of bytes received from this STA
|
||||
* @supp_rates: Bitmap of supported rates (per band)
|
||||
* @ht_info: HT capabilities of this STA
|
||||
* @lock: used for locking all fields that require locking, see comments
|
||||
* in the header file.
|
||||
* @wep_weak_iv_count: TBD
|
||||
* @last_rx: TBD
|
||||
* @num_duplicates: number of duplicate frames received from this STA
|
||||
* @rx_fragments: number of received MPDUs
|
||||
* @rx_dropped: number of dropped MPDUs from this STA
|
||||
* @last_signal: signal of last received frame from this STA
|
||||
* @last_qual: qual of last received frame from this STA
|
||||
* @last_noise: noise of last received frame from this STA
|
||||
* @last_seq_ctrl: last received seq/frag number from this STA (per RX queue)
|
||||
* @wme_rx_queue: TBD
|
||||
* @tx_filtered_count: TBD
|
||||
* @tx_retry_failed: TBD
|
||||
* @tx_retry_count: TBD
|
||||
* @tx_num_consecutive_failures: TBD
|
||||
* @tx_num_mpdu_ok: TBD
|
||||
* @tx_num_mpdu_fail: TBD
|
||||
* @fail_avg: moving percentage of failed MSDUs
|
||||
* @tx_packets: number of RX/TX MSDUs
|
||||
* @tx_bytes: TBD
|
||||
* @tx_fragments: number of transmitted MPDUs
|
||||
* @txrate_idx: TBD
|
||||
* @last_txrate_idx: TBD
|
||||
* @wme_tx_queue: TBD
|
||||
* @ampdu_mlme: TBD
|
||||
* @timer_to_tid: identity mapping to ID timers
|
||||
* @tid_to_tx_q: map tid to tx queue
|
||||
* @llid: Local link ID
|
||||
* @plid: Peer link ID
|
||||
* @reason: Cancel reason on PLINK_HOLDING state
|
||||
* @plink_retries: Retries in establishment
|
||||
* @ignore_plink_timer: TBD
|
||||
* @plink_state plink_state: TBD
|
||||
* @plink_timeout: TBD
|
||||
* @plink_timer: TBD
|
||||
* @debugfs: debug filesystem info
|
||||
*/
|
||||
struct sta_info {
|
||||
/* General information, mostly static */
|
||||
|
@ -217,14 +258,12 @@ struct sta_info {
|
|||
unsigned long rx_packets, rx_bytes;
|
||||
unsigned long wep_weak_iv_count;
|
||||
unsigned long last_rx;
|
||||
unsigned long num_duplicates; /* number of duplicate frames received
|
||||
* from this STA */
|
||||
unsigned long rx_fragments; /* number of received MPDUs */
|
||||
unsigned long rx_dropped; /* number of dropped MPDUs from this STA */
|
||||
int last_signal; /* signal of last received frame from this STA */
|
||||
int last_qual; /* qual of last received frame from this STA */
|
||||
int last_noise; /* noise of last received frame from this STA */
|
||||
/* last received seq/frag number from this STA (per RX queue) */
|
||||
unsigned long num_duplicates;
|
||||
unsigned long rx_fragments;
|
||||
unsigned long rx_dropped;
|
||||
int last_signal;
|
||||
int last_qual;
|
||||
int last_noise;
|
||||
__le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
|
||||
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
|
||||
unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
|
||||
|
@ -241,9 +280,9 @@ struct sta_info {
|
|||
unsigned int fail_avg;
|
||||
|
||||
/* Updated from TX path only, no locking requirements */
|
||||
unsigned long tx_packets; /* number of RX/TX MSDUs */
|
||||
unsigned long tx_packets;
|
||||
unsigned long tx_bytes;
|
||||
unsigned long tx_fragments; /* number of transmitted MPDUs */
|
||||
unsigned long tx_fragments;
|
||||
int txrate_idx;
|
||||
int last_txrate_idx;
|
||||
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
|
||||
|
@ -254,18 +293,18 @@ struct sta_info {
|
|||
* Aggregation information, locked with lock.
|
||||
*/
|
||||
struct sta_ampdu_mlme ampdu_mlme;
|
||||
u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */
|
||||
u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */
|
||||
u8 timer_to_tid[STA_TID_NUM];
|
||||
u8 tid_to_tx_q[STA_TID_NUM];
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
/*
|
||||
* Mesh peer link attributes
|
||||
* TODO: move to a sub-structure that is referenced with pointer?
|
||||
*/
|
||||
__le16 llid; /* Local link ID */
|
||||
__le16 plid; /* Peer link ID */
|
||||
__le16 reason; /* Cancel reason on PLINK_HOLDING state */
|
||||
u8 plink_retries; /* Retries in establishment */
|
||||
__le16 llid;
|
||||
__le16 plid;
|
||||
__le16 reason;
|
||||
u8 plink_retries;
|
||||
bool ignore_plink_timer;
|
||||
enum plink_state plink_state;
|
||||
u32 plink_timeout;
|
||||
|
|
|
@ -800,6 +800,8 @@ static int ieee80211_ioctl_siwfrag(struct net_device *dev,
|
|||
|
||||
if (frag->disabled)
|
||||
local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
|
||||
else if (!frag->fixed)
|
||||
local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
|
||||
else if (frag->value < 256 ||
|
||||
frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -154,7 +154,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
|
|||
queue = skb_get_queue_mapping(skb);
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
if (sta) {
|
||||
int ampdu_queue = sta->tid_to_tx_q[tid];
|
||||
if ((ampdu_queue < QD_NUM(hw)) &&
|
||||
|
@ -181,7 +181,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
|
|||
if (ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
u8 *p = ieee80211_get_qos_ctl(hdr);
|
||||
u8 ack_policy = 0;
|
||||
tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
if (local->wifi_wme_noack_test)
|
||||
ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
|
||||
QOS_CONTROL_ACK_POLICY_SHIFT;
|
||||
|
@ -210,7 +210,6 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
|
|||
kfree_skb(skb);
|
||||
err = NET_XMIT_DROP;
|
||||
} else {
|
||||
tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
|
||||
skb_set_queue_mapping(skb, queue);
|
||||
qdisc = q->queues[queue];
|
||||
err = qdisc->enqueue(skb, qdisc);
|
||||
|
|
|
@ -19,18 +19,10 @@
|
|||
#define QOS_CONTROL_ACK_POLICY_NORMAL 0
|
||||
#define QOS_CONTROL_ACK_POLICY_NOACK 1
|
||||
|
||||
#define QOS_CONTROL_TID_MASK 0x0f
|
||||
#define QOS_CONTROL_ACK_POLICY_SHIFT 5
|
||||
|
||||
#define QOS_CONTROL_TAG1D_MASK 0x07
|
||||
|
||||
extern const int ieee802_1d_to_ac[8];
|
||||
|
||||
static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
|
||||
{
|
||||
return (fc & 0x8C) == 0x88;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_QOS
|
||||
void ieee80211_install_qdisc(struct net_device *dev);
|
||||
int ieee80211_qdisc_installed(struct net_device *dev);
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
|
@ -19,53 +21,30 @@
|
|||
#include "aes_ccm.h"
|
||||
#include "wpa.h"
|
||||
|
||||
static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
|
||||
u8 *qos_tid, u8 **data, size_t *data_len)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
size_t hdrlen;
|
||||
__le16 fc;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = hdr->frame_control;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(fc);
|
||||
|
||||
*sa = ieee80211_get_SA(hdr);
|
||||
*da = ieee80211_get_DA(hdr);
|
||||
|
||||
*data = skb->data + hdrlen;
|
||||
*data_len = skb->len - hdrlen;
|
||||
|
||||
if (ieee80211_is_data_qos(fc))
|
||||
*qos_tid = (*ieee80211_get_qos_ctl(hdr) & 0x0f) | 0x80;
|
||||
else
|
||||
*qos_tid = 0;
|
||||
|
||||
return skb->len < hdrlen ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
ieee80211_tx_result
|
||||
ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
u8 *data, *sa, *da, *key, *mic, qos_tid, key_offset;
|
||||
u8 *data, *key, *mic, key_offset;
|
||||
size_t data_len;
|
||||
u16 fc;
|
||||
unsigned int hdrlen;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb = tx->skb;
|
||||
int authenticator;
|
||||
int wpa_test = 0;
|
||||
int tail;
|
||||
|
||||
fc = tx->fc;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
|
||||
!WLAN_FC_DATA_PRESENT(fc))
|
||||
!ieee80211_is_data_present(hdr->frame_control))
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (skb->len < hdrlen)
|
||||
return TX_DROP;
|
||||
|
||||
data = skb->data + hdrlen;
|
||||
data_len = skb->len - hdrlen;
|
||||
|
||||
if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
|
||||
!(tx->flags & IEEE80211_TX_FRAGMENTED) &&
|
||||
!(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) &&
|
||||
|
@ -95,7 +74,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
|
|||
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
|
||||
key = &tx->key->conf.key[key_offset];
|
||||
mic = skb_put(skb, MICHAEL_MIC_LEN);
|
||||
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
|
||||
michael_mic(key, hdr, data, data_len, mic);
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
@ -104,31 +83,33 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
|
|||
ieee80211_rx_result
|
||||
ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
u8 *data, *sa, *da, *key = NULL, qos_tid, key_offset;
|
||||
u8 *data, *key = NULL, key_offset;
|
||||
size_t data_len;
|
||||
u16 fc;
|
||||
unsigned int hdrlen;
|
||||
struct ieee80211_hdr *hdr;
|
||||
u8 mic[MICHAEL_MIC_LEN];
|
||||
struct sk_buff *skb = rx->skb;
|
||||
int authenticator = 1, wpa_test = 0;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
fc = rx->fc;
|
||||
|
||||
/*
|
||||
* No way to verify the MIC if the hardware stripped it
|
||||
*/
|
||||
if (rx->status->flag & RX_FLAG_MMIC_STRIPPED)
|
||||
return RX_CONTINUE;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
|
||||
!(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
|
||||
!ieee80211_has_protected(hdr->frame_control) ||
|
||||
!ieee80211_is_data_present(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
|
||||
|| data_len < MICHAEL_MIC_LEN)
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (skb->len < hdrlen + MICHAEL_MIC_LEN)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
data_len -= MICHAEL_MIC_LEN;
|
||||
data = skb->data + hdrlen;
|
||||
data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
|
||||
|
||||
#if 0
|
||||
authenticator = fc & IEEE80211_FCTL_TODS; /* FIX */
|
||||
|
@ -141,7 +122,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
|||
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
|
||||
NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
|
||||
key = &rx->key->conf.key[key_offset];
|
||||
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
|
||||
michael_mic(key, hdr, data, data_len, mic);
|
||||
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
|
||||
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
@ -253,7 +234,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
|
|||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!rx->sta || skb->len - hdrlen < 12)
|
||||
|
@ -293,70 +274,68 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
|
|||
}
|
||||
|
||||
|
||||
static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
|
||||
static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
|
||||
int encrypted)
|
||||
{
|
||||
u16 fc;
|
||||
int a4_included, qos_included;
|
||||
u8 qos_tid, *fc_pos, *data, *sa, *da;
|
||||
int len_a;
|
||||
size_t data_len;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
__le16 mask_fc;
|
||||
int a4_included;
|
||||
u8 qos_tid;
|
||||
u8 *b_0, *aad;
|
||||
u16 data_len, len_a;
|
||||
unsigned int hdrlen;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
fc_pos = (u8 *) &hdr->frame_control;
|
||||
fc = fc_pos[0] ^ (fc_pos[1] << 8);
|
||||
a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
|
||||
(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
|
||||
b_0 = scratch + 3 * AES_BLOCK_LEN;
|
||||
aad = scratch + 4 * AES_BLOCK_LEN;
|
||||
|
||||
/*
|
||||
* Mask FC: zero subtype b4 b5 b6
|
||||
* Retry, PwrMgt, MoreData; set Protected
|
||||
*/
|
||||
mask_fc = hdr->frame_control;
|
||||
mask_fc &= ~cpu_to_le16(0x0070 | IEEE80211_FCTL_RETRY |
|
||||
IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA);
|
||||
mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
len_a = hdrlen - 2;
|
||||
a4_included = ieee80211_has_a4(hdr->frame_control);
|
||||
|
||||
if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
else
|
||||
qos_tid = 0;
|
||||
|
||||
data_len = skb->len - hdrlen - CCMP_HDR_LEN;
|
||||
if (encrypted)
|
||||
data_len -= CCMP_MIC_LEN;
|
||||
|
||||
ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len);
|
||||
data_len -= CCMP_HDR_LEN + (encrypted ? CCMP_MIC_LEN : 0);
|
||||
if (qos_tid & 0x80) {
|
||||
qos_included = 1;
|
||||
qos_tid &= 0x0f;
|
||||
} else
|
||||
qos_included = 0;
|
||||
/* First block, b_0 */
|
||||
|
||||
b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
|
||||
/* Nonce: QoS Priority | A2 | PN */
|
||||
b_0[1] = qos_tid;
|
||||
memcpy(&b_0[2], hdr->addr2, 6);
|
||||
memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
|
||||
memcpy(&b_0[8], pn, CCMP_PN_LEN);
|
||||
/* l(m) */
|
||||
b_0[14] = (data_len >> 8) & 0xff;
|
||||
b_0[15] = data_len & 0xff;
|
||||
|
||||
put_unaligned_be16(data_len, &b_0[14]);
|
||||
|
||||
/* AAD (extra authenticate-only data) / masked 802.11 header
|
||||
* FC | A1 | A2 | A3 | SC | [A4] | [QC] */
|
||||
|
||||
len_a = a4_included ? 28 : 22;
|
||||
if (qos_included)
|
||||
len_a += 2;
|
||||
|
||||
aad[0] = 0; /* (len_a >> 8) & 0xff; */
|
||||
aad[1] = len_a & 0xff;
|
||||
/* Mask FC: zero subtype b4 b5 b6 */
|
||||
aad[2] = fc_pos[0] & ~(BIT(4) | BIT(5) | BIT(6));
|
||||
/* Retry, PwrMgt, MoreData; set Protected */
|
||||
aad[3] = (fc_pos[1] & ~(BIT(3) | BIT(4) | BIT(5))) | BIT(6);
|
||||
memcpy(&aad[4], &hdr->addr1, 18);
|
||||
put_unaligned_be16(len_a, &aad[0]);
|
||||
put_unaligned(mask_fc, (__le16 *)&aad[2]);
|
||||
memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
|
||||
|
||||
/* Mask Seq#, leave Frag# */
|
||||
aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
|
||||
aad[23] = 0;
|
||||
if (a4_included) {
|
||||
memcpy(&aad[24], hdr->addr4, 6);
|
||||
aad[30] = 0;
|
||||
aad[31] = 0;
|
||||
} else
|
||||
memset(&aad[24], 0, 8);
|
||||
if (qos_included) {
|
||||
u8 *dpos = &aad[a4_included ? 30 : 24];
|
||||
|
||||
/* Mask QoS Control field */
|
||||
dpos[0] = qos_tid;
|
||||
dpos[1] = 0;
|
||||
if (a4_included) {
|
||||
memcpy(&aad[24], hdr->addr4, ETH_ALEN);
|
||||
aad[30] = qos_tid;
|
||||
aad[31] = 0;
|
||||
} else {
|
||||
memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN);
|
||||
aad[24] = qos_tid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,7 +371,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
|||
struct ieee80211_key *key = tx->key;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int hdrlen, len, tail;
|
||||
u8 *pos, *pn, *b_0, *aad, *scratch;
|
||||
u8 *pos, *pn;
|
||||
int i;
|
||||
|
||||
info->control.icv_len = CCMP_MIC_LEN;
|
||||
|
@ -406,10 +385,6 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
scratch = key->u.ccmp.tx_crypto_buf;
|
||||
b_0 = scratch + 3 * AES_BLOCK_LEN;
|
||||
aad = scratch + 4 * AES_BLOCK_LEN;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
len = skb->len - hdrlen;
|
||||
|
||||
|
@ -445,8 +420,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
pos += CCMP_HDR_LEN;
|
||||
ccmp_special_blocks(skb, pn, b_0, aad, 0);
|
||||
ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, b_0, aad, pos, len,
|
||||
ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0);
|
||||
ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, key->u.ccmp.tx_crypto_buf, pos, len,
|
||||
pos, skb_put(skb, CCMP_MIC_LEN));
|
||||
|
||||
return 0;
|
||||
|
@ -478,7 +453,7 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
|
|||
ieee80211_rx_result
|
||||
ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
int hdrlen;
|
||||
struct ieee80211_key *key = rx->key;
|
||||
struct sk_buff *skb = rx->skb;
|
||||
|
@ -488,7 +463,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
|
|||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
|
||||
|
@ -508,16 +483,10 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
|
|||
|
||||
if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
|
||||
/* hardware didn't decrypt/verify MIC */
|
||||
u8 *scratch, *b_0, *aad;
|
||||
|
||||
scratch = key->u.ccmp.rx_crypto_buf;
|
||||
b_0 = scratch + 3 * AES_BLOCK_LEN;
|
||||
aad = scratch + 4 * AES_BLOCK_LEN;
|
||||
|
||||
ccmp_special_blocks(skb, pn, b_0, aad, 1);
|
||||
ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1);
|
||||
|
||||
if (ieee80211_aes_ccm_decrypt(
|
||||
key->u.ccmp.tfm, scratch, b_0, aad,
|
||||
key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf,
|
||||
skb->data + hdrlen + CCMP_HDR_LEN, data_len,
|
||||
skb->data + skb->len - CCMP_MIC_LEN,
|
||||
skb->data + hdrlen + CCMP_HDR_LEN)) {
|
||||
|
|
|
@ -130,17 +130,19 @@ static void update_rfkill_state(struct rfkill *rfkill)
|
|||
|
||||
/**
|
||||
* rfkill_toggle_radio - wrapper for toggle_radio hook
|
||||
* calls toggle_radio taking into account a lot of "small"
|
||||
* details.
|
||||
*
|
||||
* @rfkill: the rfkill struct to use
|
||||
* @force: calls toggle_radio even if cache says it is not needed,
|
||||
* and also makes sure notifications of the state will be
|
||||
* sent even if it didn't change
|
||||
* @state: the new state to call toggle_radio() with
|
||||
*
|
||||
* This wrappen protects and enforces the API for toggle_radio
|
||||
* calls. Note that @force cannot override a (possibly cached)
|
||||
* state of RFKILL_STATE_HARD_BLOCKED. Any device making use of
|
||||
* Calls rfkill->toggle_radio, enforcing the API for toggle_radio
|
||||
* calls and handling all the red tape such as issuing notifications
|
||||
* if the call is successful.
|
||||
*
|
||||
* Note that @force cannot override a (possibly cached) state of
|
||||
* RFKILL_STATE_HARD_BLOCKED. Any device making use of
|
||||
* RFKILL_STATE_HARD_BLOCKED implements either get_state() or
|
||||
* rfkill_force_state(), so the cache either is bypassed or valid.
|
||||
*
|
||||
|
@ -499,17 +501,15 @@ static struct class rfkill_class = {
|
|||
|
||||
static int rfkill_add_switch(struct rfkill *rfkill)
|
||||
{
|
||||
int error;
|
||||
|
||||
mutex_lock(&rfkill_mutex);
|
||||
|
||||
error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0);
|
||||
if (!error)
|
||||
list_add_tail(&rfkill->node, &rfkill_list);
|
||||
rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0);
|
||||
|
||||
list_add_tail(&rfkill->node, &rfkill_list);
|
||||
|
||||
mutex_unlock(&rfkill_mutex);
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rfkill_remove_switch(struct rfkill *rfkill)
|
||||
|
|
|
@ -199,12 +199,14 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
|
||||
mutex_lock(&cfg80211_drv_mutex);
|
||||
list_for_each_entry(dev, &cfg80211_drv_list, list) {
|
||||
if (++idx < start)
|
||||
if (++idx <= start)
|
||||
continue;
|
||||
if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
dev) < 0)
|
||||
dev) < 0) {
|
||||
idx--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&cfg80211_drv_mutex);
|
||||
|
||||
|
|
Loading…
Reference in New Issue