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

This commit is contained in:
David S. Miller 2008-07-08 15:39:41 -07:00
commit 54dceb008f
49 changed files with 1449 additions and 678 deletions

View File

@ -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!

View File

@ -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. "

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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 ""; }

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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);
/*

View File

@ -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 */
/*

View File

@ -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);
}

View File

@ -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.

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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));

View File

@ -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);

View File

@ -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
*

View File

@ -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

View File

@ -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.

View File

@ -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++) {

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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)) {

View File

@ -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)

View File

@ -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);