Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
Коммит
fc943b12e4
|
@ -333,3 +333,13 @@ Why: This option was introduced just to allow older lm-sensors userspace
|
|||
to keep working over the upgrade to 2.6.26. At the scheduled time of
|
||||
removal fixed lm-sensors (2.x or 3.x) should be readily available.
|
||||
Who: Rene Herman <rene.herman@gmail.com>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: Code that is now under CONFIG_WIRELESS_EXT_SYSFS
|
||||
(in net/core/net-sysfs.c)
|
||||
When: After the only user (hal) has seen a release with the patches
|
||||
for enough time, probably some time in 2010.
|
||||
Why: Over 1K .text/.data size reduction, data is available in other
|
||||
ways (ioctls)
|
||||
Who: Johannes Berg <johannes@sipsolutions.net>
|
||||
|
|
|
@ -207,7 +207,6 @@ static struct ieee80211_ops ath5k_hw_ops = {
|
|||
.get_tx_stats = ath5k_get_tx_stats,
|
||||
.get_tsf = ath5k_get_tsf,
|
||||
.reset_tsf = ath5k_reset_tsf,
|
||||
.beacon_update = ath5k_beacon_update,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2785,6 +2784,18 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
* a clean way of letting us retrieve this yet. */
|
||||
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
|
||||
}
|
||||
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON &&
|
||||
vif->type == IEEE80211_IF_TYPE_IBSS) {
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
|
||||
if (!beacon) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
/* call old handler for now */
|
||||
ath5k_beacon_update(hw, beacon);
|
||||
}
|
||||
|
||||
mutex_unlock(&sc->lock);
|
||||
|
||||
return ath5k_reset(hw);
|
||||
|
|
|
@ -1675,14 +1675,24 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
|
|||
|
||||
/* Asynchronously update the packet templates in template RAM.
|
||||
* Locking: Requires wl->irq_lock to be locked. */
|
||||
static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
|
||||
static void b43_update_templates(struct b43_wl *wl)
|
||||
{
|
||||
struct sk_buff *beacon;
|
||||
|
||||
/* This is the top half of the ansynchronous beacon update.
|
||||
* The bottom half is the beacon IRQ.
|
||||
* Beacon update must be asynchronous to avoid sending an
|
||||
* invalid beacon. This can happen for example, if the firmware
|
||||
* transmits a beacon while we are updating it. */
|
||||
|
||||
/* We could modify the existing beacon and set the aid bit in
|
||||
* the TIM field, but that would probably require resizing and
|
||||
* moving of data within the beacon template.
|
||||
* Simply request a new beacon and let mac80211 do the hard work. */
|
||||
beacon = ieee80211_beacon_get(wl->hw, wl->vif);
|
||||
if (unlikely(!beacon))
|
||||
return;
|
||||
|
||||
if (wl->current_beacon)
|
||||
dev_kfree_skb_any(wl->current_beacon);
|
||||
wl->current_beacon = beacon;
|
||||
|
@ -3645,10 +3655,14 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
|
|||
if (b43_status(dev) >= B43_STAT_INITIALIZED) {
|
||||
if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
|
||||
b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
|
||||
B43_WARN_ON(conf->type != wl->if_type);
|
||||
b43_set_ssid(dev, conf->ssid, conf->ssid_len);
|
||||
if (conf->beacon)
|
||||
b43_update_templates(wl, conf->beacon);
|
||||
B43_WARN_ON(vif->type != wl->if_type);
|
||||
if (conf->changed & IEEE80211_IFCC_SSID)
|
||||
b43_set_ssid(dev, conf->ssid, conf->ssid_len);
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON)
|
||||
b43_update_templates(wl);
|
||||
} else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON)
|
||||
b43_update_templates(wl);
|
||||
}
|
||||
b43_write_mac_bssid_templates(dev);
|
||||
}
|
||||
|
@ -4334,33 +4348,12 @@ out_unlock:
|
|||
}
|
||||
|
||||
static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
|
||||
{
|
||||
struct b43_wl *wl = hw_to_b43_wl(hw);
|
||||
struct sk_buff *beacon;
|
||||
unsigned long flags;
|
||||
|
||||
/* We could modify the existing beacon and set the aid bit in
|
||||
* the TIM field, but that would probably require resizing and
|
||||
* moving of data within the beacon template.
|
||||
* Simply request a new beacon and let mac80211 do the hard work. */
|
||||
beacon = ieee80211_beacon_get(hw, wl->vif);
|
||||
if (unlikely(!beacon))
|
||||
return -ENOMEM;
|
||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||
b43_update_templates(wl, beacon);
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
|
||||
struct sk_buff *beacon)
|
||||
{
|
||||
struct b43_wl *wl = hw_to_b43_wl(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||
b43_update_templates(wl, beacon);
|
||||
b43_update_templates(wl);
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -4391,7 +4384,6 @@ static const struct ieee80211_ops b43_hw_ops = {
|
|||
.stop = b43_op_stop,
|
||||
.set_retry_limit = b43_op_set_retry_limit,
|
||||
.set_tim = b43_op_beacon_set_tim,
|
||||
.beacon_update = b43_op_ibss_beacon_update,
|
||||
.sta_notify = b43_op_sta_notify,
|
||||
};
|
||||
|
||||
|
|
|
@ -317,7 +317,8 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
|||
/* MAC control */
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
mac_ctl |= B43_TXH_MAC_ACK;
|
||||
if (!ieee80211_is_pspoll(fctl))
|
||||
/* use hardware sequence counter as the non-TID counter */
|
||||
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
|
||||
mac_ctl |= B43_TXH_MAC_HWSEQ;
|
||||
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
|
||||
mac_ctl |= B43_TXH_MAC_STMSDU;
|
||||
|
|
|
@ -1138,14 +1138,22 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
|
|||
|
||||
/* Asynchronously update the packet templates in template RAM.
|
||||
* Locking: Requires wl->irq_lock to be locked. */
|
||||
static void b43legacy_update_templates(struct b43legacy_wl *wl,
|
||||
struct sk_buff *beacon)
|
||||
static void b43legacy_update_templates(struct b43legacy_wl *wl)
|
||||
{
|
||||
struct sk_buff *beacon;
|
||||
/* This is the top half of the ansynchronous beacon update. The bottom
|
||||
* half is the beacon IRQ. Beacon update must be asynchronous to avoid
|
||||
* sending an invalid beacon. This can happen for example, if the
|
||||
* firmware transmits a beacon while we are updating it. */
|
||||
|
||||
/* We could modify the existing beacon and set the aid bit in the TIM
|
||||
* field, but that would probably require resizing and moving of data
|
||||
* within the beacon template. Simply request a new beacon and let
|
||||
* mac80211 do the hard work. */
|
||||
beacon = ieee80211_beacon_get(wl->hw, wl->vif);
|
||||
if (unlikely(!beacon))
|
||||
return;
|
||||
|
||||
if (wl->current_beacon)
|
||||
dev_kfree_skb_any(wl->current_beacon);
|
||||
wl->current_beacon = beacon;
|
||||
|
@ -2727,10 +2735,13 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
|
|||
memset(wl->bssid, 0, ETH_ALEN);
|
||||
if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
|
||||
if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
|
||||
B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
|
||||
B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP);
|
||||
b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
|
||||
if (conf->beacon)
|
||||
b43legacy_update_templates(wl, conf->beacon);
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON)
|
||||
b43legacy_update_templates(wl);
|
||||
} else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON)
|
||||
b43legacy_update_templates(wl);
|
||||
}
|
||||
b43legacy_write_mac_bssid_templates(dev);
|
||||
}
|
||||
|
@ -3394,33 +3405,12 @@ out_unlock:
|
|||
|
||||
static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
|
||||
int aid, int set)
|
||||
{
|
||||
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
|
||||
struct sk_buff *beacon;
|
||||
unsigned long flags;
|
||||
|
||||
/* We could modify the existing beacon and set the aid bit in the TIM
|
||||
* field, but that would probably require resizing and moving of data
|
||||
* within the beacon template. Simply request a new beacon and let
|
||||
* mac80211 do the hard work. */
|
||||
beacon = ieee80211_beacon_get(hw, wl->vif);
|
||||
if (unlikely(!beacon))
|
||||
return -ENOMEM;
|
||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||
b43legacy_update_templates(wl, beacon);
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
|
||||
struct sk_buff *beacon)
|
||||
{
|
||||
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||
b43legacy_update_templates(wl, beacon);
|
||||
b43legacy_update_templates(wl);
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -3440,7 +3430,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
|
|||
.stop = b43legacy_op_stop,
|
||||
.set_retry_limit = b43legacy_op_set_retry_limit,
|
||||
.set_tim = b43legacy_op_beacon_set_tim,
|
||||
.beacon_update = b43legacy_op_ibss_beacon_update,
|
||||
};
|
||||
|
||||
/* Hard-reset the chip. Do not call this directly.
|
||||
|
|
|
@ -295,8 +295,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
|
|||
/* MAC control */
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
mac_ctl |= B43legacy_TX4_MAC_ACK;
|
||||
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
|
||||
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
|
||||
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
|
||||
mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
|
||||
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
|
||||
mac_ctl |= B43legacy_TX4_MAC_STMSDU;
|
||||
|
|
|
@ -42,14 +42,11 @@
|
|||
#include "iwl-3945.h"
|
||||
#include "iwl-helpers.h"
|
||||
|
||||
#define IWL_1MB_RATE (128 * 1024)
|
||||
#define IWL_LED_THRESHOLD (16)
|
||||
#define IWL_MAX_BLINK_TBL (10)
|
||||
|
||||
static const struct {
|
||||
u16 brightness;
|
||||
u8 on_time;
|
||||
u8 of_time;
|
||||
u8 off_time;
|
||||
} blink_tbl[] =
|
||||
{
|
||||
{300, 25, 25},
|
||||
|
@ -61,9 +58,16 @@ static const struct {
|
|||
{15, 95, 95 },
|
||||
{10, 110, 110},
|
||||
{5, 130, 130},
|
||||
{0, 167, 167}
|
||||
{0, 167, 167},
|
||||
/*SOLID_ON*/
|
||||
{-1, IWL_LED_SOLID, 0}
|
||||
};
|
||||
|
||||
#define IWL_1MB_RATE (128 * 1024)
|
||||
#define IWL_LED_THRESHOLD (16)
|
||||
#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
|
||||
#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
|
||||
|
||||
static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
|
||||
struct iwl3945_cmd *cmd,
|
||||
struct sk_buff *skb)
|
||||
|
@ -71,6 +75,10 @@ static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
|
||||
{
|
||||
return fls(0x000000FF & (u32)brightness);
|
||||
}
|
||||
|
||||
/* Send led command */
|
||||
static int iwl_send_led_cmd(struct iwl3945_priv *priv,
|
||||
|
@ -81,13 +89,33 @@ static int iwl_send_led_cmd(struct iwl3945_priv *priv,
|
|||
.len = sizeof(struct iwl3945_led_cmd),
|
||||
.data = led_cmd,
|
||||
.meta.flags = CMD_ASYNC,
|
||||
.meta.u.callback = iwl3945_led_cmd_callback
|
||||
.meta.u.callback = iwl3945_led_cmd_callback,
|
||||
};
|
||||
|
||||
return iwl3945_send_cmd(priv, &cmd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Set led on command */
|
||||
static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id,
|
||||
unsigned int idx)
|
||||
{
|
||||
struct iwl3945_led_cmd led_cmd = {
|
||||
.id = led_id,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
|
||||
BUG_ON(idx > IWL_MAX_BLINK_TBL);
|
||||
|
||||
led_cmd.on = blink_tbl[idx].on_time;
|
||||
led_cmd.off = blink_tbl[idx].off_time;
|
||||
|
||||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
/* Set led on command */
|
||||
static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id)
|
||||
{
|
||||
|
@ -100,30 +128,6 @@ static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id)
|
|||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
/* Set led on command */
|
||||
static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct iwl3945_led_cmd led_cmd = {
|
||||
.id = led_id,
|
||||
.on = brightness,
|
||||
.off = brightness,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
if (brightness == LED_FULL) {
|
||||
led_cmd.on = IWL_LED_SOLID;
|
||||
led_cmd.off = 0;
|
||||
}
|
||||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
/* Set led register off */
|
||||
static int iwl3945_led_on_reg(struct iwl3945_priv *priv, int led_id)
|
||||
{
|
||||
IWL_DEBUG_LED("led on %d\n", led_id);
|
||||
return iwl3945_led_on(priv, led_id);
|
||||
}
|
||||
|
||||
/* Set led off command */
|
||||
static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id)
|
||||
{
|
||||
|
@ -136,27 +140,7 @@ static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id)
|
|||
IWL_DEBUG_LED("led off %d\n", led_id);
|
||||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
/* Set led register off */
|
||||
static int iwl3945_led_off_reg(struct iwl3945_priv *priv, int led_id)
|
||||
{
|
||||
iwl3945_led_off(priv, led_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set led blink command */
|
||||
static int iwl3945_led_not_solid(struct iwl3945_priv *priv, int led_id,
|
||||
u8 brightness)
|
||||
{
|
||||
struct iwl3945_led_cmd led_cmd = {
|
||||
.id = led_id,
|
||||
.on = brightness,
|
||||
.off = brightness,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
|
||||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
@ -206,8 +190,10 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
|
|||
led->led_off(priv, IWL_LED_LINK);
|
||||
break;
|
||||
default:
|
||||
if (led->led_pattern)
|
||||
led->led_pattern(priv, IWL_LED_LINK, brightness);
|
||||
if (led->led_pattern) {
|
||||
int idx = iwl3945_brightness_to_idx(brightness);
|
||||
led->led_pattern(priv, IWL_LED_LINK, idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -252,24 +238,20 @@ static int iwl3945_led_register_led(struct iwl3945_priv *priv,
|
|||
static inline u8 get_blink_rate(struct iwl3945_priv *priv)
|
||||
{
|
||||
int index;
|
||||
u8 blink_rate;
|
||||
u64 current_tpt = priv->rxtxpackets;
|
||||
s64 tpt = current_tpt - priv->led_tpt;
|
||||
|
||||
if (priv->rxtxpackets < IWL_LED_THRESHOLD)
|
||||
index = 10;
|
||||
else {
|
||||
for (index = 0; index < IWL_MAX_BLINK_TBL; index++) {
|
||||
if (priv->rxtxpackets > (blink_tbl[index].brightness *
|
||||
IWL_1MB_RATE))
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* if 0 frame is transfered */
|
||||
if ((index == IWL_MAX_BLINK_TBL) || !priv->allow_blinking)
|
||||
blink_rate = IWL_LED_SOLID;
|
||||
if (tpt < 0)
|
||||
tpt = -tpt;
|
||||
priv->led_tpt = current_tpt;
|
||||
|
||||
if (!priv->allow_blinking)
|
||||
index = IWL_MAX_BLINK_TBL;
|
||||
else
|
||||
blink_rate = blink_tbl[index].on_time;
|
||||
|
||||
return blink_rate;
|
||||
for (index = 0; index < IWL_MAX_BLINK_TBL; index++)
|
||||
if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE))
|
||||
break;
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline int is_rf_kill(struct iwl3945_priv *priv)
|
||||
|
@ -285,7 +267,7 @@ static inline int is_rf_kill(struct iwl3945_priv *priv)
|
|||
*/
|
||||
void iwl3945_led_background(struct iwl3945_priv *priv)
|
||||
{
|
||||
u8 blink_rate;
|
||||
u8 blink_idx;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
priv->last_blink_time = 0;
|
||||
|
@ -298,9 +280,10 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
|
|||
|
||||
if (!priv->allow_blinking) {
|
||||
priv->last_blink_time = 0;
|
||||
if (priv->last_blink_rate != IWL_LED_SOLID) {
|
||||
priv->last_blink_rate = IWL_LED_SOLID;
|
||||
iwl3945_led_on(priv, IWL_LED_LINK);
|
||||
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
|
||||
priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
|
||||
iwl3945_led_pattern(priv, IWL_LED_LINK,
|
||||
IWL_SOLID_BLINK_IDX);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -309,21 +292,14 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
|
|||
msecs_to_jiffies(1000)))
|
||||
return;
|
||||
|
||||
blink_rate = get_blink_rate(priv);
|
||||
blink_idx = get_blink_rate(priv);
|
||||
|
||||
/* call only if blink rate change */
|
||||
if (blink_rate != priv->last_blink_rate) {
|
||||
if (blink_rate != IWL_LED_SOLID) {
|
||||
priv->last_blink_time = jiffies +
|
||||
msecs_to_jiffies(1000);
|
||||
iwl3945_led_not_solid(priv, IWL_LED_LINK, blink_rate);
|
||||
} else {
|
||||
priv->last_blink_time = 0;
|
||||
iwl3945_led_on(priv, IWL_LED_LINK);
|
||||
}
|
||||
}
|
||||
if (blink_idx != priv->last_blink_rate)
|
||||
iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx);
|
||||
|
||||
priv->last_blink_rate = blink_rate;
|
||||
priv->last_blink_time = jiffies;
|
||||
priv->last_blink_rate = blink_idx;
|
||||
priv->rxtxpackets = 0;
|
||||
}
|
||||
|
||||
|
@ -337,6 +313,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
|
|||
|
||||
priv->last_blink_rate = 0;
|
||||
priv->rxtxpackets = 0;
|
||||
priv->led_tpt = 0;
|
||||
priv->last_blink_time = 0;
|
||||
priv->allow_blinking = 0;
|
||||
|
||||
|
@ -344,8 +321,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
|
|||
snprintf(name, sizeof(name), "iwl-%s:radio",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on_reg;
|
||||
priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off_reg;
|
||||
priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
|
||||
priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off;
|
||||
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
|
||||
|
||||
ret = iwl3945_led_register_led(priv,
|
||||
|
@ -364,8 +341,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
|
|||
IWL_LED_TRG_ASSOC, 0,
|
||||
name, trigger);
|
||||
/* for assoc always turn led on */
|
||||
priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on_reg;
|
||||
priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on_reg;
|
||||
priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on;
|
||||
priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on;
|
||||
priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
|
||||
|
||||
if (ret)
|
||||
|
@ -391,6 +368,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
|
|||
trigger = ieee80211_get_tx_led_name(priv->hw);
|
||||
snprintf(name, sizeof(name), "iwl-%s:TX",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
ret = iwl3945_led_register_led(priv,
|
||||
&priv->led[IWL_LED_TRG_TX],
|
||||
IWL_LED_TRG_TX, 0,
|
||||
|
|
|
@ -54,7 +54,7 @@ struct iwl3945_led {
|
|||
int (*led_on) (struct iwl3945_priv *priv, int led_id);
|
||||
int (*led_off) (struct iwl3945_priv *priv, int led_id);
|
||||
int (*led_pattern) (struct iwl3945_priv *priv, int led_id,
|
||||
enum led_brightness brightness);
|
||||
unsigned int idx);
|
||||
|
||||
enum led_type type;
|
||||
unsigned int registered;
|
||||
|
|
|
@ -514,6 +514,23 @@ static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
|
|||
}
|
||||
#endif
|
||||
|
||||
/* This is necessary only for a number of statistics, see the caller. */
|
||||
static int iwl3945_is_network_packet(struct iwl3945_priv *priv,
|
||||
struct ieee80211_hdr *header)
|
||||
{
|
||||
/* Filter incoming packets to determine if they are targeted toward
|
||||
* this network, discarding packets coming from ourselves */
|
||||
switch (priv->iw_mode) {
|
||||
case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
|
||||
/* packets to our IBSS update information */
|
||||
return !compare_ether_addr(header->addr3, priv->bssid);
|
||||
case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
|
||||
/* packets to our IBSS update information */
|
||||
return !compare_ether_addr(header->addr2, priv->bssid);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
|
||||
struct sk_buff *skb,
|
||||
|
@ -608,12 +625,12 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
|
|||
stats->flag |= RX_FLAG_RADIOTAP;
|
||||
}
|
||||
|
||||
static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
|
||||
static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv,
|
||||
struct iwl3945_rx_mem_buffer *rxb,
|
||||
struct ieee80211_rx_status *stats)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
|
||||
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
|
||||
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
|
||||
short len = le16_to_cpu(rx_hdr->len);
|
||||
|
@ -635,8 +652,6 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
|
|||
/* Set the size of the skb to the size of the frame */
|
||||
skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
|
||||
|
||||
hdr = (void *)rxb->skb->data;
|
||||
|
||||
if (iwl3945_param_hwcrypto)
|
||||
iwl3945_set_decrypted_flag(priv, rxb->skb,
|
||||
le32_to_cpu(rx_end->status), stats);
|
||||
|
@ -645,7 +660,7 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
|
|||
iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);
|
||||
|
||||
#ifdef CONFIG_IWL3945_LEDS
|
||||
if (is_data)
|
||||
if (ieee80211_is_data(hdr->frame_control))
|
||||
priv->rxtxpackets += len;
|
||||
#endif
|
||||
ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
|
||||
|
@ -694,7 +709,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
|
|||
}
|
||||
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
|
||||
iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
|
||||
iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -842,26 +857,11 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
|
|||
}
|
||||
}
|
||||
|
||||
iwl3945_handle_data_packet(priv, 0, rxb, &rx_status);
|
||||
case IEEE80211_FTYPE_DATA:
|
||||
/* fall through */
|
||||
default:
|
||||
iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
|
||||
break;
|
||||
|
||||
case IEEE80211_FTYPE_CTL:
|
||||
break;
|
||||
|
||||
case IEEE80211_FTYPE_DATA: {
|
||||
DECLARE_MAC_BUF(mac1);
|
||||
DECLARE_MAC_BUF(mac2);
|
||||
DECLARE_MAC_BUF(mac3);
|
||||
|
||||
if (unlikely(iwl3945_is_duplicate_packet(priv, header)))
|
||||
IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
|
||||
print_mac(mac1, header->addr1),
|
||||
print_mac(mac2, header->addr2),
|
||||
print_mac(mac3, header->addr3));
|
||||
else
|
||||
iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -510,8 +510,6 @@ struct iwl3945_ucode {
|
|||
u8 data[0]; /* data in same order as "size" elements */
|
||||
};
|
||||
|
||||
#define IWL_IBSS_MAC_HASH_SIZE 32
|
||||
|
||||
struct iwl3945_ibss_seq {
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 seq_num;
|
||||
|
@ -569,17 +567,8 @@ extern int iwl3945_send_add_station(struct iwl3945_priv *priv,
|
|||
struct iwl3945_addsta_cmd *sta, u8 flags);
|
||||
extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid,
|
||||
int is_ap, u8 flags);
|
||||
extern int iwl3945_is_network_packet(struct iwl3945_priv *priv,
|
||||
struct ieee80211_hdr *header);
|
||||
extern int iwl3945_power_init_handle(struct iwl3945_priv *priv);
|
||||
extern int iwl3945_eeprom_init(struct iwl3945_priv *priv);
|
||||
extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv,
|
||||
struct iwl3945_rx_mem_buffer *rxb,
|
||||
void *data, short len,
|
||||
struct ieee80211_rx_status *stats,
|
||||
u16 phy_flags);
|
||||
extern int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv,
|
||||
struct ieee80211_hdr *header);
|
||||
extern int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv);
|
||||
extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv,
|
||||
struct iwl3945_rx_queue *rxq);
|
||||
|
@ -805,6 +794,7 @@ struct iwl3945_priv {
|
|||
u8 last_blink_rate;
|
||||
u8 allow_blinking;
|
||||
unsigned int rxtxpackets;
|
||||
u64 led_tpt;
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -859,14 +849,6 @@ struct iwl3945_priv {
|
|||
u32 last_beacon_time;
|
||||
u64 last_tsf;
|
||||
|
||||
/* Duplicate packet detection */
|
||||
u16 last_seq_num;
|
||||
u16 last_frag_num;
|
||||
unsigned long last_packet_time;
|
||||
|
||||
/* Hash table for finding stations in IBSS network */
|
||||
struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
|
||||
|
||||
/* eeprom */
|
||||
struct iwl3945_eeprom eeprom;
|
||||
|
||||
|
|
|
@ -819,6 +819,7 @@ enum {
|
|||
#define IWL49_NUM_FIFOS 7
|
||||
#define IWL49_CMD_FIFO_NUM 4
|
||||
#define IWL49_NUM_QUEUES 16
|
||||
#define IWL49_NUM_AMPDU_QUEUES 8
|
||||
|
||||
/**
|
||||
* struct iwl_tfd_frame_data
|
||||
|
|
|
@ -2265,9 +2265,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
|
|||
|
||||
/* as default allow aggregation for all tids */
|
||||
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
lq_sta->drv = priv;
|
||||
#endif
|
||||
|
||||
rs_initialize_lq(priv, conf, sta);
|
||||
}
|
||||
|
|
|
@ -49,9 +49,17 @@
|
|||
static int iwl4965_send_tx_power(struct iwl_priv *priv);
|
||||
static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
|
||||
|
||||
/* Change firmware file name, using "-" and incrementing number,
|
||||
* *only* when uCode interface or architecture changes so that it
|
||||
* is not compatible with earlier drivers.
|
||||
* This number will also appear in << 8 position of 1st dword of uCode file */
|
||||
#define IWL4965_UCODE_API "-2"
|
||||
|
||||
|
||||
/* module parameters */
|
||||
static struct iwl_mod_params iwl4965_mod_params = {
|
||||
.num_of_queues = IWL49_NUM_QUEUES,
|
||||
.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
|
||||
.enable_qos = 1,
|
||||
.amsdu_size_8K = 1,
|
||||
.restart_fw = 1,
|
||||
|
@ -642,6 +650,18 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
|
|||
data->beacon_count = 0;
|
||||
}
|
||||
|
||||
static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
|
||||
__le32 *tx_flags)
|
||||
{
|
||||
if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
|
||||
*tx_flags |= TX_CMD_FLG_RTS_MSK;
|
||||
*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
|
||||
} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
||||
*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
|
||||
*tx_flags |= TX_CMD_FLG_CTS_MSK;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl4965_bg_txpower_work(struct work_struct *work)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(work, struct iwl_priv,
|
||||
|
@ -1931,9 +1951,11 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
if (IWL49_FIRST_AMPDU_QUEUE > txq_id) {
|
||||
IWL_WARNING("queue number too small: %d, must be > %d\n",
|
||||
txq_id, IWL49_FIRST_AMPDU_QUEUE);
|
||||
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
|
||||
(IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
|
||||
IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
|
||||
txq_id, IWL49_FIRST_AMPDU_QUEUE,
|
||||
IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2000,9 +2022,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
|
|||
int ret;
|
||||
u16 ra_tid;
|
||||
|
||||
if (IWL49_FIRST_AMPDU_QUEUE > txq_id)
|
||||
IWL_WARNING("queue number too small: %d, must be > %d\n",
|
||||
txq_id, IWL49_FIRST_AMPDU_QUEUE);
|
||||
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
|
||||
(IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
|
||||
IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
|
||||
txq_id, IWL49_FIRST_AMPDU_QUEUE,
|
||||
IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ra_tid = BUILD_RAxTID(sta_id, tid);
|
||||
|
||||
|
@ -2372,6 +2398,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
|
|||
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
|
||||
.chain_noise_reset = iwl4965_chain_noise_reset,
|
||||
.gain_computation = iwl4965_gain_computation,
|
||||
.rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag,
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl4965_lib = {
|
||||
|
@ -2434,6 +2461,9 @@ struct iwl_cfg iwl4965_agn_cfg = {
|
|||
.mod_params = &iwl4965_mod_params,
|
||||
};
|
||||
|
||||
/* Module firmware */
|
||||
MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode");
|
||||
|
||||
module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
|
||||
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
|
||||
module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#define IWL50_QUEUE_SIZE 256
|
||||
#define IWL50_CMD_FIFO_NUM 7
|
||||
#define IWL50_NUM_QUEUES 20
|
||||
#define IWL50_NUM_AMPDU_QUEUES 10
|
||||
#define IWL50_FIRST_AMPDU_QUEUE 10
|
||||
|
||||
#define IWL_sta_id_POS 12
|
||||
|
|
|
@ -370,6 +370,16 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
|
|||
}
|
||||
}
|
||||
|
||||
static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
|
||||
__le32 *tx_flags)
|
||||
{
|
||||
if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
|
||||
(info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
|
||||
*tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
|
||||
else
|
||||
*tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
|
||||
}
|
||||
|
||||
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
|
||||
.min_nrg_cck = 95,
|
||||
.max_nrg_cck = 0,
|
||||
|
@ -1006,9 +1016,13 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
|
|||
int ret;
|
||||
u16 ra_tid;
|
||||
|
||||
if (IWL50_FIRST_AMPDU_QUEUE > txq_id)
|
||||
IWL_WARNING("queue number too small: %d, must be > %d\n",
|
||||
txq_id, IWL50_FIRST_AMPDU_QUEUE);
|
||||
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
|
||||
(IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
|
||||
IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
|
||||
txq_id, IWL50_FIRST_AMPDU_QUEUE,
|
||||
IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ra_tid = BUILD_RAxTID(sta_id, tid);
|
||||
|
||||
|
@ -1067,9 +1081,11 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (IWL50_FIRST_AMPDU_QUEUE > txq_id) {
|
||||
IWL_WARNING("queue number too small: %d, must be > %d\n",
|
||||
txq_id, IWL50_FIRST_AMPDU_QUEUE);
|
||||
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
|
||||
(IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
|
||||
IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
|
||||
txq_id, IWL50_FIRST_AMPDU_QUEUE,
|
||||
IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1437,6 +1453,7 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
|
|||
.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
|
||||
.gain_computation = iwl5000_gain_computation,
|
||||
.chain_noise_reset = iwl5000_chain_noise_reset,
|
||||
.rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl5000_lib = {
|
||||
|
@ -1490,6 +1507,7 @@ static struct iwl_ops iwl5000_ops = {
|
|||
|
||||
static struct iwl_mod_params iwl50_mod_params = {
|
||||
.num_of_queues = IWL50_NUM_QUEUES,
|
||||
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
|
||||
.enable_qos = 1,
|
||||
.amsdu_size_8K = 1,
|
||||
.restart_fw = 1,
|
||||
|
@ -1506,6 +1524,24 @@ struct iwl_cfg iwl5300_agn_cfg = {
|
|||
.mod_params = &iwl50_mod_params,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5100_bg_cfg = {
|
||||
.name = "5100BG",
|
||||
.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
|
||||
.sku = IWL_SKU_G,
|
||||
.ops = &iwl5000_ops,
|
||||
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
||||
.mod_params = &iwl50_mod_params,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5100_abg_cfg = {
|
||||
.name = "5100ABG",
|
||||
.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
|
||||
.sku = IWL_SKU_A|IWL_SKU_G,
|
||||
.ops = &iwl5000_ops,
|
||||
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
||||
.mod_params = &iwl50_mod_params,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5100_agn_cfg = {
|
||||
.name = "5100AGN",
|
||||
.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
|
||||
|
|
|
@ -556,6 +556,8 @@ enum {
|
|||
#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25)
|
||||
#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25)
|
||||
#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25)
|
||||
/* CTS to self (if spec allows) flag */
|
||||
#define RXON_FLG_SELF_CTS_EN __constant_cpu_to_le32(0x1<<30)
|
||||
|
||||
/* rx_config filter flags */
|
||||
/* accept all data frames */
|
||||
|
@ -723,7 +725,7 @@ struct iwl4965_csa_notification {
|
|||
* transmission retry. Device uses cw_max as a bit mask, ANDed with new CW
|
||||
* value, to cap the CW value.
|
||||
*/
|
||||
struct iwl4965_ac_qos {
|
||||
struct iwl_ac_qos {
|
||||
__le16 cw_min;
|
||||
__le16 cw_max;
|
||||
u8 aifsn;
|
||||
|
@ -745,9 +747,9 @@ struct iwl4965_ac_qos {
|
|||
* This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
|
||||
* 0: Background, 1: Best Effort, 2: Video, 3: Voice.
|
||||
*/
|
||||
struct iwl4965_qosparam_cmd {
|
||||
struct iwl_qosparam_cmd {
|
||||
__le32 qos_flags;
|
||||
struct iwl4965_ac_qos ac[AC_NUM];
|
||||
struct iwl_ac_qos ac[AC_NUM];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -1139,6 +1141,11 @@ struct iwl4965_rx_mpdu_res_start {
|
|||
|
||||
/* REPLY_TX Tx flags field */
|
||||
|
||||
/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it
|
||||
* before this frame. if CTS-to-self required check
|
||||
* RXON_FLG_SELF_CTS_EN status. */
|
||||
#define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0)
|
||||
|
||||
/* 1: Use Request-To-Send protocol before this frame.
|
||||
* Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
|
||||
#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
|
||||
|
@ -2092,6 +2099,9 @@ struct iwl_ct_kill_config {
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0)
|
||||
#define SCAN_CHANNEL_TYPE_ACTIVE __constant_cpu_to_le32(1)
|
||||
|
||||
/**
|
||||
* struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
|
||||
*
|
||||
|
@ -2115,12 +2125,12 @@ struct iwl_scan_channel {
|
|||
/*
|
||||
* type is defined as:
|
||||
* 0:0 1 = active, 0 = passive
|
||||
* 1:4 SSID direct bit map; if a bit is set, then corresponding
|
||||
* 1:20 SSID direct bit map; if a bit is set, then corresponding
|
||||
* SSID IE is transmitted in probe request.
|
||||
* 5:7 reserved
|
||||
* 21:31 reserved
|
||||
*/
|
||||
u8 type;
|
||||
u8 channel; /* band is selected by iwl4965_scan_cmd "flags" field */
|
||||
__le32 type;
|
||||
__le16 channel; /* band is selected by iwl_scan_cmd "flags" field */
|
||||
u8 tx_gain; /* gain for analog radio */
|
||||
u8 dsp_atten; /* gain for DSP */
|
||||
__le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */
|
||||
|
@ -2140,9 +2150,9 @@ struct iwl_ssid_ie {
|
|||
u8 ssid[32];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define PROBE_OPTION_MAX 0x4
|
||||
#define PROBE_OPTION_MAX 0x14
|
||||
#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF)
|
||||
#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1)
|
||||
#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1)
|
||||
#define IWL_MAX_SCAN_SIZE 1024
|
||||
|
||||
/*
|
||||
|
@ -2919,7 +2929,7 @@ struct iwl5000_calibration_chain_noise_gain_cmd {
|
|||
* For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
|
||||
* this command turns it on or off, or sets up a periodic blinking cycle.
|
||||
*/
|
||||
struct iwl4965_led_cmd {
|
||||
struct iwl_led_cmd {
|
||||
__le32 interval; /* "interval" in uSec */
|
||||
u8 id; /* 1: Activity, 2: Link, 3: Tech */
|
||||
u8 off; /* # intervals off while blinking;
|
||||
|
|
|
@ -825,7 +825,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
|
|||
hw->queues = 4;
|
||||
/* queues to support 11n aggregation */
|
||||
if (priv->cfg->sku & IWL_SKU_N)
|
||||
hw->ampdu_queues = 12;
|
||||
hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues;
|
||||
|
||||
hw->conf.beacon_int = 100;
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ struct iwl_host_cmd;
|
|||
struct iwl_cmd;
|
||||
|
||||
|
||||
#define IWLWIFI_VERSION "1.2.26k"
|
||||
#define IWLWIFI_VERSION "1.3.27k"
|
||||
#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation"
|
||||
|
||||
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
|
||||
|
@ -93,6 +93,8 @@ struct iwl_hcmd_utils_ops {
|
|||
u16 min_average_noise_antennat_i,
|
||||
u32 min_average_noise);
|
||||
void (*chain_noise_reset)(struct iwl_priv *priv);
|
||||
void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
|
||||
__le32 *tx_flags);
|
||||
};
|
||||
|
||||
struct iwl_lib_ops {
|
||||
|
@ -157,6 +159,7 @@ struct iwl_mod_params {
|
|||
int debug; /* def: 0 = minimal debug log messages */
|
||||
int disable_hw_scan; /* def: 0 = use h/w scan */
|
||||
int num_of_queues; /* def: HW dependent */
|
||||
int num_of_ampdu_queues;/* def: HW dependent */
|
||||
int enable_qos; /* def: 1 = use quality of service */
|
||||
int disable_11n; /* def: 0 = disable 11n capabilities */
|
||||
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
|
||||
|
|
|
@ -51,12 +51,8 @@ extern struct iwl_cfg iwl4965_agn_cfg;
|
|||
extern struct iwl_cfg iwl5300_agn_cfg;
|
||||
extern struct iwl_cfg iwl5100_agn_cfg;
|
||||
extern struct iwl_cfg iwl5350_agn_cfg;
|
||||
|
||||
/* Change firmware file name, using "-" and incrementing number,
|
||||
* *only* when uCode interface or architecture changes so that it
|
||||
* is not compatible with earlier drivers.
|
||||
* This number will also appear in << 8 position of 1st dword of uCode file */
|
||||
#define IWL4965_UCODE_API "-1"
|
||||
extern struct iwl_cfg iwl5100_bg_cfg;
|
||||
extern struct iwl_cfg iwl5100_abg_cfg;
|
||||
|
||||
/* CT-KILL constants */
|
||||
#define CT_KILL_THRESHOLD 110 /* in Celsius */
|
||||
|
@ -280,7 +276,7 @@ struct iwl_cmd {
|
|||
struct iwl_cmd_header hdr; /* uCode API */
|
||||
union {
|
||||
struct iwl_addsta_cmd addsta;
|
||||
struct iwl4965_led_cmd led;
|
||||
struct iwl_led_cmd led;
|
||||
u32 flags;
|
||||
u8 val8;
|
||||
u16 val16;
|
||||
|
@ -288,7 +284,7 @@ struct iwl_cmd {
|
|||
struct iwl4965_bt_cmd bt;
|
||||
struct iwl4965_rxon_time_cmd rxon_time;
|
||||
struct iwl4965_powertable_cmd powertable;
|
||||
struct iwl4965_qosparam_cmd qosparam;
|
||||
struct iwl_qosparam_cmd qosparam;
|
||||
struct iwl_tx_cmd tx;
|
||||
struct iwl4965_tx_beacon_cmd tx_beacon;
|
||||
struct iwl4965_rxon_assoc_cmd rxon_assoc;
|
||||
|
@ -433,7 +429,7 @@ struct iwl_ht_info {
|
|||
u8 non_GF_STA_present;
|
||||
};
|
||||
|
||||
union iwl4965_qos_capabity {
|
||||
union iwl_qos_capabity {
|
||||
struct {
|
||||
u8 edca_count:4; /* bit 0-3 */
|
||||
u8 q_ack:1; /* bit 4 */
|
||||
|
@ -454,11 +450,11 @@ union iwl4965_qos_capabity {
|
|||
};
|
||||
|
||||
/* QoS structures */
|
||||
struct iwl4965_qos_info {
|
||||
struct iwl_qos_info {
|
||||
int qos_enable;
|
||||
int qos_active;
|
||||
union iwl4965_qos_capabity qos_cap;
|
||||
struct iwl4965_qosparam_cmd def_qos_parm;
|
||||
union iwl_qos_capabity qos_cap;
|
||||
struct iwl_qosparam_cmd def_qos_parm;
|
||||
};
|
||||
|
||||
#define STA_PS_STATUS_WAKE 0
|
||||
|
@ -490,8 +486,6 @@ struct iwl_ucode {
|
|||
u8 data[0]; /* data in same order as "size" elements */
|
||||
};
|
||||
|
||||
#define IWL_IBSS_MAC_HASH_SIZE 32
|
||||
|
||||
struct iwl4965_ibss_seq {
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 seq_num;
|
||||
|
@ -933,7 +927,7 @@ struct iwl_priv {
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
struct iwl4965_led led[IWL_LED_TRG_MAX];
|
||||
struct iwl_led led[IWL_LED_TRG_MAX];
|
||||
unsigned long last_blink_time;
|
||||
u8 last_blink_rate;
|
||||
u8 allow_blinking;
|
||||
|
@ -1042,7 +1036,7 @@ struct iwl_priv {
|
|||
u16 assoc_capability;
|
||||
u8 ps_mode;
|
||||
|
||||
struct iwl4965_qos_info qos_data;
|
||||
struct iwl_qos_info qos_data;
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
|
||||
|
@ -1065,7 +1059,6 @@ struct iwl_priv {
|
|||
struct delayed_work init_alive_start;
|
||||
struct delayed_work alive_start;
|
||||
struct delayed_work scan_check;
|
||||
struct delayed_work post_associate;
|
||||
/* TX Power */
|
||||
s8 tx_power_user_lmt;
|
||||
s8 tx_power_channel_lmt;
|
||||
|
|
|
@ -44,14 +44,21 @@
|
|||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
|
||||
#define IWL_1MB_RATE (128 * 1024)
|
||||
#define IWL_LED_THRESHOLD (16)
|
||||
#define IWL_MAX_BLINK_TBL (10)
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
static const char *led_type_str[] = {
|
||||
__stringify(IWL_LED_TRG_TX),
|
||||
__stringify(IWL_LED_TRG_RX),
|
||||
__stringify(IWL_LED_TRG_ASSOC),
|
||||
__stringify(IWL_LED_TRG_RADIO),
|
||||
NULL
|
||||
};
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
||||
|
||||
static const struct {
|
||||
u16 tpt;
|
||||
u8 on_time;
|
||||
u8 of_time;
|
||||
u8 off_time;
|
||||
} blink_tbl[] =
|
||||
{
|
||||
{300, 25, 25},
|
||||
|
@ -63,26 +70,31 @@ static const struct {
|
|||
{15, 95, 95 },
|
||||
{10, 110, 110},
|
||||
{5, 130, 130},
|
||||
{0, 167, 167}
|
||||
{0, 167, 167},
|
||||
/* SOLID_ON */
|
||||
{-1, IWL_LED_SOLID, 0}
|
||||
};
|
||||
|
||||
static int iwl_led_cmd_callback(struct iwl_priv *priv,
|
||||
struct iwl_cmd *cmd, struct sk_buff *skb)
|
||||
#define IWL_1MB_RATE (128 * 1024)
|
||||
#define IWL_LED_THRESHOLD (16)
|
||||
#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */
|
||||
#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
|
||||
|
||||
/* [0-256] -> [0..8] FIXME: we need [0..10] */
|
||||
static inline int iwl_brightness_to_idx(enum led_brightness brightness)
|
||||
{
|
||||
return 1;
|
||||
return fls(0x000000FF & (u32)brightness);
|
||||
}
|
||||
|
||||
|
||||
/* Send led command */
|
||||
static int iwl_send_led_cmd(struct iwl_priv *priv,
|
||||
struct iwl4965_led_cmd *led_cmd)
|
||||
static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_LEDS_CMD,
|
||||
.len = sizeof(struct iwl4965_led_cmd),
|
||||
.len = sizeof(struct iwl_led_cmd),
|
||||
.data = led_cmd,
|
||||
.meta.flags = CMD_ASYNC,
|
||||
.meta.u.callback = iwl_led_cmd_callback
|
||||
.meta.u.callback = NULL,
|
||||
};
|
||||
u32 reg;
|
||||
|
||||
|
@ -93,33 +105,20 @@ static int iwl_send_led_cmd(struct iwl_priv *priv,
|
|||
return iwl_send_cmd(priv, &cmd);
|
||||
}
|
||||
|
||||
|
||||
/* Set led on command */
|
||||
static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
|
||||
{
|
||||
struct iwl4965_led_cmd led_cmd = {
|
||||
.id = led_id,
|
||||
.on = IWL_LED_SOLID,
|
||||
.off = 0,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
/* Set led on command */
|
||||
/* Set led pattern command */
|
||||
static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
|
||||
enum led_brightness brightness)
|
||||
unsigned int idx)
|
||||
{
|
||||
struct iwl4965_led_cmd led_cmd = {
|
||||
struct iwl_led_cmd led_cmd = {
|
||||
.id = led_id,
|
||||
.on = brightness,
|
||||
.off = brightness,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
if (brightness == LED_FULL) {
|
||||
led_cmd.on = IWL_LED_SOLID;
|
||||
led_cmd.off = 0;
|
||||
}
|
||||
|
||||
BUG_ON(idx > IWL_MAX_BLINK_TBL);
|
||||
|
||||
led_cmd.on = blink_tbl[idx].on_time;
|
||||
led_cmd.off = blink_tbl[idx].off_time;
|
||||
|
||||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
|
@ -132,10 +131,22 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
|
|||
}
|
||||
|
||||
#if 0
|
||||
/* Set led on command */
|
||||
static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
|
||||
{
|
||||
struct iwl_led_cmd led_cmd = {
|
||||
.id = led_id,
|
||||
.on = IWL_LED_SOLID,
|
||||
.off = 0,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
/* Set led off command */
|
||||
int iwl4965_led_off(struct iwl_priv *priv, int led_id)
|
||||
{
|
||||
struct iwl4965_led_cmd led_cmd = {
|
||||
struct iwl_led_cmd led_cmd = {
|
||||
.id = led_id,
|
||||
.on = 0,
|
||||
.off = 0,
|
||||
|
@ -155,25 +166,10 @@ static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Set led blink command */
|
||||
static int iwl4965_led_not_solid(struct iwl_priv *priv, int led_id,
|
||||
u8 brightness)
|
||||
{
|
||||
struct iwl4965_led_cmd led_cmd = {
|
||||
.id = led_id,
|
||||
.on = brightness,
|
||||
.off = brightness,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
|
||||
return iwl_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* brightness call back function for Tx/Rx LED
|
||||
*/
|
||||
static int iwl4965_led_associated(struct iwl_priv *priv, int led_id)
|
||||
static int iwl_led_associated(struct iwl_priv *priv, int led_id)
|
||||
{
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
|
||||
!test_bit(STATUS_READY, &priv->status))
|
||||
|
@ -189,16 +185,18 @@ static int iwl4965_led_associated(struct iwl_priv *priv, int led_id)
|
|||
/*
|
||||
* brightness call back for association and radio
|
||||
*/
|
||||
static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
|
||||
static void iwl_led_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct iwl4965_led *led = container_of(led_cdev,
|
||||
struct iwl4965_led, led_dev);
|
||||
struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev);
|
||||
struct iwl_priv *priv = led->priv;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
|
||||
IWL_DEBUG_LED("Led type = %s brightness = %d\n",
|
||||
led_type_str[led->type], brightness);
|
||||
switch (brightness) {
|
||||
case LED_FULL:
|
||||
if (led->type == IWL_LED_TRG_ASSOC)
|
||||
|
@ -215,8 +213,10 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
|
|||
led->led_off(priv, IWL_LED_LINK);
|
||||
break;
|
||||
default:
|
||||
if (led->led_pattern)
|
||||
led->led_pattern(priv, IWL_LED_LINK, brightness);
|
||||
if (led->led_pattern) {
|
||||
int idx = iwl_brightness_to_idx(brightness);
|
||||
led->led_pattern(priv, IWL_LED_LINK, idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -226,8 +226,7 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
|
|||
/*
|
||||
* Register led class with the system
|
||||
*/
|
||||
static int iwl_leds_register_led(struct iwl_priv *priv,
|
||||
struct iwl4965_led *led,
|
||||
static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
|
||||
enum led_type type, u8 set_led,
|
||||
const char *name, char *trigger)
|
||||
{
|
||||
|
@ -235,7 +234,7 @@ static int iwl_leds_register_led(struct iwl_priv *priv,
|
|||
int ret;
|
||||
|
||||
led->led_dev.name = name;
|
||||
led->led_dev.brightness_set = iwl4965_led_brightness_set;
|
||||
led->led_dev.brightness_set = iwl_led_brightness_set;
|
||||
led->led_dev.default_trigger = trigger;
|
||||
|
||||
led->priv = priv;
|
||||
|
@ -259,32 +258,28 @@ static int iwl_leds_register_led(struct iwl_priv *priv,
|
|||
/*
|
||||
* calculate blink rate according to last 2 sec Tx/Rx activities
|
||||
*/
|
||||
static inline u8 get_blink_rate(struct iwl_priv *priv)
|
||||
static int iwl_get_blink_rate(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
u8 blink_rate;
|
||||
u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
|
||||
u64 current_tpt = priv->tx_stats[2].bytes;
|
||||
/* FIXME: + priv->rx_stats[2].bytes; */
|
||||
s64 tpt = current_tpt - priv->led_tpt;
|
||||
|
||||
if (tpt < 0) /* wrapparound */
|
||||
tpt = -tpt;
|
||||
|
||||
IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt);
|
||||
priv->led_tpt = current_tpt;
|
||||
|
||||
if (tpt < IWL_LED_THRESHOLD) {
|
||||
if (!priv->allow_blinking)
|
||||
i = IWL_MAX_BLINK_TBL;
|
||||
} else {
|
||||
else
|
||||
for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
|
||||
if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
|
||||
break;
|
||||
}
|
||||
/* if 0 frame is transfered */
|
||||
if ((i == IWL_MAX_BLINK_TBL) || !priv->allow_blinking)
|
||||
blink_rate = IWL_LED_SOLID;
|
||||
else
|
||||
blink_rate = blink_tbl[i].on_time;
|
||||
|
||||
return blink_rate;
|
||||
IWL_DEBUG_LED("LED BLINK IDX=%d", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline int is_rf_kill(struct iwl_priv *priv)
|
||||
|
@ -300,7 +295,7 @@ static inline int is_rf_kill(struct iwl_priv *priv)
|
|||
*/
|
||||
void iwl_leds_background(struct iwl_priv *priv)
|
||||
{
|
||||
u8 blink_rate;
|
||||
u8 blink_idx;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
priv->last_blink_time = 0;
|
||||
|
@ -313,9 +308,10 @@ void iwl_leds_background(struct iwl_priv *priv)
|
|||
|
||||
if (!priv->allow_blinking) {
|
||||
priv->last_blink_time = 0;
|
||||
if (priv->last_blink_rate != IWL_LED_SOLID) {
|
||||
priv->last_blink_rate = IWL_LED_SOLID;
|
||||
iwl4965_led_on(priv, IWL_LED_LINK);
|
||||
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
|
||||
priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
|
||||
iwl4965_led_pattern(priv, IWL_LED_LINK,
|
||||
IWL_SOLID_BLINK_IDX);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -324,21 +320,14 @@ void iwl_leds_background(struct iwl_priv *priv)
|
|||
msecs_to_jiffies(1000)))
|
||||
return;
|
||||
|
||||
blink_rate = get_blink_rate(priv);
|
||||
blink_idx = iwl_get_blink_rate(priv);
|
||||
|
||||
/* call only if blink rate change */
|
||||
if (blink_rate != priv->last_blink_rate) {
|
||||
if (blink_rate != IWL_LED_SOLID) {
|
||||
priv->last_blink_time = jiffies +
|
||||
msecs_to_jiffies(1000);
|
||||
iwl4965_led_not_solid(priv, IWL_LED_LINK, blink_rate);
|
||||
} else {
|
||||
priv->last_blink_time = 0;
|
||||
iwl4965_led_on(priv, IWL_LED_LINK);
|
||||
}
|
||||
}
|
||||
if (blink_idx != priv->last_blink_rate)
|
||||
iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx);
|
||||
|
||||
priv->last_blink_rate = blink_rate;
|
||||
priv->last_blink_time = jiffies;
|
||||
priv->last_blink_rate = blink_idx;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_leds_background);
|
||||
|
||||
|
@ -362,10 +351,8 @@ int iwl_leds_register(struct iwl_priv *priv)
|
|||
priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
|
||||
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
|
||||
|
||||
ret = iwl_leds_register_led(priv,
|
||||
&priv->led[IWL_LED_TRG_RADIO],
|
||||
IWL_LED_TRG_RADIO, 1,
|
||||
name, trigger);
|
||||
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
|
||||
IWL_LED_TRG_RADIO, 1, name, trigger);
|
||||
if (ret)
|
||||
goto exit_fail;
|
||||
|
||||
|
@ -373,10 +360,9 @@ int iwl_leds_register(struct iwl_priv *priv)
|
|||
snprintf(name, sizeof(name), "iwl-%s:assoc",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
ret = iwl_leds_register_led(priv,
|
||||
&priv->led[IWL_LED_TRG_ASSOC],
|
||||
IWL_LED_TRG_ASSOC, 0,
|
||||
name, trigger);
|
||||
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC],
|
||||
IWL_LED_TRG_ASSOC, 0, name, trigger);
|
||||
|
||||
/* for assoc always turn led on */
|
||||
priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg;
|
||||
priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg;
|
||||
|
@ -386,31 +372,26 @@ int iwl_leds_register(struct iwl_priv *priv)
|
|||
goto exit_fail;
|
||||
|
||||
trigger = ieee80211_get_rx_led_name(priv->hw);
|
||||
snprintf(name, sizeof(name), "iwl-%s:RX",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
snprintf(name, sizeof(name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy));
|
||||
|
||||
|
||||
ret = iwl_leds_register_led(priv,
|
||||
&priv->led[IWL_LED_TRG_RX],
|
||||
IWL_LED_TRG_RX, 0,
|
||||
name, trigger);
|
||||
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX],
|
||||
IWL_LED_TRG_RX, 0, name, trigger);
|
||||
|
||||
priv->led[IWL_LED_TRG_RX].led_on = iwl4965_led_associated;
|
||||
priv->led[IWL_LED_TRG_RX].led_off = iwl4965_led_associated;
|
||||
priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
|
||||
priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
|
||||
priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
|
||||
|
||||
if (ret)
|
||||
goto exit_fail;
|
||||
|
||||
trigger = ieee80211_get_tx_led_name(priv->hw);
|
||||
snprintf(name, sizeof(name), "iwl-%s:TX",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
ret = iwl_leds_register_led(priv,
|
||||
&priv->led[IWL_LED_TRG_TX],
|
||||
IWL_LED_TRG_TX, 0,
|
||||
name, trigger);
|
||||
priv->led[IWL_LED_TRG_TX].led_on = iwl4965_led_associated;
|
||||
priv->led[IWL_LED_TRG_TX].led_off = iwl4965_led_associated;
|
||||
snprintf(name, sizeof(name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy));
|
||||
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX],
|
||||
IWL_LED_TRG_TX, 0, name, trigger);
|
||||
|
||||
priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
|
||||
priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
|
||||
priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
|
||||
|
||||
if (ret)
|
||||
|
@ -425,7 +406,7 @@ exit_fail:
|
|||
EXPORT_SYMBOL(iwl_leds_register);
|
||||
|
||||
/* unregister led class */
|
||||
static void iwl_leds_unregister_led(struct iwl4965_led *led, u8 set_led)
|
||||
static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led)
|
||||
{
|
||||
if (!led->registered)
|
||||
return;
|
||||
|
|
|
@ -49,14 +49,13 @@ enum led_type {
|
|||
};
|
||||
|
||||
|
||||
struct iwl4965_led {
|
||||
struct iwl_led {
|
||||
struct iwl_priv *priv;
|
||||
struct led_classdev led_dev;
|
||||
|
||||
int (*led_on) (struct iwl_priv *priv, int led_id);
|
||||
int (*led_off) (struct iwl_priv *priv, int led_id);
|
||||
int (*led_pattern) (struct iwl_priv *priv, int led_id,
|
||||
enum led_brightness brightness);
|
||||
int (*led_pattern) (struct iwl_priv *priv, int led_id, unsigned int idx);
|
||||
|
||||
enum led_type type;
|
||||
unsigned int registered;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
|
@ -829,23 +830,22 @@ static void iwl_add_radiotap(struct iwl_priv *priv,
|
|||
iwl4965_rt->rt_hdr.it_pad = 0;
|
||||
|
||||
/* total header + data */
|
||||
put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)),
|
||||
&iwl4965_rt->rt_hdr.it_len);
|
||||
put_unaligned_le16(sizeof(*iwl4965_rt), &iwl4965_rt->rt_hdr.it_len);
|
||||
|
||||
/* Indicate all the fields we add to the radiotap header */
|
||||
put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
|
||||
(1 << IEEE80211_RADIOTAP_FLAGS) |
|
||||
(1 << IEEE80211_RADIOTAP_RATE) |
|
||||
(1 << IEEE80211_RADIOTAP_CHANNEL) |
|
||||
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
|
||||
(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
|
||||
(1 << IEEE80211_RADIOTAP_ANTENNA)),
|
||||
&iwl4965_rt->rt_hdr.it_present);
|
||||
put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) |
|
||||
(1 << IEEE80211_RADIOTAP_FLAGS) |
|
||||
(1 << IEEE80211_RADIOTAP_RATE) |
|
||||
(1 << IEEE80211_RADIOTAP_CHANNEL) |
|
||||
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
|
||||
(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
|
||||
(1 << IEEE80211_RADIOTAP_ANTENNA),
|
||||
&(iwl4965_rt->rt_hdr.it_present));
|
||||
|
||||
/* Zero the flags, we'll add to them as we go */
|
||||
iwl4965_rt->rt_flags = 0;
|
||||
|
||||
put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf);
|
||||
put_unaligned_le64(tsf, &iwl4965_rt->rt_tsf);
|
||||
|
||||
iwl4965_rt->rt_dbmsignal = signal;
|
||||
iwl4965_rt->rt_dbmnoise = noise;
|
||||
|
@ -853,17 +853,14 @@ static void iwl_add_radiotap(struct iwl_priv *priv,
|
|||
/* Convert the channel frequency and set the flags */
|
||||
put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz);
|
||||
if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
|
||||
put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
|
||||
IEEE80211_CHAN_5GHZ),
|
||||
&iwl4965_rt->rt_chbitmask);
|
||||
put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
|
||||
&iwl4965_rt->rt_chbitmask);
|
||||
else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
|
||||
put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK |
|
||||
IEEE80211_CHAN_2GHZ),
|
||||
&iwl4965_rt->rt_chbitmask);
|
||||
put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
|
||||
&iwl4965_rt->rt_chbitmask);
|
||||
else /* 802.11g */
|
||||
put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
|
||||
IEEE80211_CHAN_2GHZ),
|
||||
&iwl4965_rt->rt_chbitmask);
|
||||
put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
|
||||
&iwl4965_rt->rt_chbitmask);
|
||||
|
||||
if (rate == -1)
|
||||
iwl4965_rt->rt_rate = 0;
|
||||
|
|
|
@ -38,8 +38,11 @@
|
|||
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
|
||||
* sending probe req. This should be set long enough to hear probe responses
|
||||
* from more than one AP. */
|
||||
#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */
|
||||
#define IWL_ACTIVE_DWELL_TIME_52 (10)
|
||||
#define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */
|
||||
#define IWL_ACTIVE_DWELL_TIME_52 (20)
|
||||
|
||||
#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
|
||||
#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
|
||||
|
||||
/* For faster active scanning, scan will move to the next channel if fewer than
|
||||
* PLCP_QUIET_THRESH packets are heard on this channel within
|
||||
|
@ -48,7 +51,7 @@
|
|||
* no other traffic).
|
||||
* Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
|
||||
#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */
|
||||
#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */
|
||||
#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(10) /* msec */
|
||||
|
||||
/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
|
||||
* Must be set longer than active dwell time.
|
||||
|
@ -58,10 +61,15 @@
|
|||
#define IWL_PASSIVE_DWELL_BASE (100)
|
||||
#define IWL_CHANNEL_TUNE_TIME 5
|
||||
|
||||
#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
|
||||
|
||||
|
||||
static int scan_tx_ant[3] = {
|
||||
RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int iwl_is_empty_essid(const char *essid, int essid_len)
|
||||
{
|
||||
/* Single white space is for Linksys APs */
|
||||
|
@ -226,8 +234,9 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
|
|||
"(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
|
||||
notif->channel,
|
||||
notif->band ? "bg" : "a",
|
||||
notif->tsf_high,
|
||||
notif->tsf_low, notif->status, notif->beacon_timer);
|
||||
le32_to_cpu(notif->tsf_high),
|
||||
le32_to_cpu(notif->tsf_low),
|
||||
notif->status, notif->beacon_timer);
|
||||
}
|
||||
|
||||
/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
|
||||
|
@ -332,19 +341,21 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
|
|||
EXPORT_SYMBOL(iwl_setup_rx_scan_handlers);
|
||||
|
||||
static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
|
||||
enum ieee80211_band band)
|
||||
enum ieee80211_band band,
|
||||
u8 n_probes)
|
||||
{
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
return IWL_ACTIVE_DWELL_TIME_52;
|
||||
return IWL_ACTIVE_DWELL_TIME_52 +
|
||||
IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
|
||||
else
|
||||
return IWL_ACTIVE_DWELL_TIME_24;
|
||||
return IWL_ACTIVE_DWELL_TIME_24 +
|
||||
IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
|
||||
}
|
||||
|
||||
static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
|
||||
enum ieee80211_band band)
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
u16 active = iwl_get_active_dwell_time(priv, band);
|
||||
u16 passive = (band != IEEE80211_BAND_5GHZ) ?
|
||||
u16 passive = (band == IEEE80211_BAND_2GHZ) ?
|
||||
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
|
||||
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
|
||||
|
||||
|
@ -358,15 +369,12 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
|
|||
passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
|
||||
}
|
||||
|
||||
if (passive <= active)
|
||||
passive = active + 1;
|
||||
|
||||
return passive;
|
||||
}
|
||||
|
||||
static int iwl_get_channels_for_scan(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u8 is_active, u8 direct_mask,
|
||||
u8 is_active, u8 n_probes,
|
||||
struct iwl_scan_channel *scan_ch)
|
||||
{
|
||||
const struct ieee80211_channel *channels = NULL;
|
||||
|
@ -375,6 +383,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
|
|||
u16 passive_dwell = 0;
|
||||
u16 active_dwell = 0;
|
||||
int added, i;
|
||||
u16 channel;
|
||||
|
||||
sband = iwl_get_hw_mode(priv, band);
|
||||
if (!sband)
|
||||
|
@ -382,31 +391,35 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
|
|||
|
||||
channels = sband->channels;
|
||||
|
||||
active_dwell = iwl_get_active_dwell_time(priv, band);
|
||||
active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
|
||||
passive_dwell = iwl_get_passive_dwell_time(priv, band);
|
||||
|
||||
if (passive_dwell <= active_dwell)
|
||||
passive_dwell = active_dwell + 1;
|
||||
|
||||
for (i = 0, added = 0; i < sband->n_channels; i++) {
|
||||
if (channels[i].flags & IEEE80211_CHAN_DISABLED)
|
||||
continue;
|
||||
|
||||
scan_ch->channel =
|
||||
channel =
|
||||
ieee80211_frequency_to_channel(channels[i].center_freq);
|
||||
scan_ch->channel = cpu_to_le16(channel);
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
|
||||
ch_info = iwl_get_channel_info(priv, band, channel);
|
||||
if (!is_channel_valid(ch_info)) {
|
||||
IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
|
||||
scan_ch->channel);
|
||||
channel);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_active || is_channel_passive(ch_info) ||
|
||||
(channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
|
||||
scan_ch->type = 0;
|
||||
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
|
||||
else
|
||||
scan_ch->type = 1;
|
||||
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
|
||||
|
||||
if (scan_ch->type & 1)
|
||||
scan_ch->type |= (direct_mask << 1);
|
||||
if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes)
|
||||
scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
|
||||
|
||||
scan_ch->active_dwell = cpu_to_le16(active_dwell);
|
||||
scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
|
||||
|
@ -414,20 +427,20 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
|
|||
/* Set txpower levels to defaults */
|
||||
scan_ch->dsp_atten = 110;
|
||||
|
||||
/* NOTE: if we were doing 6Mb OFDM for scans we'd use
|
||||
* power level:
|
||||
* scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
|
||||
*/
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
|
||||
else {
|
||||
else
|
||||
scan_ch->tx_gain = ((1 << 5) | (5 << 3));
|
||||
/* NOTE: if we were doing 6Mb OFDM for scans we'd use
|
||||
* power level:
|
||||
* scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
|
||||
*/
|
||||
}
|
||||
|
||||
IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
|
||||
scan_ch->channel,
|
||||
(scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
|
||||
(scan_ch->type & 1) ?
|
||||
IWL_DEBUG_SCAN("Scanning ch=%d prob=0x%X [%s %d]\n",
|
||||
channel, le32_to_cpu(scan_ch->type),
|
||||
(scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
|
||||
"ACTIVE" : "PASSIVE",
|
||||
(scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
|
||||
active_dwell : passive_dwell);
|
||||
|
||||
scan_ch++;
|
||||
|
@ -673,7 +686,7 @@ static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind);
|
||||
return scan_tx_ant[ind];
|
||||
}
|
||||
|
||||
|
@ -693,7 +706,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
|
|||
u32 tx_ant;
|
||||
u16 cmd_len;
|
||||
enum ieee80211_band band;
|
||||
u8 direct_mask;
|
||||
u8 n_probes = 2;
|
||||
u8 rx_chain = 0x7; /* bitmap: ABC chains */
|
||||
|
||||
conf = ieee80211_get_hw_conf(priv->hw);
|
||||
|
@ -793,17 +806,16 @@ static void iwl_bg_request_scan(struct work_struct *data)
|
|||
scan->direct_scan[0].len = priv->direct_ssid_len;
|
||||
memcpy(scan->direct_scan[0].ssid,
|
||||
priv->direct_ssid, priv->direct_ssid_len);
|
||||
direct_mask = 1;
|
||||
n_probes++;
|
||||
} else if (!iwl_is_associated(priv) && priv->essid_len) {
|
||||
IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
|
||||
iwl_escape_essid(priv->essid, priv->essid_len));
|
||||
scan->direct_scan[0].id = WLAN_EID_SSID;
|
||||
scan->direct_scan[0].len = priv->essid_len;
|
||||
memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
|
||||
direct_mask = 1;
|
||||
n_probes++;
|
||||
} else {
|
||||
IWL_DEBUG_SCAN("Start indirect scan.\n");
|
||||
direct_mask = 0;
|
||||
}
|
||||
|
||||
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
|
||||
|
@ -860,16 +872,11 @@ static void iwl_bg_request_scan(struct work_struct *data)
|
|||
scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
|
||||
RXON_FILTER_BCON_AWARE_MSK);
|
||||
|
||||
if (direct_mask)
|
||||
scan->channel_count =
|
||||
iwl_get_channels_for_scan(priv, band, 1, /* active */
|
||||
direct_mask,
|
||||
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
|
||||
else
|
||||
scan->channel_count =
|
||||
iwl_get_channels_for_scan(priv, band, 0, /* passive */
|
||||
direct_mask,
|
||||
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
|
||||
scan->channel_count =
|
||||
iwl_get_channels_for_scan(priv, band, 1, /* active */
|
||||
n_probes,
|
||||
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
|
||||
|
||||
if (scan->channel_count == 0) {
|
||||
IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count);
|
||||
goto done;
|
||||
|
|
|
@ -601,13 +601,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
|
|||
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
|
||||
}
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
|
||||
tx_flags |= TX_CMD_FLG_RTS_MSK;
|
||||
tx_flags &= ~TX_CMD_FLG_CTS_MSK;
|
||||
} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
||||
tx_flags &= ~TX_CMD_FLG_RTS_MSK;
|
||||
tx_flags |= TX_CMD_FLG_CTS_MSK;
|
||||
}
|
||||
priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
|
||||
|
||||
if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
|
||||
tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
|
||||
|
|
|
@ -2035,36 +2035,6 @@ static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
|
||||
{
|
||||
/* Filter incoming packets to determine if they are targeted toward
|
||||
* this network, discarding packets coming from ourselves */
|
||||
switch (priv->iw_mode) {
|
||||
case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
|
||||
/* packets from our adapter are dropped (echo) */
|
||||
if (!compare_ether_addr(header->addr2, priv->mac_addr))
|
||||
return 0;
|
||||
/* {broad,multi}cast packets to our IBSS go through */
|
||||
if (is_multicast_ether_addr(header->addr1))
|
||||
return !compare_ether_addr(header->addr3, priv->bssid);
|
||||
/* packets to our adapter go through */
|
||||
return !compare_ether_addr(header->addr1, priv->mac_addr);
|
||||
case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
|
||||
/* packets from our adapter are dropped (echo) */
|
||||
if (!compare_ether_addr(header->addr3, priv->mac_addr))
|
||||
return 0;
|
||||
/* {broad,multi}cast packets to our BSS go through */
|
||||
if (is_multicast_ether_addr(header->addr1))
|
||||
return !compare_ether_addr(header->addr2, priv->bssid);
|
||||
/* packets to our adapter go through */
|
||||
return !compare_ether_addr(header->addr1, priv->mac_addr);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl3945_scan_cancel - Cancel any currently executing HW scan
|
||||
*
|
||||
|
@ -2117,20 +2087,6 @@ static int iwl3945_scan_cancel_timeout(struct iwl3945_priv *priv, unsigned long
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void iwl3945_sequence_reset(struct iwl3945_priv *priv)
|
||||
{
|
||||
/* Reset ieee stats */
|
||||
|
||||
/* We don't reset the net_device_stats (ieee->stats) on
|
||||
* re-association */
|
||||
|
||||
priv->last_seq_num = -1;
|
||||
priv->last_frag_num = -1;
|
||||
priv->last_packet_time = 0;
|
||||
|
||||
iwl3945_scan_cancel(priv);
|
||||
}
|
||||
|
||||
#define MAX_UCODE_BEACON_INTERVAL 1024
|
||||
#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA)
|
||||
|
||||
|
@ -2925,72 +2881,6 @@ void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb,
|
|||
}
|
||||
}
|
||||
|
||||
#define IWL_PACKET_RETRY_TIME HZ
|
||||
|
||||
int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
|
||||
{
|
||||
u16 sc = le16_to_cpu(header->seq_ctrl);
|
||||
u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
|
||||
u16 frag = sc & IEEE80211_SCTL_FRAG;
|
||||
u16 *last_seq, *last_frag;
|
||||
unsigned long *last_time;
|
||||
|
||||
switch (priv->iw_mode) {
|
||||
case IEEE80211_IF_TYPE_IBSS:{
|
||||
struct list_head *p;
|
||||
struct iwl3945_ibss_seq *entry = NULL;
|
||||
u8 *mac = header->addr2;
|
||||
int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
|
||||
|
||||
__list_for_each(p, &priv->ibss_mac_hash[index]) {
|
||||
entry = list_entry(p, struct iwl3945_ibss_seq, list);
|
||||
if (!compare_ether_addr(entry->mac, mac))
|
||||
break;
|
||||
}
|
||||
if (p == &priv->ibss_mac_hash[index]) {
|
||||
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
if (!entry) {
|
||||
IWL_ERROR("Cannot malloc new mac entry\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy(entry->mac, mac, ETH_ALEN);
|
||||
entry->seq_num = seq;
|
||||
entry->frag_num = frag;
|
||||
entry->packet_time = jiffies;
|
||||
list_add(&entry->list, &priv->ibss_mac_hash[index]);
|
||||
return 0;
|
||||
}
|
||||
last_seq = &entry->seq_num;
|
||||
last_frag = &entry->frag_num;
|
||||
last_time = &entry->packet_time;
|
||||
break;
|
||||
}
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
last_seq = &priv->last_seq_num;
|
||||
last_frag = &priv->last_frag_num;
|
||||
last_time = &priv->last_packet_time;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if ((*last_seq == seq) &&
|
||||
time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
|
||||
if (*last_frag == frag)
|
||||
goto drop;
|
||||
if (*last_frag + 1 != frag)
|
||||
/* out-of-order fragment */
|
||||
goto drop;
|
||||
} else
|
||||
*last_seq = seq;
|
||||
|
||||
*last_frag = frag;
|
||||
*last_time = jiffies;
|
||||
return 0;
|
||||
|
||||
drop:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
|
||||
|
||||
#include "iwl-spectrum.h"
|
||||
|
@ -6531,8 +6421,6 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
|
|||
break;
|
||||
}
|
||||
|
||||
iwl3945_sequence_reset(priv);
|
||||
|
||||
iwl3945_activate_qos(priv, 0);
|
||||
|
||||
/* we have just associated, don't start scan too early */
|
||||
|
@ -6907,6 +6795,9 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
|
|||
* clear sta table, add BCAST sta... */
|
||||
}
|
||||
|
||||
/* temporary */
|
||||
static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
|
||||
static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_if_conf *conf)
|
||||
|
@ -6924,10 +6815,21 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* handle this temporarily here */
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
|
||||
conf->changed & IEEE80211_IFCC_BEACON) {
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
|
||||
if (!beacon)
|
||||
return -ENOMEM;
|
||||
rc = iwl3945_mac_beacon_update(hw, beacon);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* XXX: this MUST use conf->mac_addr */
|
||||
|
||||
if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
|
||||
(!conf->beacon || !conf->ssid_len)) {
|
||||
(!conf->ssid_len)) {
|
||||
IWL_DEBUG_MAC80211
|
||||
("Leaving in AP mode because HostAPD is not ready.\n");
|
||||
return 0;
|
||||
|
@ -6959,7 +6861,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
|
|||
if (priv->ibss_beacon)
|
||||
dev_kfree_skb(priv->ibss_beacon);
|
||||
|
||||
priv->ibss_beacon = conf->beacon;
|
||||
priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
|
||||
}
|
||||
|
||||
if (iwl3945_is_rfkill(priv))
|
||||
|
@ -7940,7 +7842,6 @@ static struct ieee80211_ops iwl3945_hw_ops = {
|
|||
.conf_tx = iwl3945_mac_conf_tx,
|
||||
.get_tsf = iwl3945_mac_get_tsf,
|
||||
.reset_tsf = iwl3945_mac_reset_tsf,
|
||||
.beacon_update = iwl3945_mac_beacon_update,
|
||||
.hw_scan = iwl3945_mac_hw_scan
|
||||
};
|
||||
|
||||
|
@ -7950,7 +7851,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
|||
struct iwl3945_priv *priv;
|
||||
struct ieee80211_hw *hw;
|
||||
struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
|
||||
int i;
|
||||
unsigned long flags;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
|
@ -8011,9 +7911,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
|||
spin_lock_init(&priv->sta_lock);
|
||||
spin_lock_init(&priv->hcmd_lock);
|
||||
|
||||
for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
|
||||
INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
|
||||
|
||||
INIT_LIST_HEAD(&priv->free_frames);
|
||||
|
||||
mutex_init(&priv->mutex);
|
||||
|
@ -8186,8 +8083,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
|||
static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct iwl3945_priv *priv = pci_get_drvdata(pdev);
|
||||
struct list_head *p, *q;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
if (!priv)
|
||||
|
@ -8208,14 +8103,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
|
|||
|
||||
iwl_synchronize_irq(priv);
|
||||
|
||||
/* Free MAC hash list for ADHOC */
|
||||
for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
|
||||
list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
|
||||
list_del(p);
|
||||
kfree(list_entry(p, struct iwl3945_ibss_seq, list));
|
||||
}
|
||||
}
|
||||
|
||||
sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
|
||||
|
||||
iwl3945_rfkill_unregister(priv);
|
||||
|
|
|
@ -250,6 +250,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
|
|||
|
||||
/* always get timestamp with Rx frame */
|
||||
priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
|
||||
/* allow CTS-to-self if possible. this is relevant only for
|
||||
* 5000, but will not damage 4965 */
|
||||
priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
|
||||
|
||||
ret = iwl4965_check_rxon_cmd(&priv->staging_rxon);
|
||||
if (ret) {
|
||||
|
@ -325,16 +328,6 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
|
|||
if (!priv->error_recovering)
|
||||
priv->start_calib = 0;
|
||||
|
||||
iwl_init_sensitivity(priv);
|
||||
|
||||
/* If we issue a new RXON command which required a tune then we must
|
||||
* send a new TXPOWER command or we won't be able to Tx any frames */
|
||||
ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
|
||||
if (ret) {
|
||||
IWL_ERROR("Error sending TX power (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Add the broadcast address so we can send broadcast frames */
|
||||
if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
|
||||
IWL_INVALID_STATION) {
|
||||
|
@ -370,6 +363,16 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
|
|||
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
|
||||
}
|
||||
|
||||
iwl_init_sensitivity(priv);
|
||||
|
||||
/* If we issue a new RXON command which required a tune then we must
|
||||
* send a new TXPOWER command or we won't be able to Tx any frames */
|
||||
ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
|
||||
if (ret) {
|
||||
IWL_ERROR("Error sending TX power (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -572,25 +575,14 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
|
|||
/*
|
||||
* QoS support
|
||||
*/
|
||||
static int iwl4965_send_qos_params_command(struct iwl_priv *priv,
|
||||
struct iwl4965_qosparam_cmd *qos)
|
||||
static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
|
||||
{
|
||||
|
||||
return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
|
||||
sizeof(struct iwl4965_qosparam_cmd), qos);
|
||||
}
|
||||
|
||||
static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (!priv->qos_data.qos_enable)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->qos_data.def_qos_parm.qos_flags = 0;
|
||||
|
||||
if (priv->qos_data.qos_cap.q_AP.queue_request &&
|
||||
|
@ -604,15 +596,14 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force)
|
|||
if (priv->current_ht_config.is_ht)
|
||||
priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (force || iwl_is_associated(priv)) {
|
||||
IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
|
||||
priv->qos_data.qos_active,
|
||||
priv->qos_data.def_qos_parm.qos_flags);
|
||||
|
||||
iwl4965_send_qos_params_command(priv,
|
||||
&(priv->qos_data.def_qos_parm));
|
||||
iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
|
||||
sizeof(struct iwl_qosparam_cmd),
|
||||
&priv->qos_data.def_qos_parm, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2421,6 +2412,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
|
|||
struct ieee80211_conf *conf = NULL;
|
||||
int ret = 0;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
unsigned long flags;
|
||||
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
|
||||
IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
|
||||
|
@ -2510,25 +2502,15 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
|
|||
if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
|
||||
priv->assoc_station_added = 1;
|
||||
|
||||
iwl4965_activate_qos(priv, 0);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
iwl_activate_qos(priv, 0);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
iwl_power_update_mode(priv, 0);
|
||||
/* we have just associated, don't start scan too early */
|
||||
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
|
||||
}
|
||||
|
||||
|
||||
static void iwl4965_bg_post_associate(struct work_struct *data)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(data, struct iwl_priv,
|
||||
post_associate.work);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl4965_post_associate(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
}
|
||||
|
||||
static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
|
||||
|
||||
static void iwl_bg_scan_completed(struct work_struct *work)
|
||||
|
@ -2659,7 +2641,6 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
|
|||
*/
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl_scan_cancel_timeout(priv, 100);
|
||||
cancel_delayed_work(&priv->post_associate);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
|
@ -2855,6 +2836,7 @@ out:
|
|||
static void iwl4965_config_ap(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
@ -2902,7 +2884,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
|
|||
/* restore RXON assoc */
|
||||
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
|
||||
iwl4965_commit_rxon(priv);
|
||||
iwl4965_activate_qos(priv, 1);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
iwl_activate_qos(priv, 1);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
|
||||
}
|
||||
iwl4965_send_beacon_cmd(priv);
|
||||
|
@ -2912,6 +2896,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
|
|||
* clear sta table, add BCAST sta... */
|
||||
}
|
||||
|
||||
/* temporary */
|
||||
static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
|
||||
static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_if_conf *conf)
|
||||
|
@ -2929,8 +2916,18 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
|
||||
conf->changed & IEEE80211_IFCC_BEACON) {
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
|
||||
if (!beacon)
|
||||
return -ENOMEM;
|
||||
rc = iwl4965_mac_beacon_update(hw, beacon);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
|
||||
(!conf->beacon || !conf->ssid_len)) {
|
||||
(!conf->ssid_len)) {
|
||||
IWL_DEBUG_MAC80211
|
||||
("Leaving in AP mode because HostAPD is not ready.\n");
|
||||
return 0;
|
||||
|
@ -2962,7 +2959,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
|
|||
if (priv->ibss_beacon)
|
||||
dev_kfree_skb(priv->ibss_beacon);
|
||||
|
||||
priv->ibss_beacon = conf->beacon;
|
||||
priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
|
||||
}
|
||||
|
||||
if (iwl_is_rfkill(priv))
|
||||
|
@ -3048,7 +3045,6 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
|
||||
if (iwl_is_ready_rf(priv)) {
|
||||
iwl_scan_cancel_timeout(priv, 100);
|
||||
cancel_delayed_work(&priv->post_associate);
|
||||
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||
iwl4965_commit_rxon(priv);
|
||||
}
|
||||
|
@ -3338,15 +3334,12 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
|||
priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
|
||||
priv->qos_data.qos_active = 1;
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
|
||||
iwl4965_activate_qos(priv, 1);
|
||||
iwl_activate_qos(priv, 1);
|
||||
else if (priv->assoc_id && iwl_is_associated(priv))
|
||||
iwl4965_activate_qos(priv, 0);
|
||||
iwl_activate_qos(priv, 0);
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
IWL_DEBUG_MAC80211("leave\n");
|
||||
return 0;
|
||||
|
@ -3413,8 +3406,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
|
|||
|
||||
iwl_reset_qos(priv);
|
||||
|
||||
cancel_delayed_work(&priv->post_associate);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->assoc_id = 0;
|
||||
priv->assoc_capability = 0;
|
||||
|
@ -4016,7 +4007,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
|||
INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
|
||||
INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
|
||||
INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
|
||||
INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate);
|
||||
INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
|
||||
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
|
||||
|
||||
|
@ -4043,7 +4033,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
|||
cancel_delayed_work_sync(&priv->init_alive_start);
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
cancel_delayed_work(&priv->alive_start);
|
||||
cancel_delayed_work(&priv->post_associate);
|
||||
cancel_work_sync(&priv->beacon_update);
|
||||
del_timer_sync(&priv->statistics_periodic);
|
||||
}
|
||||
|
@ -4090,7 +4079,6 @@ static struct ieee80211_ops iwl4965_hw_ops = {
|
|||
.get_tx_stats = iwl4965_mac_get_tx_stats,
|
||||
.conf_tx = iwl4965_mac_conf_tx,
|
||||
.reset_tsf = iwl4965_mac_reset_tsf,
|
||||
.beacon_update = iwl4965_mac_beacon_update,
|
||||
.bss_info_changed = iwl4965_bss_info_changed,
|
||||
.ampdu_action = iwl4965_mac_ampdu_action,
|
||||
.hw_scan = iwl4965_mac_hw_scan
|
||||
|
@ -4409,8 +4397,16 @@ static struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
#ifdef CONFIG_IWL5000
|
||||
{IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)},
|
||||
#endif /* CONFIG_IWL5000 */
|
||||
{0}
|
||||
|
|
|
@ -126,7 +126,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
|
|||
(1 << IEEE80211_RADIOTAP_CHANNEL));
|
||||
hdr->rt_flags = 0;
|
||||
hdr->rt_rate = txrate->bitrate / 5;
|
||||
hdr->rt_channel = data->channel->center_freq;
|
||||
hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
|
||||
flags = IEEE80211_CHAN_2GHZ;
|
||||
if (txrate->flags & IEEE80211_RATE_ERP_G)
|
||||
flags |= IEEE80211_CHAN_OFDM;
|
||||
|
|
|
@ -1069,6 +1069,40 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
/*
|
||||
* TX data initialization
|
||||
*/
|
||||
static void rt2400pci_write_beacon(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
u32 word;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 0);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
|
||||
/*
|
||||
* Replace rt2x00lib allocated descriptor with the
|
||||
* pointer to the _real_ hardware descriptor.
|
||||
* After that, map the beacon to DMA and update the
|
||||
* descriptor.
|
||||
*/
|
||||
memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
|
||||
skbdesc->desc = entry_priv->desc;
|
||||
|
||||
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 1, &word);
|
||||
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
|
||||
rt2x00_desc_write(entry_priv->desc, 1, word);
|
||||
}
|
||||
|
||||
static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
|
||||
const enum data_queue_qid queue)
|
||||
{
|
||||
|
@ -1515,59 +1549,6 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
|
|||
return tsf;
|
||||
}
|
||||
|
||||
static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
|
||||
struct queue_entry_priv_pci *entry_priv;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct txentry_desc txdesc;
|
||||
u32 reg;
|
||||
|
||||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
entry_priv = intf->beacon->priv_data;
|
||||
|
||||
/*
|
||||
* Copy all TX descriptor information into txdesc,
|
||||
* after that we are free to use the skb->cb array
|
||||
* for our information.
|
||||
*/
|
||||
intf->beacon->skb = skb;
|
||||
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
|
||||
|
||||
/*
|
||||
* Fill in skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = entry_priv->desc;
|
||||
skbdesc->desc_len = intf->beacon->queue->desc_size;
|
||||
skbdesc->entry = intf->beacon;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 0);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
|
||||
/*
|
||||
* Enable beacon generation.
|
||||
* Write entire beacon with descriptor to register,
|
||||
* and kick the beacon generator.
|
||||
*/
|
||||
rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
|
||||
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
|
||||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
|
@ -1592,7 +1573,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
|
|||
.conf_tx = rt2400pci_conf_tx,
|
||||
.get_tx_stats = rt2x00mac_get_tx_stats,
|
||||
.get_tsf = rt2400pci_get_tsf,
|
||||
.beacon_update = rt2400pci_beacon_update,
|
||||
.tx_last_beacon = rt2400pci_tx_last_beacon,
|
||||
};
|
||||
|
||||
|
@ -1610,6 +1590,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
|
|||
.link_tuner = rt2400pci_link_tuner,
|
||||
.write_tx_desc = rt2400pci_write_tx_desc,
|
||||
.write_tx_data = rt2x00pci_write_tx_data,
|
||||
.write_beacon = rt2400pci_write_beacon,
|
||||
.kick_tx_queue = rt2400pci_kick_tx_queue,
|
||||
.fill_rxdone = rt2400pci_fill_rxdone,
|
||||
.config_filter = rt2400pci_config_filter,
|
||||
|
|
|
@ -1227,6 +1227,40 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
/*
|
||||
* TX data initialization
|
||||
*/
|
||||
static void rt2500pci_write_beacon(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
u32 word;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 0);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
|
||||
/*
|
||||
* Replace rt2x00lib allocated descriptor with the
|
||||
* pointer to the _real_ hardware descriptor.
|
||||
* After that, map the beacon to DMA and update the
|
||||
* descriptor.
|
||||
*/
|
||||
memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
|
||||
skbdesc->desc = entry_priv->desc;
|
||||
|
||||
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 1, &word);
|
||||
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
|
||||
rt2x00_desc_write(entry_priv->desc, 1, word);
|
||||
}
|
||||
|
||||
static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
|
||||
const enum data_queue_qid queue)
|
||||
{
|
||||
|
@ -1808,60 +1842,6 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
|
|||
return tsf;
|
||||
}
|
||||
|
||||
static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
|
||||
struct queue_entry_priv_pci *entry_priv;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct txentry_desc txdesc;
|
||||
u32 reg;
|
||||
|
||||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
|
||||
entry_priv = intf->beacon->priv_data;
|
||||
|
||||
/*
|
||||
* Copy all TX descriptor information into txdesc,
|
||||
* after that we are free to use the skb->cb array
|
||||
* for our information.
|
||||
*/
|
||||
intf->beacon->skb = skb;
|
||||
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
|
||||
|
||||
/*
|
||||
* Fill in skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = entry_priv->desc;
|
||||
skbdesc->desc_len = intf->beacon->queue->desc_size;
|
||||
skbdesc->entry = intf->beacon;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 0);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
|
||||
/*
|
||||
* Enable beacon generation.
|
||||
* Write entire beacon with descriptor to register,
|
||||
* and kick the beacon generator.
|
||||
*/
|
||||
rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
|
||||
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
|
||||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
|
@ -1886,7 +1866,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
|
|||
.conf_tx = rt2x00mac_conf_tx,
|
||||
.get_tx_stats = rt2x00mac_get_tx_stats,
|
||||
.get_tsf = rt2500pci_get_tsf,
|
||||
.beacon_update = rt2500pci_beacon_update,
|
||||
.tx_last_beacon = rt2500pci_tx_last_beacon,
|
||||
};
|
||||
|
||||
|
@ -1904,6 +1883,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
|
|||
.link_tuner = rt2500pci_link_tuner,
|
||||
.write_tx_desc = rt2500pci_write_tx_desc,
|
||||
.write_tx_data = rt2x00pci_write_tx_data,
|
||||
.write_beacon = rt2500pci_write_beacon,
|
||||
.kick_tx_queue = rt2500pci_kick_tx_queue,
|
||||
.fill_rxdone = rt2500pci_fill_rxdone,
|
||||
.config_filter = rt2500pci_config_filter,
|
||||
|
|
|
@ -1107,6 +1107,65 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
rt2x00_desc_write(txd, 0, word);
|
||||
}
|
||||
|
||||
/*
|
||||
* TX data initialization
|
||||
*/
|
||||
static void rt2500usb_beacondone(struct urb *urb);
|
||||
|
||||
static void rt2500usb_write_beacon(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
|
||||
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
int pipe = usb_sndbulkpipe(usb_dev, 1);
|
||||
int length;
|
||||
u16 reg;
|
||||
|
||||
/*
|
||||
* Add the descriptor in front of the skb.
|
||||
*/
|
||||
skb_push(entry->skb, entry->queue->desc_size);
|
||||
memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
|
||||
skbdesc->desc = entry->skb->data;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
|
||||
|
||||
/*
|
||||
* USB devices cannot blindly pass the skb->len as the
|
||||
* length of the data to usb_fill_bulk_urb. Pass the skb
|
||||
* to the driver to determine what the length should be.
|
||||
*/
|
||||
length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
|
||||
|
||||
usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
|
||||
entry->skb->data, length, rt2500usb_beacondone,
|
||||
entry);
|
||||
|
||||
/*
|
||||
* Second we need to create the guardian byte.
|
||||
* We only need a single byte, so lets recycle
|
||||
* the 'flags' field we are not using for beacons.
|
||||
*/
|
||||
bcn_priv->guardian_data = 0;
|
||||
usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
|
||||
&bcn_priv->guardian_data, 1, rt2500usb_beacondone,
|
||||
entry);
|
||||
|
||||
/*
|
||||
* Send out the guardian byte.
|
||||
*/
|
||||
usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -1122,9 +1181,6 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
|
|||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
* TX data initialization
|
||||
*/
|
||||
static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
|
||||
const enum data_queue_qid queue)
|
||||
{
|
||||
|
@ -1679,96 +1735,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* IEEE80211 stack callback functions.
|
||||
*/
|
||||
static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
|
||||
struct queue_entry_priv_usb_bcn *bcn_priv;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct txentry_desc txdesc;
|
||||
int pipe = usb_sndbulkpipe(usb_dev, 1);
|
||||
int length;
|
||||
u16 reg;
|
||||
|
||||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
|
||||
bcn_priv = intf->beacon->priv_data;
|
||||
|
||||
/*
|
||||
* Copy all TX descriptor information into txdesc,
|
||||
* after that we are free to use the skb->cb array
|
||||
* for our information.
|
||||
*/
|
||||
intf->beacon->skb = skb;
|
||||
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
|
||||
|
||||
/*
|
||||
* Add the descriptor in front of the skb.
|
||||
*/
|
||||
skb_push(skb, intf->beacon->queue->desc_size);
|
||||
memset(skb->data, 0, intf->beacon->queue->desc_size);
|
||||
|
||||
/*
|
||||
* Fill in skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = skb->data;
|
||||
skbdesc->desc_len = intf->beacon->queue->desc_size;
|
||||
skbdesc->entry = intf->beacon;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
|
||||
|
||||
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
|
||||
|
||||
/*
|
||||
* USB devices cannot blindly pass the skb->len as the
|
||||
* length of the data to usb_fill_bulk_urb. Pass the skb
|
||||
* to the driver to determine what the length should be.
|
||||
*/
|
||||
length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
|
||||
|
||||
usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
|
||||
skb->data, length, rt2500usb_beacondone,
|
||||
intf->beacon);
|
||||
|
||||
/*
|
||||
* Second we need to create the guardian byte.
|
||||
* We only need a single byte, so lets recycle
|
||||
* the 'flags' field we are not using for beacons.
|
||||
*/
|
||||
bcn_priv->guardian_data = 0;
|
||||
usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
|
||||
&bcn_priv->guardian_data, 1, rt2500usb_beacondone,
|
||||
intf->beacon);
|
||||
|
||||
/*
|
||||
* Send out the guardian byte.
|
||||
*/
|
||||
usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
|
||||
|
||||
/*
|
||||
* Enable beacon generation.
|
||||
*/
|
||||
rt2500usb_kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops rt2500usb_mac80211_ops = {
|
||||
.tx = rt2x00mac_tx,
|
||||
.start = rt2x00mac_start,
|
||||
|
@ -1782,7 +1748,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
|
|||
.bss_info_changed = rt2x00mac_bss_info_changed,
|
||||
.conf_tx = rt2x00mac_conf_tx,
|
||||
.get_tx_stats = rt2x00mac_get_tx_stats,
|
||||
.beacon_update = rt2500usb_beacon_update,
|
||||
};
|
||||
|
||||
static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
|
||||
|
@ -1797,6 +1762,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
|
|||
.link_tuner = rt2500usb_link_tuner,
|
||||
.write_tx_desc = rt2500usb_write_tx_desc,
|
||||
.write_tx_data = rt2x00usb_write_tx_data,
|
||||
.write_beacon = rt2500usb_write_beacon,
|
||||
.get_tx_data_len = rt2500usb_get_tx_data_len,
|
||||
.kick_tx_queue = rt2500usb_kick_tx_queue,
|
||||
.fill_rxdone = rt2500usb_fill_rxdone,
|
||||
|
|
|
@ -364,6 +364,8 @@ struct rt2x00_intf {
|
|||
#define DELAYED_UPDATE_BEACON 0x00000001
|
||||
#define DELAYED_CONFIG_ERP 0x00000002
|
||||
#define DELAYED_LED_ASSOC 0x00000004
|
||||
|
||||
u16 seqno;
|
||||
};
|
||||
|
||||
static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
|
||||
|
@ -434,6 +436,7 @@ struct rt2x00lib_conf {
|
|||
*/
|
||||
struct rt2x00lib_erp {
|
||||
int short_preamble;
|
||||
int cts_protection;
|
||||
|
||||
int ack_timeout;
|
||||
int ack_consume_time;
|
||||
|
@ -520,6 +523,7 @@ struct rt2x00lib_ops {
|
|||
struct sk_buff *skb,
|
||||
struct txentry_desc *txdesc);
|
||||
int (*write_tx_data) (struct queue_entry *entry);
|
||||
void (*write_beacon) (struct queue_entry *entry);
|
||||
int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
|
||||
struct sk_buff *skb);
|
||||
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
|
||||
|
@ -909,39 +913,6 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
|
|||
*/
|
||||
void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
|
||||
* @entry: The entry which will be used to transfer the TX frame.
|
||||
* @txdesc: rt2x00 TX descriptor which will be initialized by this function.
|
||||
*
|
||||
* This function will initialize the &struct txentry_desc based on information
|
||||
* from mac80211. This descriptor can then be used by rt2x00lib and the drivers
|
||||
* to correctly initialize the hardware descriptor.
|
||||
* Note that before calling this function the skb->cb array must be untouched
|
||||
* by rt2x00lib. Only after this function completes will it be save to
|
||||
* overwrite the skb->cb information.
|
||||
* The reason for this is that mac80211 writes its own tx information into
|
||||
* the skb->cb array, and this function will use that information to initialize
|
||||
* the &struct txentry_desc structure.
|
||||
*/
|
||||
void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc);
|
||||
|
||||
/**
|
||||
* rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware
|
||||
* @entry: The entry which will be used to transfer the TX frame.
|
||||
* @txdesc: TX descriptor which will be used to write hardware descriptor
|
||||
*
|
||||
* This function will write a TX descriptor initialized by
|
||||
* &rt2x00queue_create_tx_descriptor to the hardware. After this call
|
||||
* has completed the frame is now owned by the hardware, the hardware
|
||||
* queue will have automatically be kicked unless this frame was generated
|
||||
* by rt2x00lib, in which case the frame is "special" and must be kicked
|
||||
* by the caller.
|
||||
*/
|
||||
void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc);
|
||||
|
||||
/**
|
||||
* rt2x00queue_get_queue - Convert queue index to queue pointer
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
|
|
|
@ -84,6 +84,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
|
|||
memset(&erp, 0, sizeof(erp));
|
||||
|
||||
erp.short_preamble = bss_conf->use_short_preamble;
|
||||
erp.cts_protection = bss_conf->use_cts_prot;
|
||||
|
||||
erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10);
|
||||
erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
|
||||
|
||||
|
|
|
@ -409,7 +409,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
|
|||
{
|
||||
struct rt2x00_dev *rt2x00dev = data;
|
||||
struct rt2x00_intf *intf = vif_to_intf(vif);
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_bss_conf conf;
|
||||
int delayed_flags;
|
||||
|
||||
|
@ -435,12 +434,8 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
|
|||
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
|
||||
return;
|
||||
|
||||
if (delayed_flags & DELAYED_UPDATE_BEACON) {
|
||||
skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
|
||||
if (skb &&
|
||||
rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
if (delayed_flags & DELAYED_UPDATE_BEACON)
|
||||
rt2x00queue_update_beacon(rt2x00dev, vif);
|
||||
|
||||
if (delayed_flags & DELAYED_CONFIG_ERP)
|
||||
rt2x00lib_config_erp(rt2x00dev, intf, &conf);
|
||||
|
|
|
@ -100,6 +100,14 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
|
|||
retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
|
||||
rt2x00dev->fw->data,
|
||||
rt2x00dev->fw->size);
|
||||
|
||||
/*
|
||||
* When the firmware is uploaded to the hardware the LED
|
||||
* association status might have been triggered, for correct
|
||||
* LED handling it should now be reset.
|
||||
*/
|
||||
rt2x00leds_led_assoc(rt2x00dev, false);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
@ -138,6 +138,14 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
|
|||
*/
|
||||
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
* @vif: Interface for which the beacon should be updated.
|
||||
*/
|
||||
int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* rt2x00queue_index_inc - Index incrementation function
|
||||
* @queue: Queue (&struct data_queue) to perform the action on.
|
||||
|
|
|
@ -96,6 +96,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
|
||||
enum data_queue_qid qid = skb_get_queue_mapping(skb);
|
||||
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
|
||||
struct data_queue *queue;
|
||||
u16 frame_control;
|
||||
|
||||
|
@ -151,6 +152,18 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: This is as wrong as the old mac80211 code was,
|
||||
* due to beacons not getting sequence numbers assigned
|
||||
* properly.
|
||||
*/
|
||||
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
|
||||
if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
|
||||
intf->seqno += 0x10;
|
||||
ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
|
||||
ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
|
||||
}
|
||||
|
||||
if (rt2x00queue_write_tx_frame(queue, skb)) {
|
||||
ieee80211_stop_queue(rt2x00dev->hw, qid);
|
||||
return NETDEV_TX_BUSY;
|
||||
|
@ -348,7 +361,8 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct rt2x00_intf *intf = vif_to_intf(vif);
|
||||
int status;
|
||||
int update_bssid = 0;
|
||||
int status = 0;
|
||||
|
||||
/*
|
||||
* Mac80211 might be calling this function while we are trying
|
||||
|
@ -360,12 +374,13 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
|
|||
spin_lock(&intf->lock);
|
||||
|
||||
/*
|
||||
* If the interface does not work in master mode,
|
||||
* then the bssid value in the interface structure
|
||||
* should now be set.
|
||||
* conf->bssid can be NULL if coming from the internal
|
||||
* beacon update routine.
|
||||
*/
|
||||
if (conf->type != IEEE80211_IF_TYPE_AP)
|
||||
if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) {
|
||||
update_bssid = 1;
|
||||
memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
|
||||
}
|
||||
|
||||
spin_unlock(&intf->lock);
|
||||
|
||||
|
@ -375,17 +390,14 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
|
|||
* values as arguments we make keep access to rt2x00_intf thread safe
|
||||
* even without the lock.
|
||||
*/
|
||||
rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, conf->bssid);
|
||||
rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
|
||||
update_bssid ? conf->bssid : NULL);
|
||||
|
||||
/*
|
||||
* We only need to initialize the beacon when master mode is enabled.
|
||||
* Update the beacon.
|
||||
*/
|
||||
if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
|
||||
return 0;
|
||||
|
||||
status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon);
|
||||
if (status)
|
||||
dev_kfree_skb(conf->beacon);
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON)
|
||||
status = rt2x00queue_update_beacon(rt2x00dev, vif);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -501,7 +513,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
|
|||
* When the erp information has changed, we should perform
|
||||
* additional configuration steps. For all other changes we are done.
|
||||
*/
|
||||
if (changes & BSS_CHANGED_ERP_PREAMBLE) {
|
||||
if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) {
|
||||
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
|
||||
rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
|
||||
else
|
||||
|
|
|
@ -108,12 +108,15 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
|
|||
|
||||
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
|
||||
{
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
rt2x00queue_unmap_skb(rt2x00dev, skb);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc)
|
||||
static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
|
||||
|
@ -237,10 +240,9 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
|||
txdesc->signal |= 0x08;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor);
|
||||
|
||||
void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc)
|
||||
static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc)
|
||||
{
|
||||
struct data_queue *queue = entry->queue;
|
||||
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
|
||||
|
@ -270,7 +272,6 @@ void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
|
|||
!test_bit(ENTRY_TXD_BURST, &txdesc->flags))
|
||||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor);
|
||||
|
||||
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
|
||||
{
|
||||
|
@ -320,6 +321,60 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct rt2x00_intf *intf = vif_to_intf(vif);
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct txentry_desc txdesc;
|
||||
__le32 desc[16];
|
||||
|
||||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
|
||||
intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
|
||||
if (!intf->beacon->skb)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Copy all TX descriptor information into txdesc,
|
||||
* after that we are free to use the skb->cb array
|
||||
* for our information.
|
||||
*/
|
||||
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
|
||||
|
||||
/*
|
||||
* For the descriptor we use a local array from where the
|
||||
* driver can move it to the correct location required for
|
||||
* the hardware.
|
||||
*/
|
||||
memset(desc, 0, sizeof(desc));
|
||||
|
||||
/*
|
||||
* Fill in skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(intf->beacon->skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = desc;
|
||||
skbdesc->desc_len = intf->beacon->queue->desc_size;
|
||||
skbdesc->entry = intf->beacon;
|
||||
|
||||
/*
|
||||
* Write TX descriptor into reserved room in front of the beacon.
|
||||
*/
|
||||
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
|
||||
|
||||
/*
|
||||
* Send beacon to hardware.
|
||||
* Also enable beacon generation, which might have been disabled
|
||||
* by the driver during the config_beacon() callback function.
|
||||
*/
|
||||
rt2x00dev->ops->lib->write_beacon(intf->beacon);
|
||||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
|
||||
const enum data_queue_qid queue)
|
||||
{
|
||||
|
|
|
@ -1600,6 +1600,41 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
/*
|
||||
* TX data initialization
|
||||
*/
|
||||
static void rt61pci_write_beacon(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
unsigned int beacon_base;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
/*
|
||||
* Write entire beacon with descriptor to register.
|
||||
*/
|
||||
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
|
||||
rt2x00pci_register_multiwrite(rt2x00dev,
|
||||
beacon_base,
|
||||
skbdesc->desc, skbdesc->desc_len);
|
||||
rt2x00pci_register_multiwrite(rt2x00dev,
|
||||
beacon_base + skbdesc->desc_len,
|
||||
entry->skb->data, entry->skb->len);
|
||||
|
||||
/*
|
||||
* Clean up beacon skb.
|
||||
*/
|
||||
dev_kfree_skb_any(entry->skb);
|
||||
entry->skb = NULL;
|
||||
}
|
||||
|
||||
static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
|
||||
const enum data_queue_qid queue)
|
||||
{
|
||||
|
@ -2355,72 +2390,6 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
|
|||
return tsf;
|
||||
}
|
||||
|
||||
static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
|
||||
struct queue_entry_priv_pci *entry_priv;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct txentry_desc txdesc;
|
||||
unsigned int beacon_base;
|
||||
u32 reg;
|
||||
|
||||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
|
||||
/*
|
||||
* Copy all TX descriptor information into txdesc,
|
||||
* after that we are free to use the skb->cb array
|
||||
* for our information.
|
||||
*/
|
||||
intf->beacon->skb = skb;
|
||||
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
|
||||
|
||||
entry_priv = intf->beacon->priv_data;
|
||||
memset(entry_priv->desc, 0, intf->beacon->queue->desc_size);
|
||||
|
||||
/*
|
||||
* Fill in skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = entry_priv->desc;
|
||||
skbdesc->desc_len = intf->beacon->queue->desc_size;
|
||||
skbdesc->entry = intf->beacon;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
/*
|
||||
* Write entire beacon with descriptor to register,
|
||||
* and kick the beacon generator.
|
||||
*/
|
||||
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
|
||||
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
|
||||
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
|
||||
skbdesc->desc, skbdesc->desc_len);
|
||||
rt2x00pci_register_multiwrite(rt2x00dev,
|
||||
beacon_base + skbdesc->desc_len,
|
||||
skb->data, skb->len);
|
||||
rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
/*
|
||||
* Clean up beacon skb.
|
||||
*/
|
||||
dev_kfree_skb_any(skb);
|
||||
intf->beacon->skb = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops rt61pci_mac80211_ops = {
|
||||
.tx = rt2x00mac_tx,
|
||||
.start = rt2x00mac_start,
|
||||
|
@ -2436,7 +2405,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
|
|||
.conf_tx = rt2x00mac_conf_tx,
|
||||
.get_tx_stats = rt2x00mac_get_tx_stats,
|
||||
.get_tsf = rt61pci_get_tsf,
|
||||
.beacon_update = rt61pci_beacon_update,
|
||||
};
|
||||
|
||||
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
|
||||
|
@ -2456,6 +2424,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
|
|||
.link_tuner = rt61pci_link_tuner,
|
||||
.write_tx_desc = rt61pci_write_tx_desc,
|
||||
.write_tx_data = rt2x00pci_write_tx_data,
|
||||
.write_beacon = rt61pci_write_beacon,
|
||||
.kick_tx_queue = rt61pci_kick_tx_queue,
|
||||
.fill_rxdone = rt61pci_fill_rxdone,
|
||||
.config_filter = rt61pci_config_filter,
|
||||
|
|
|
@ -1343,6 +1343,49 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
rt2x00_desc_write(txd, 0, word);
|
||||
}
|
||||
|
||||
/*
|
||||
* TX data initialization
|
||||
*/
|
||||
static void rt73usb_write_beacon(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
unsigned int beacon_base;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Add the descriptor in front of the skb.
|
||||
*/
|
||||
skb_push(entry->skb, entry->queue->desc_size);
|
||||
memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
|
||||
skbdesc->desc = entry->skb->data;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
/*
|
||||
* Write entire beacon with descriptor to register.
|
||||
*/
|
||||
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
|
||||
rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
|
||||
USB_VENDOR_REQUEST_OUT, beacon_base, 0,
|
||||
entry->skb->data, entry->skb->len,
|
||||
REGISTER_TIMEOUT32(entry->skb->len));
|
||||
|
||||
/*
|
||||
* Clean up the beacon skb.
|
||||
*/
|
||||
dev_kfree_skb(entry->skb);
|
||||
entry->skb = NULL;
|
||||
}
|
||||
|
||||
static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -1358,9 +1401,6 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
|
|||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
* TX data initialization
|
||||
*/
|
||||
static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
|
||||
const enum data_queue_qid queue)
|
||||
{
|
||||
|
@ -1958,73 +1998,6 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
|
|||
#define rt73usb_get_tsf NULL
|
||||
#endif
|
||||
|
||||
static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct txentry_desc txdesc;
|
||||
unsigned int beacon_base;
|
||||
u32 reg;
|
||||
|
||||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
|
||||
/*
|
||||
* Copy all TX descriptor information into txdesc,
|
||||
* after that we are free to use the skb->cb array
|
||||
* for our information.
|
||||
*/
|
||||
intf->beacon->skb = skb;
|
||||
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
|
||||
|
||||
/*
|
||||
* Add the descriptor in front of the skb.
|
||||
*/
|
||||
skb_push(skb, intf->beacon->queue->desc_size);
|
||||
memset(skb->data, 0, intf->beacon->queue->desc_size);
|
||||
|
||||
/*
|
||||
* Fill in skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = skb->data;
|
||||
skbdesc->desc_len = intf->beacon->queue->desc_size;
|
||||
skbdesc->entry = intf->beacon;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
/*
|
||||
* Write entire beacon with descriptor to register,
|
||||
* and kick the beacon generator.
|
||||
*/
|
||||
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
|
||||
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
|
||||
rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
|
||||
USB_VENDOR_REQUEST_OUT, beacon_base, 0,
|
||||
skb->data, skb->len,
|
||||
REGISTER_TIMEOUT32(skb->len));
|
||||
rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
/*
|
||||
* Clean up the beacon skb.
|
||||
*/
|
||||
dev_kfree_skb(skb);
|
||||
intf->beacon->skb = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops rt73usb_mac80211_ops = {
|
||||
.tx = rt2x00mac_tx,
|
||||
.start = rt2x00mac_start,
|
||||
|
@ -2040,7 +2013,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
|
|||
.conf_tx = rt2x00mac_conf_tx,
|
||||
.get_tx_stats = rt2x00mac_get_tx_stats,
|
||||
.get_tsf = rt73usb_get_tsf,
|
||||
.beacon_update = rt73usb_beacon_update,
|
||||
};
|
||||
|
||||
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
|
||||
|
@ -2058,6 +2030,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
|
|||
.link_tuner = rt73usb_link_tuner,
|
||||
.write_tx_desc = rt73usb_write_tx_desc,
|
||||
.write_tx_data = rt2x00usb_write_tx_data,
|
||||
.write_beacon = rt73usb_write_beacon,
|
||||
.get_tx_data_len = rt73usb_get_tx_data_len,
|
||||
.kick_tx_queue = rt73usb_kick_tx_queue,
|
||||
.fill_rxdone = rt73usb_fill_rxdone,
|
||||
|
|
|
@ -430,8 +430,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
|
|||
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_iowrite32(priv, &priv->map->ANAPARAM,
|
||||
RTL8187_RTL8225_ANAPARAM_ON);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
|
||||
RTL8187_RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg &
|
||||
~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
|
||||
|
@ -453,8 +455,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
|
|||
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_iowrite32(priv, &priv->map->ANAPARAM,
|
||||
RTL8187_RTL8225_ANAPARAM_ON);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
|
||||
RTL8187_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);
|
||||
|
@ -566,9 +570,12 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
|
|||
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_iowrite32(priv, &priv->map->ANAPARAM2,
|
||||
RTL8187B_RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
|
||||
RTL8187B_RTL8225_ANAPARAM_ON);
|
||||
rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
|
||||
RTL8187B_RTL8225_ANAPARAM3_ON);
|
||||
|
||||
rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10);
|
||||
reg = rtl818x_ioread8(priv, (u8 *)0xFF62);
|
||||
|
@ -1180,7 +1187,7 @@ static struct usb_driver rtl8187_driver = {
|
|||
.name = KBUILD_MODNAME,
|
||||
.id_table = rtl8187_table,
|
||||
.probe = rtl8187_probe,
|
||||
.disconnect = rtl8187_disconnect,
|
||||
.disconnect = __devexit_p(rtl8187_disconnect),
|
||||
};
|
||||
|
||||
static int __init rtl8187_init(void)
|
||||
|
|
|
@ -307,7 +307,8 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
|
|||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
|
||||
reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
|
||||
RTL8187_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);
|
||||
|
@ -560,7 +561,8 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
|
|||
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
|
||||
reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
|
||||
RTL8187_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);
|
||||
|
@ -913,8 +915,19 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev)
|
|||
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->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
|
||||
if (!priv->is_rtl8187b) {
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
|
||||
RTL8187_RTL8225_ANAPARAM2_OFF);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
|
||||
RTL8187_RTL8225_ANAPARAM_OFF);
|
||||
} else {
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
|
||||
RTL8187B_RTL8225_ANAPARAM2_OFF);
|
||||
rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
|
||||
RTL8187B_RTL8225_ANAPARAM_OFF);
|
||||
rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
|
||||
RTL8187B_RTL8225_ANAPARAM3_OFF);
|
||||
}
|
||||
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
|
||||
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,17 @@
|
|||
#ifndef RTL8187_RTL8225_H
|
||||
#define RTL8187_RTL8225_H
|
||||
|
||||
#define RTL8225_ANAPARAM_ON 0xa0000a59
|
||||
#define RTL8225_ANAPARAM2_ON 0x860c7312
|
||||
#define RTL8225_ANAPARAM_OFF 0xa00beb59
|
||||
#define RTL8225_ANAPARAM2_OFF 0x840dec11
|
||||
#define RTL8187_RTL8225_ANAPARAM_ON 0xa0000a59
|
||||
#define RTL8187_RTL8225_ANAPARAM2_ON 0x860c7312
|
||||
#define RTL8187_RTL8225_ANAPARAM_OFF 0xa00beb59
|
||||
#define RTL8187_RTL8225_ANAPARAM2_OFF 0x840dec11
|
||||
|
||||
#define RTL8187B_RTL8225_ANAPARAM_ON 0x45090658
|
||||
#define RTL8187B_RTL8225_ANAPARAM2_ON 0x727f3f52
|
||||
#define RTL8187B_RTL8225_ANAPARAM3_ON 0x00
|
||||
#define RTL8187B_RTL8225_ANAPARAM_OFF 0x55480658
|
||||
#define RTL8187B_RTL8225_ANAPARAM2_OFF 0x72003f50
|
||||
#define RTL8187B_RTL8225_ANAPARAM3_OFF 0x00
|
||||
|
||||
const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *);
|
||||
|
||||
|
|
|
@ -728,15 +728,19 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
|
|||
if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
|
||||
mac->type == IEEE80211_IF_TYPE_IBSS) {
|
||||
associated = true;
|
||||
if (conf->beacon) {
|
||||
r = zd_mac_config_beacon(hw, conf->beacon);
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON) {
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
|
||||
|
||||
if (!beacon)
|
||||
return -ENOMEM;
|
||||
r = zd_mac_config_beacon(hw, 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);
|
||||
kfree_skb(beacon);
|
||||
}
|
||||
} else
|
||||
associated = is_valid_ether_addr(conf->bssid);
|
||||
|
@ -890,17 +894,6 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
static int zd_op_beacon_update(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct zd_mac *mac = zd_hw_mac(hw);
|
||||
zd_mac_config_beacon(hw, skb);
|
||||
kfree_skb(skb);
|
||||
zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
|
||||
hw->conf.beacon_int);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops zd_ops = {
|
||||
.tx = zd_op_tx,
|
||||
.start = zd_op_start,
|
||||
|
@ -911,7 +904,6 @@ static const struct ieee80211_ops zd_ops = {
|
|||
.config_interface = zd_op_config_interface,
|
||||
.configure_filter = zd_op_configure_filter,
|
||||
.bss_info_changed = zd_op_bss_info_changed,
|
||||
.beacon_update = zd_op_beacon_update,
|
||||
};
|
||||
|
||||
struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <linux/ssb/ssb_regs.h>
|
||||
|
||||
|
|
|
@ -115,17 +115,17 @@ enum ieee80211_max_queues {
|
|||
* The information provided in this structure is required for QoS
|
||||
* transmit queue configuration. Cf. IEEE 802.11 7.3.2.29.
|
||||
*
|
||||
* @aifs: arbitration interface space [0..255, -1: use default]
|
||||
* @cw_min: minimum contention window [will be a value of the form
|
||||
* 2^n-1 in the range 1..1023; 0: use default]
|
||||
* @aifs: arbitration interface space [0..255]
|
||||
* @cw_min: minimum contention window [a value of the form
|
||||
* 2^n-1 in the range 1..32767]
|
||||
* @cw_max: maximum contention window [like @cw_min]
|
||||
* @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
|
||||
*/
|
||||
struct ieee80211_tx_queue_params {
|
||||
s16 aifs;
|
||||
u16 txop;
|
||||
u16 cw_min;
|
||||
u16 cw_max;
|
||||
u16 txop;
|
||||
u8 aifs;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -239,6 +239,17 @@ struct ieee80211_bss_conf {
|
|||
* is for the whole aggregation.
|
||||
* @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
|
||||
* so consider using block ack request (BAR).
|
||||
* @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
|
||||
* number to this frame, taking care of not overwriting the fragment
|
||||
* number and increasing the sequence number only when the
|
||||
* IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly
|
||||
* assign sequence numbers to QoS-data frames but cannot do so correctly
|
||||
* for non-QoS-data and management frames because beacons need them from
|
||||
* that counter as well and mac80211 cannot guarantee proper sequencing.
|
||||
* If this flag is set, the driver should instruct the hardware to
|
||||
* assign a sequence number to the frame or assign one itself. Cf. IEEE
|
||||
* 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
|
||||
* beacons always be clear for frames without a sequence number field.
|
||||
*/
|
||||
enum mac80211_tx_control_flags {
|
||||
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
|
||||
|
@ -265,6 +276,7 @@ enum mac80211_tx_control_flags {
|
|||
IEEE80211_TX_STAT_ACK = BIT(21),
|
||||
IEEE80211_TX_STAT_AMPDU = BIT(22),
|
||||
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(23),
|
||||
IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(24),
|
||||
};
|
||||
|
||||
|
||||
|
@ -407,11 +419,13 @@ struct ieee80211_rx_status {
|
|||
* @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time
|
||||
* @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
|
||||
* @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
|
||||
* @IEEE80211_CONF_PS: Enable 802.11 power save mode
|
||||
*/
|
||||
enum ieee80211_conf_flags {
|
||||
IEEE80211_CONF_SHORT_SLOT_TIME = (1<<0),
|
||||
IEEE80211_CONF_RADIOTAP = (1<<1),
|
||||
IEEE80211_CONF_SUPPORT_HT_MODE = (1<<2),
|
||||
IEEE80211_CONF_PS = (1<<3),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -526,34 +540,39 @@ struct ieee80211_if_init_conf {
|
|||
void *mac_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_if_conf_change - interface config change flags
|
||||
*
|
||||
* @IEEE80211_IFCC_BSSID: The BSSID changed.
|
||||
* @IEEE80211_IFCC_SSID: The SSID changed.
|
||||
* @IEEE80211_IFCC_BEACON: The beacon for this interface changed
|
||||
* (currently AP and MESH only), use ieee80211_beacon_get().
|
||||
*/
|
||||
enum ieee80211_if_conf_change {
|
||||
IEEE80211_IFCC_BSSID = BIT(0),
|
||||
IEEE80211_IFCC_SSID = BIT(1),
|
||||
IEEE80211_IFCC_BEACON = BIT(2),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_if_conf - configuration of an interface
|
||||
*
|
||||
* @type: type of the interface. This is always the same as was specified in
|
||||
* &struct ieee80211_if_init_conf. The type of an interface never changes
|
||||
* during the life of the interface; this field is present only for
|
||||
* convenience.
|
||||
* @changed: parameters that have changed, see &enum ieee80211_if_conf_change.
|
||||
* @bssid: BSSID of the network we are associated to/creating.
|
||||
* @ssid: used (together with @ssid_len) by drivers for hardware that
|
||||
* generate beacons independently. The pointer is valid only during the
|
||||
* config_interface() call, so copy the value somewhere if you need
|
||||
* it.
|
||||
* @ssid_len: length of the @ssid field.
|
||||
* @beacon: beacon template. Valid only if @host_gen_beacon_template in
|
||||
* &struct ieee80211_hw is set. The driver is responsible of freeing
|
||||
* the sk_buff.
|
||||
* @beacon_control: tx_control for the beacon template, this field is only
|
||||
* valid when the @beacon field was set.
|
||||
*
|
||||
* This structure is passed to the config_interface() callback of
|
||||
* &struct ieee80211_hw.
|
||||
*/
|
||||
struct ieee80211_if_conf {
|
||||
int type;
|
||||
u32 changed;
|
||||
u8 *bssid;
|
||||
u8 *ssid;
|
||||
size_t ssid_len;
|
||||
struct sk_buff *beacon;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -681,15 +700,6 @@ enum ieee80211_tkip_key_type {
|
|||
* any particular flags. There are some exceptions to this rule,
|
||||
* however, so you are advised to review these flags carefully.
|
||||
*
|
||||
* @IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE:
|
||||
* The device only needs to be supplied with a beacon template.
|
||||
* If you need the host to generate each beacon then don't use
|
||||
* this flag and call ieee80211_beacon_get() when you need the
|
||||
* next beacon frame. Note that if you set this flag, you must
|
||||
* implement the set_tim() callback for powersave mode to work
|
||||
* properly.
|
||||
* This flag is only relevant for access-point mode.
|
||||
*
|
||||
* @IEEE80211_HW_RX_INCLUDES_FCS:
|
||||
* Indicates that received frames passed to the stack include
|
||||
* the FCS at the end.
|
||||
|
@ -1149,17 +1159,6 @@ enum ieee80211_ampdu_mlme_action {
|
|||
* function is optional if the firmware/hardware takes full care of
|
||||
* TSF synchronization.
|
||||
*
|
||||
* @beacon_update: Setup beacon data for IBSS beacons. Unlike access point,
|
||||
* IBSS uses a fixed beacon frame which is configured using this
|
||||
* function.
|
||||
* If the driver returns success (0) from this callback, it owns
|
||||
* the skb. That means the driver is responsible to kfree_skb() it.
|
||||
* The control structure is not dynamically allocated. That means the
|
||||
* driver does not own the pointer and if it needs it somewhere
|
||||
* outside of the context of this function, it must copy it
|
||||
* somewhere else.
|
||||
* This handler is required only for IBSS mode.
|
||||
*
|
||||
* @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
|
||||
* This is needed only for IBSS mode and the result of this function is
|
||||
* used to determine whether to reply to Probe Requests.
|
||||
|
@ -1217,8 +1216,6 @@ struct ieee80211_ops {
|
|||
struct ieee80211_tx_queue_stats *stats);
|
||||
u64 (*get_tsf)(struct ieee80211_hw *hw);
|
||||
void (*reset_tsf)(struct ieee80211_hw *hw);
|
||||
int (*beacon_update)(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb);
|
||||
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
||||
int (*ampdu_action)(struct ieee80211_hw *hw,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
|
|
|
@ -318,7 +318,7 @@ static struct attribute_group netstat_group = {
|
|||
.attrs = netstat_attrs,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_WIRELESS_EXT
|
||||
#ifdef CONFIG_WIRELESS_EXT_SYSFS
|
||||
/* helper function that does all the locking etc for wireless stats */
|
||||
static ssize_t wireless_show(struct device *d, char *buf,
|
||||
ssize_t (*format)(const struct iw_statistics *,
|
||||
|
@ -459,7 +459,7 @@ int netdev_register_kobject(struct net_device *net)
|
|||
#ifdef CONFIG_SYSFS
|
||||
*groups++ = &netstat_group;
|
||||
|
||||
#ifdef CONFIG_WIRELESS_EXT
|
||||
#ifdef CONFIG_WIRELESS_EXT_SYSFS
|
||||
if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
|
||||
*groups++ = &wireless_group;
|
||||
#endif
|
||||
|
|
|
@ -50,14 +50,11 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
int err;
|
||||
|
||||
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
|
||||
return -ENODEV;
|
||||
|
||||
itype = nl80211_type_to_mac80211_type(type);
|
||||
if (itype == IEEE80211_IF_TYPE_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
err = ieee80211_if_add(local->mdev, name, &dev, itype, params);
|
||||
err = ieee80211_if_add(local, name, &dev, itype, params);
|
||||
if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
|
||||
return err;
|
||||
|
||||
|
@ -68,54 +65,41 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
|||
|
||||
static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct net_device *dev;
|
||||
char *name;
|
||||
|
||||
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
|
||||
return -ENODEV;
|
||||
|
||||
/* we're under RTNL */
|
||||
dev = __dev_get_by_index(&init_net, ifindex);
|
||||
if (!dev)
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
|
||||
name = dev->name;
|
||||
ieee80211_if_remove(dev);
|
||||
|
||||
return ieee80211_if_remove(local->mdev, name, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct net_device *dev;
|
||||
enum ieee80211_if_types itype;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
|
||||
return -ENODEV;
|
||||
int ret;
|
||||
|
||||
/* we're under RTNL */
|
||||
dev = __dev_get_by_index(&init_net, ifindex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (netif_running(dev))
|
||||
return -EBUSY;
|
||||
|
||||
itype = nl80211_type_to_mac80211_type(type);
|
||||
if (itype == IEEE80211_IF_TYPE_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ieee80211_if_reinit(dev);
|
||||
ieee80211_if_set_type(dev, itype);
|
||||
ret = ieee80211_if_change_type(sdata, itype);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
|
||||
ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
|
||||
|
@ -485,7 +469,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
kfree(old);
|
||||
|
||||
return ieee80211_if_config_beacon(sdata->dev);
|
||||
return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
|
||||
}
|
||||
|
||||
static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
@ -539,7 +523,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
|
|||
synchronize_rcu();
|
||||
kfree(old);
|
||||
|
||||
return ieee80211_if_config_beacon(dev);
|
||||
return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
|
||||
}
|
||||
|
||||
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
|
||||
|
|
|
@ -70,16 +70,6 @@ DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
|
|||
|
||||
/* statistics stuff */
|
||||
|
||||
static inline int rtnl_lock_local(struct ieee80211_local *local)
|
||||
{
|
||||
rtnl_lock();
|
||||
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
|
||||
rtnl_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \
|
||||
DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
|
||||
|
||||
|
@ -96,10 +86,7 @@ static ssize_t format_devstat_counter(struct ieee80211_local *local,
|
|||
if (!local->ops->get_stats)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
res = rtnl_lock_local(local);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
rtnl_lock();
|
||||
res = local->ops->get_stats(local_to_hw(local), &stats);
|
||||
rtnl_unlock();
|
||||
if (!res)
|
||||
|
|
|
@ -156,6 +156,8 @@ static const struct file_operations name##_ops = { \
|
|||
|
||||
/* common attributes */
|
||||
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
|
||||
IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
|
||||
IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
|
||||
|
||||
/* STA/IBSS attributes */
|
||||
IEEE80211_IF_FILE(state, u.sta.state, DEC);
|
||||
|
@ -191,8 +193,6 @@ __IEEE80211_IF_FILE(flags);
|
|||
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
|
||||
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
|
||||
IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
|
||||
IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
|
||||
IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC);
|
||||
|
||||
static ssize_t ieee80211_if_fmt_num_buffered_multicast(
|
||||
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
|
||||
|
@ -248,6 +248,9 @@ IEEE80211_IF_WFILE(min_discovery_timeout,
|
|||
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, sta);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, ap);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
|
||||
|
||||
DEBUGFS_ADD(state, sta);
|
||||
DEBUGFS_ADD(bssid, sta);
|
||||
DEBUGFS_ADD(prev_bssid, sta);
|
||||
|
@ -268,23 +271,29 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
|||
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, ap);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, ap);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
|
||||
|
||||
DEBUGFS_ADD(num_sta_ps, ap);
|
||||
DEBUGFS_ADD(dtim_count, ap);
|
||||
DEBUGFS_ADD(num_beacons, ap);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, ap);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
|
||||
DEBUGFS_ADD(num_buffered_multicast, ap);
|
||||
}
|
||||
|
||||
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, wds);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, ap);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
|
||||
|
||||
DEBUGFS_ADD(peer, wds);
|
||||
}
|
||||
|
||||
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, vlan);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, ap);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
|
||||
}
|
||||
|
||||
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -372,6 +381,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
|
|||
static void del_sta_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_DEL(drop_unencrypted, sta);
|
||||
DEBUGFS_DEL(force_unicast_rateidx, ap);
|
||||
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
|
||||
|
||||
DEBUGFS_DEL(state, sta);
|
||||
DEBUGFS_DEL(bssid, sta);
|
||||
DEBUGFS_DEL(prev_bssid, sta);
|
||||
|
@ -392,23 +404,29 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
|
|||
static void del_ap_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_DEL(drop_unencrypted, ap);
|
||||
DEBUGFS_DEL(force_unicast_rateidx, ap);
|
||||
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
|
||||
|
||||
DEBUGFS_DEL(num_sta_ps, ap);
|
||||
DEBUGFS_DEL(dtim_count, ap);
|
||||
DEBUGFS_DEL(num_beacons, ap);
|
||||
DEBUGFS_DEL(force_unicast_rateidx, ap);
|
||||
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
|
||||
DEBUGFS_DEL(num_buffered_multicast, ap);
|
||||
}
|
||||
|
||||
static void del_wds_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_DEL(drop_unencrypted, wds);
|
||||
DEBUGFS_DEL(force_unicast_rateidx, ap);
|
||||
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
|
||||
|
||||
DEBUGFS_DEL(peer, wds);
|
||||
}
|
||||
|
||||
static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_DEL(drop_unencrypted, vlan);
|
||||
DEBUGFS_DEL(force_unicast_rateidx, ap);
|
||||
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
|
||||
}
|
||||
|
||||
static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -458,12 +476,12 @@ static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void del_files(struct ieee80211_sub_if_data *sdata, int type)
|
||||
static void del_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
if (!sdata->debugfsdir)
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
switch (sdata->vif.type) {
|
||||
case IEEE80211_IF_TYPE_MESH_POINT:
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
del_mesh_stats(sdata);
|
||||
|
@ -503,29 +521,23 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
|
|||
sprintf(buf, "netdev:%s", sdata->dev->name);
|
||||
sdata->debugfsdir = debugfs_create_dir(buf,
|
||||
sdata->local->hw.wiphy->debugfsdir);
|
||||
add_files(sdata);
|
||||
}
|
||||
|
||||
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
del_files(sdata, sdata->vif.type);
|
||||
del_files(sdata);
|
||||
debugfs_remove(sdata->debugfsdir);
|
||||
sdata->debugfsdir = NULL;
|
||||
}
|
||||
|
||||
void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
|
||||
int oldtype)
|
||||
{
|
||||
del_files(sdata, oldtype);
|
||||
add_files(sdata);
|
||||
}
|
||||
|
||||
static int netdev_notify(struct notifier_block *nb,
|
||||
unsigned long state,
|
||||
void *ndev)
|
||||
{
|
||||
struct net_device *dev = ndev;
|
||||
struct dentry *dir;
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
char buf[10+IFNAMSIZ];
|
||||
|
||||
if (state != NETDEV_CHANGENAME)
|
||||
|
@ -537,6 +549,8 @@ static int netdev_notify(struct notifier_block *nb,
|
|||
if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
|
||||
return 0;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
sprintf(buf, "netdev:%s", dev->name);
|
||||
dir = sdata->debugfsdir;
|
||||
if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
|
||||
int oldtype);
|
||||
void ieee80211_debugfs_netdev_init(void);
|
||||
void ieee80211_debugfs_netdev_exit(void);
|
||||
#else
|
||||
|
@ -17,9 +15,6 @@ static inline void ieee80211_debugfs_add_netdev(
|
|||
static inline void ieee80211_debugfs_remove_netdev(
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{}
|
||||
static inline void ieee80211_debugfs_change_if_type(
|
||||
struct ieee80211_sub_if_data *sdata, int oldtype)
|
||||
{}
|
||||
static inline void ieee80211_debugfs_netdev_init(void)
|
||||
{}
|
||||
|
||||
|
|
|
@ -237,8 +237,6 @@ struct ieee80211_if_ap {
|
|||
struct sk_buff_head ps_bc_buf;
|
||||
atomic_t num_sta_ps; /* number of stations in PS mode */
|
||||
int dtim_count;
|
||||
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
|
||||
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
|
||||
int num_beacons; /* number of TXed beacon frames for this BSS */
|
||||
};
|
||||
|
||||
|
@ -248,7 +246,6 @@ struct ieee80211_if_wds {
|
|||
};
|
||||
|
||||
struct ieee80211_if_vlan {
|
||||
struct ieee80211_sub_if_data *ap;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
@ -422,8 +419,6 @@ struct ieee80211_sub_if_data {
|
|||
*/
|
||||
u64 basic_rates;
|
||||
|
||||
u16 sequence;
|
||||
|
||||
/* Fragment table for host-based reassembly */
|
||||
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
|
||||
unsigned int fragment_next;
|
||||
|
@ -432,16 +427,18 @@ struct ieee80211_sub_if_data {
|
|||
struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
|
||||
struct ieee80211_key *default_key;
|
||||
|
||||
/*
|
||||
* BSS configuration for this interface.
|
||||
*
|
||||
* FIXME: I feel bad putting this here when we already have a
|
||||
* bss pointer, but the bss pointer is just wrong when
|
||||
* you have multiple virtual STA mode interfaces...
|
||||
* This needs to be fixed.
|
||||
*/
|
||||
/* BSS configuration for this interface. */
|
||||
struct ieee80211_bss_conf bss_conf;
|
||||
struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
|
||||
|
||||
/*
|
||||
* AP this belongs to: self in AP mode and
|
||||
* corresponding AP in VLAN mode, NULL for
|
||||
* all others (might be needed later in IBSS)
|
||||
*/
|
||||
struct ieee80211_if_ap *bss;
|
||||
|
||||
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
|
||||
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
|
||||
|
||||
union {
|
||||
struct ieee80211_if_ap ap;
|
||||
|
@ -533,8 +530,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
|
|||
return container_of(p, struct ieee80211_sub_if_data, vif);
|
||||
}
|
||||
|
||||
#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
|
||||
|
||||
enum {
|
||||
IEEE80211_RX_MSG = 1,
|
||||
IEEE80211_TX_STATUS_MSG = 2,
|
||||
|
@ -561,12 +556,6 @@ struct ieee80211_local {
|
|||
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
|
||||
int tx_headroom; /* required headroom for hardware/radiotap */
|
||||
|
||||
enum {
|
||||
IEEE80211_DEV_UNINITIALIZED = 0,
|
||||
IEEE80211_DEV_REGISTERED,
|
||||
IEEE80211_DEV_UNREGISTERED,
|
||||
} reg_state;
|
||||
|
||||
/* Tasklet and skb queue to process calls from IRQ mode. All frames
|
||||
* added to skb_queue will be processed, but frames in
|
||||
* skb_queue_unreliable may be dropped if the total length of these
|
||||
|
@ -760,6 +749,16 @@ static inline int ieee80211_is_multiqueue(struct ieee80211_local *local)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline struct ieee80211_sub_if_data *
|
||||
IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
|
||||
BUG_ON(!local || local->mdev == dev);
|
||||
|
||||
return netdev_priv(dev);
|
||||
}
|
||||
|
||||
/* this struct represents 802.11n's RA/TID combination */
|
||||
struct ieee80211_ra_tid {
|
||||
u8 ra[ETH_ALEN];
|
||||
|
@ -853,10 +852,8 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
|
|||
|
||||
/* ieee80211.c */
|
||||
int ieee80211_hw_config(struct ieee80211_local *local);
|
||||
int ieee80211_if_config(struct net_device *dev);
|
||||
int ieee80211_if_config_beacon(struct net_device *dev);
|
||||
int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
|
||||
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
|
||||
void ieee80211_if_setup(struct net_device *dev);
|
||||
u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
|
||||
struct ieee80211_ht_info *req_ht_cap,
|
||||
struct ieee80211_ht_bss_info *req_bss_cap);
|
||||
|
@ -883,8 +880,8 @@ int ieee80211_sta_scan_results(struct net_device *dev,
|
|||
ieee80211_rx_result ieee80211_sta_rx_scan(
|
||||
struct net_device *dev, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
void ieee80211_rx_bss_list_init(struct net_device *dev);
|
||||
void ieee80211_rx_bss_list_deinit(struct net_device *dev);
|
||||
void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
|
||||
void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
|
||||
int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
|
||||
struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
|
||||
struct sk_buff *skb, u8 *bssid,
|
||||
|
@ -925,17 +922,15 @@ static inline void ieee80211_start_mesh(struct net_device *dev)
|
|||
{}
|
||||
#endif
|
||||
|
||||
/* ieee80211_iface.c */
|
||||
int ieee80211_if_add(struct net_device *dev, const char *name,
|
||||
struct net_device **new_dev, int type,
|
||||
/* interface handling */
|
||||
void ieee80211_if_setup(struct net_device *dev);
|
||||
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
struct net_device **new_dev, enum ieee80211_if_types type,
|
||||
struct vif_params *params);
|
||||
void ieee80211_if_set_type(struct net_device *dev, int type);
|
||||
void ieee80211_if_reinit(struct net_device *dev);
|
||||
void __ieee80211_if_del(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
|
||||
void ieee80211_if_free(struct net_device *dev);
|
||||
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_if_types type);
|
||||
void ieee80211_if_remove(struct net_device *dev);
|
||||
void ieee80211_remove_interfaces(struct ieee80211_local *local);
|
||||
|
||||
/* tx handling */
|
||||
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -17,37 +18,164 @@
|
|||
#include "debugfs_netdev.h"
|
||||
#include "mesh.h"
|
||||
|
||||
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
|
||||
/*
|
||||
* Called when the netdev is removed or, by the code below, before
|
||||
* the interface type changes.
|
||||
*/
|
||||
static void ieee80211_teardown_sdata(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct beacon_data *beacon;
|
||||
struct sk_buff *skb;
|
||||
int flushed;
|
||||
int i;
|
||||
|
||||
/* Default values for sub-interface parameters */
|
||||
sdata->drop_unencrypted = 0;
|
||||
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
|
||||
skb_queue_head_init(&sdata->fragments[i].skb_list);
|
||||
ieee80211_debugfs_remove_netdev(sdata);
|
||||
|
||||
INIT_LIST_HEAD(&sdata->key_list);
|
||||
}
|
||||
|
||||
static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
int i;
|
||||
/* free extra data */
|
||||
ieee80211_free_keys(sdata);
|
||||
|
||||
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
|
||||
__skb_queue_purge(&sdata->fragments[i].skb_list);
|
||||
sdata->fragment_next = 0;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case IEEE80211_IF_TYPE_AP:
|
||||
beacon = sdata->u.ap.beacon;
|
||||
rcu_assign_pointer(sdata->u.ap.beacon, NULL);
|
||||
synchronize_rcu();
|
||||
kfree(beacon);
|
||||
|
||||
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
|
||||
local->total_ps_buffered--;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MESH_POINT:
|
||||
/* Allow compiler to elide mesh_rmc_free call. */
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
mesh_rmc_free(dev);
|
||||
/* fall through */
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
case IEEE80211_IF_TYPE_IBSS:
|
||||
kfree(sdata->u.sta.extra_ie);
|
||||
kfree(sdata->u.sta.assocreq_ies);
|
||||
kfree(sdata->u.sta.assocresp_ies);
|
||||
kfree_skb(sdata->u.sta.probe_resp);
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_INVALID:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
flushed = sta_info_flush(local, sdata);
|
||||
WARN_ON(flushed);
|
||||
}
|
||||
|
||||
/* Must be called with rtnl lock held. */
|
||||
int ieee80211_if_add(struct net_device *dev, const char *name,
|
||||
struct net_device **new_dev, int type,
|
||||
/*
|
||||
* Helper function to initialise an interface to a specific type.
|
||||
*/
|
||||
static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_if_types type)
|
||||
{
|
||||
struct ieee80211_if_sta *ifsta;
|
||||
|
||||
/* clear type-dependent union */
|
||||
memset(&sdata->u, 0, sizeof(sdata->u));
|
||||
|
||||
/* and set some type-dependent values */
|
||||
sdata->vif.type = type;
|
||||
|
||||
/* only monitor differs */
|
||||
sdata->dev->type = ARPHRD_ETHER;
|
||||
|
||||
switch (type) {
|
||||
case IEEE80211_IF_TYPE_AP:
|
||||
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
|
||||
INIT_LIST_HEAD(&sdata->u.ap.vlans);
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MESH_POINT:
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
case IEEE80211_IF_TYPE_IBSS:
|
||||
ifsta = &sdata->u.sta;
|
||||
INIT_WORK(&ifsta->work, ieee80211_sta_work);
|
||||
setup_timer(&ifsta->timer, ieee80211_sta_timer,
|
||||
(unsigned long) sdata);
|
||||
skb_queue_head_init(&ifsta->skb_queue);
|
||||
|
||||
ifsta->capab = WLAN_CAPABILITY_ESS;
|
||||
ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
|
||||
IEEE80211_AUTH_ALG_SHARED_KEY;
|
||||
ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
|
||||
IEEE80211_STA_AUTO_BSSID_SEL |
|
||||
IEEE80211_STA_AUTO_CHANNEL_SEL;
|
||||
if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
|
||||
ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
ieee80211_mesh_init_sdata(sdata);
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP;
|
||||
sdata->dev->hard_start_xmit = ieee80211_monitor_start_xmit;
|
||||
sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
|
||||
MONITOR_FLAG_OTHER_BSS;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_INVALID:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
ieee80211_debugfs_add_netdev(sdata);
|
||||
}
|
||||
|
||||
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_if_types type)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (type == sdata->vif.type)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We could, here, on changes between IBSS/STA/MESH modes,
|
||||
* invoke an MLME function instead that disassociates etc.
|
||||
* and goes into the requested mode.
|
||||
*/
|
||||
|
||||
if (netif_running(sdata->dev))
|
||||
return -EBUSY;
|
||||
|
||||
/* Purge and reset type-dependent state. */
|
||||
ieee80211_teardown_sdata(sdata->dev);
|
||||
ieee80211_setup_sdata(sdata, type);
|
||||
|
||||
/* reset some values that shouldn't be kept across type changes */
|
||||
sdata->basic_rates = 0;
|
||||
sdata->drop_unencrypted = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
struct net_device **new_dev, enum ieee80211_if_types type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct net_device *ndev;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = NULL;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
|
||||
name, ieee80211_if_setup);
|
||||
if (!ndev)
|
||||
|
@ -67,26 +195,33 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
|
|||
goto fail;
|
||||
|
||||
memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
|
||||
ndev->base_addr = dev->base_addr;
|
||||
ndev->irq = dev->irq;
|
||||
ndev->mem_start = dev->mem_start;
|
||||
ndev->mem_end = dev->mem_end;
|
||||
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
|
||||
/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
|
||||
sdata = netdev_priv(ndev);
|
||||
ndev->ieee80211_ptr = &sdata->wdev;
|
||||
|
||||
/* initialise type-independent data */
|
||||
sdata->wdev.wiphy = local->hw.wiphy;
|
||||
sdata->vif.type = IEEE80211_IF_TYPE_AP;
|
||||
sdata->dev = ndev;
|
||||
sdata->local = local;
|
||||
ieee80211_if_sdata_init(sdata);
|
||||
sdata->dev = ndev;
|
||||
|
||||
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
|
||||
skb_queue_head_init(&sdata->fragments[i].skb_list);
|
||||
|
||||
INIT_LIST_HEAD(&sdata->key_list);
|
||||
|
||||
sdata->force_unicast_rateidx = -1;
|
||||
sdata->max_ratectrl_rateidx = -1;
|
||||
|
||||
/* setup type-dependent data */
|
||||
ieee80211_setup_sdata(sdata, type);
|
||||
|
||||
ret = register_netdevice(ndev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ieee80211_debugfs_add_netdev(sdata);
|
||||
ieee80211_if_set_type(ndev, type);
|
||||
ndev->uninit = ieee80211_teardown_sdata;
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
params && params->mesh_id_len)
|
||||
|
@ -94,11 +229,6 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
|
|||
params->mesh_id_len,
|
||||
params->mesh_id);
|
||||
|
||||
/* we're under RTNL so all this is fine */
|
||||
if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
|
||||
__ieee80211_if_del(local, sdata);
|
||||
return -ENODEV;
|
||||
}
|
||||
list_add_tail_rcu(&sdata->list, &local->interfaces);
|
||||
|
||||
if (new_dev)
|
||||
|
@ -106,218 +236,34 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
|
|||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
free_netdev(ndev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ieee80211_if_set_type(struct net_device *dev, int type)
|
||||
void ieee80211_if_remove(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
int oldtype = sdata->vif.type;
|
||||
|
||||
/*
|
||||
* We need to call this function on the master interface
|
||||
* which already has a hard_start_xmit routine assigned
|
||||
* which must not be changed.
|
||||
*/
|
||||
if (dev != sdata->local->mdev)
|
||||
dev->hard_start_xmit = ieee80211_subif_start_xmit;
|
||||
|
||||
/*
|
||||
* Called even when register_netdevice fails, it would
|
||||
* oops if assigned before initialising the rest.
|
||||
*/
|
||||
dev->uninit = ieee80211_if_reinit;
|
||||
|
||||
/* most have no BSS pointer */
|
||||
sdata->bss = NULL;
|
||||
sdata->vif.type = type;
|
||||
|
||||
sdata->basic_rates = 0;
|
||||
|
||||
switch (type) {
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
/* nothing special */
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
sdata->u.vlan.ap = NULL;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_AP:
|
||||
sdata->u.ap.force_unicast_rateidx = -1;
|
||||
sdata->u.ap.max_ratectrl_rateidx = -1;
|
||||
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
|
||||
sdata->bss = &sdata->u.ap;
|
||||
INIT_LIST_HEAD(&sdata->u.ap.vlans);
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MESH_POINT:
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
case IEEE80211_IF_TYPE_IBSS: {
|
||||
struct ieee80211_sub_if_data *msdata;
|
||||
struct ieee80211_if_sta *ifsta;
|
||||
|
||||
ifsta = &sdata->u.sta;
|
||||
INIT_WORK(&ifsta->work, ieee80211_sta_work);
|
||||
setup_timer(&ifsta->timer, ieee80211_sta_timer,
|
||||
(unsigned long) sdata);
|
||||
skb_queue_head_init(&ifsta->skb_queue);
|
||||
|
||||
ifsta->capab = WLAN_CAPABILITY_ESS;
|
||||
ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
|
||||
IEEE80211_AUTH_ALG_SHARED_KEY;
|
||||
ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
|
||||
IEEE80211_STA_AUTO_BSSID_SEL |
|
||||
IEEE80211_STA_AUTO_CHANNEL_SEL;
|
||||
if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
|
||||
ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
|
||||
|
||||
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
|
||||
sdata->bss = &msdata->u.ap;
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
ieee80211_mesh_init_sdata(sdata);
|
||||
break;
|
||||
}
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
dev->type = ARPHRD_IEEE80211_RADIOTAP;
|
||||
dev->hard_start_xmit = ieee80211_monitor_start_xmit;
|
||||
sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
|
||||
MONITOR_FLAG_OTHER_BSS;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_INVALID:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
ieee80211_debugfs_change_if_type(sdata, oldtype);
|
||||
}
|
||||
|
||||
/* Must be called with rtnl lock held. */
|
||||
void ieee80211_if_reinit(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sk_buff *skb;
|
||||
int flushed;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
ieee80211_free_keys(sdata);
|
||||
|
||||
ieee80211_if_sdata_deinit(sdata);
|
||||
|
||||
/* Need to handle mesh specially to allow eliding the function call */
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
mesh_rmc_free(dev);
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case IEEE80211_IF_TYPE_INVALID:
|
||||
/* cannot happen */
|
||||
WARN_ON(1);
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_AP: {
|
||||
/* Remove all virtual interfaces that use this BSS
|
||||
* as their sdata->bss */
|
||||
struct ieee80211_sub_if_data *tsdata, *n;
|
||||
struct beacon_data *beacon;
|
||||
|
||||
list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
|
||||
if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
|
||||
printk(KERN_DEBUG "%s: removing virtual "
|
||||
"interface %s because its BSS interface"
|
||||
" is being removed\n",
|
||||
sdata->dev->name, tsdata->dev->name);
|
||||
list_del_rcu(&tsdata->list);
|
||||
/*
|
||||
* We have lots of time and can afford
|
||||
* to sync for each interface
|
||||
*/
|
||||
synchronize_rcu();
|
||||
__ieee80211_if_del(local, tsdata);
|
||||
}
|
||||
}
|
||||
|
||||
beacon = sdata->u.ap.beacon;
|
||||
rcu_assign_pointer(sdata->u.ap.beacon, NULL);
|
||||
synchronize_rcu();
|
||||
kfree(beacon);
|
||||
|
||||
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
|
||||
local->total_ps_buffered--;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
/* nothing to do */
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MESH_POINT:
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
case IEEE80211_IF_TYPE_IBSS:
|
||||
kfree(sdata->u.sta.extra_ie);
|
||||
sdata->u.sta.extra_ie = NULL;
|
||||
kfree(sdata->u.sta.assocreq_ies);
|
||||
sdata->u.sta.assocreq_ies = NULL;
|
||||
kfree(sdata->u.sta.assocresp_ies);
|
||||
sdata->u.sta.assocresp_ies = NULL;
|
||||
if (sdata->u.sta.probe_resp) {
|
||||
dev_kfree_skb(sdata->u.sta.probe_resp);
|
||||
sdata->u.sta.probe_resp = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
dev->type = ARPHRD_ETHER;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
sdata->u.vlan.ap = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
flushed = sta_info_flush(local, sdata);
|
||||
WARN_ON(flushed);
|
||||
|
||||
memset(&sdata->u, 0, sizeof(sdata->u));
|
||||
ieee80211_if_sdata_init(sdata);
|
||||
}
|
||||
|
||||
/* Must be called with rtnl lock held. */
|
||||
void __ieee80211_if_del(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct net_device *dev = sdata->dev;
|
||||
|
||||
ieee80211_debugfs_remove_netdev(sdata);
|
||||
list_del_rcu(&sdata->list);
|
||||
synchronize_rcu();
|
||||
unregister_netdevice(dev);
|
||||
/* Except master interface, the net_device will be freed by
|
||||
* net_device->destructor (i. e. ieee80211_if_free). */
|
||||
}
|
||||
|
||||
/* Must be called with rtnl lock held. */
|
||||
int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
|
||||
/*
|
||||
* Remove all interfaces, may only be called at hardware unregistration
|
||||
* time because it doesn't do RCU-safe list removals.
|
||||
*/
|
||||
void ieee80211_remove_interfaces(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata, *n;
|
||||
struct ieee80211_sub_if_data *sdata, *tmp;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
|
||||
if ((sdata->vif.type == id || id == -1) &&
|
||||
strcmp(name, sdata->dev->name) == 0 &&
|
||||
sdata->dev != local->mdev) {
|
||||
list_del_rcu(&sdata->list);
|
||||
synchronize_rcu();
|
||||
__ieee80211_if_del(local, sdata);
|
||||
return 0;
|
||||
}
|
||||
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
|
||||
list_del(&sdata->list);
|
||||
unregister_netdevice(sdata->dev);
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void ieee80211_if_free(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
ieee80211_if_sdata_deinit(sdata);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ static int ieee80211_master_open(struct net_device *dev)
|
|||
|
||||
/* we hold the RTNL here so can safely walk the list */
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata->dev != dev && netif_running(sdata->dev)) {
|
||||
if (netif_running(sdata->dev)) {
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ static int ieee80211_master_stop(struct net_device *dev)
|
|||
|
||||
/* we hold the RTNL here so can safely walk the list */
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
if (sdata->dev != dev && netif_running(sdata->dev))
|
||||
if (netif_running(sdata->dev))
|
||||
dev_close(sdata->dev);
|
||||
|
||||
return 0;
|
||||
|
@ -194,7 +194,7 @@ static int ieee80211_open(struct net_device *dev)
|
|||
list_for_each_entry(nsdata, &local->interfaces, list) {
|
||||
struct net_device *ndev = nsdata->dev;
|
||||
|
||||
if (ndev != dev && ndev != local->mdev && netif_running(ndev)) {
|
||||
if (ndev != dev && netif_running(ndev)) {
|
||||
/*
|
||||
* Allow only a single IBSS interface to be up at any
|
||||
* time. This is restricted because beacon distribution
|
||||
|
@ -209,30 +209,6 @@ static int ieee80211_open(struct net_device *dev)
|
|||
nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* Disallow multiple IBSS/STA mode interfaces.
|
||||
*
|
||||
* This is a technical restriction, it is possible although
|
||||
* most likely not IEEE 802.11 compliant to have multiple
|
||||
* STAs with just a single hardware (the TSF timer will not
|
||||
* be adjusted properly.)
|
||||
*
|
||||
* However, because mac80211 uses the master device's BSS
|
||||
* information for each STA/IBSS interface, doing this will
|
||||
* currently corrupt that BSS information completely, unless,
|
||||
* a not very useful case, both STAs are associated to the
|
||||
* same BSS.
|
||||
*
|
||||
* To remove this restriction, the BSS information needs to
|
||||
* be embedded in the STA/IBSS mode sdata instead of using
|
||||
* the master device's BSS structure.
|
||||
*/
|
||||
if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
|
||||
(nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* The remaining checks are only performed for interfaces
|
||||
* with the same MAC address.
|
||||
|
@ -252,7 +228,7 @@ static int ieee80211_open(struct net_device *dev)
|
|||
*/
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
|
||||
nsdata->vif.type == IEEE80211_IF_TYPE_AP)
|
||||
sdata->u.vlan.ap = nsdata;
|
||||
sdata->bss = &nsdata->u.ap;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,10 +238,13 @@ static int ieee80211_open(struct net_device *dev)
|
|||
return -ENOLINK;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
if (!sdata->u.vlan.ap)
|
||||
if (!sdata->bss)
|
||||
return -ENOLINK;
|
||||
list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_AP:
|
||||
sdata->bss = &sdata->u.ap;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
case IEEE80211_IF_TYPE_IBSS:
|
||||
|
@ -283,14 +262,13 @@ static int ieee80211_open(struct net_device *dev)
|
|||
if (local->ops->start)
|
||||
res = local->ops->start(local_to_hw(local));
|
||||
if (res)
|
||||
return res;
|
||||
goto err_del_bss;
|
||||
need_hw_reconfig = 1;
|
||||
ieee80211_led_radio(local, local->hw.conf.radio_enabled);
|
||||
}
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
|
||||
/* no need to tell driver */
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
|
@ -329,7 +307,8 @@ static int ieee80211_open(struct net_device *dev)
|
|||
if (res)
|
||||
goto err_stop;
|
||||
|
||||
ieee80211_if_config(dev);
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
ieee80211_start_mesh(sdata->dev);
|
||||
changed |= ieee80211_reset_erp_info(dev);
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
ieee80211_enable_keys(sdata);
|
||||
|
@ -404,6 +383,10 @@ static int ieee80211_open(struct net_device *dev)
|
|||
err_stop:
|
||||
if (!local->open_count && local->ops->stop)
|
||||
local->ops->stop(local_to_hw(local));
|
||||
err_del_bss:
|
||||
sdata->bss = NULL;
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
|
||||
list_del(&sdata->u.vlan.list);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -486,7 +469,6 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
switch (sdata->vif.type) {
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
list_del(&sdata->u.vlan.list);
|
||||
sdata->u.vlan.ap = NULL;
|
||||
/* no need to tell driver */
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
|
@ -549,6 +531,8 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
local->ops->remove_interface(local_to_hw(local), &conf);
|
||||
}
|
||||
|
||||
sdata->bss = NULL;
|
||||
|
||||
if (local->open_count == 0) {
|
||||
if (netif_running(local->mdev))
|
||||
dev_close(local->mdev);
|
||||
|
@ -988,7 +972,6 @@ static const struct header_ops ieee80211_header_ops = {
|
|||
.cache_update = eth_header_cache_update,
|
||||
};
|
||||
|
||||
/* Must not be called for mdev */
|
||||
void ieee80211_if_setup(struct net_device *dev)
|
||||
{
|
||||
ether_setup(dev);
|
||||
|
@ -998,64 +981,54 @@ void ieee80211_if_setup(struct net_device *dev)
|
|||
dev->change_mtu = ieee80211_change_mtu;
|
||||
dev->open = ieee80211_open;
|
||||
dev->stop = ieee80211_stop;
|
||||
dev->destructor = ieee80211_if_free;
|
||||
dev->destructor = free_netdev;
|
||||
}
|
||||
|
||||
/* everything else */
|
||||
|
||||
static int __ieee80211_if_config(struct net_device *dev,
|
||||
struct sk_buff *beacon)
|
||||
int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_conf conf;
|
||||
|
||||
if (!local->ops->config_interface || !netif_running(dev))
|
||||
if (WARN_ON(!netif_running(sdata->dev)))
|
||||
return 0;
|
||||
|
||||
if (!local->ops->config_interface)
|
||||
return 0;
|
||||
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
conf.type = sdata->vif.type;
|
||||
conf.changed = changed;
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
|
||||
conf.bssid = sdata->u.sta.bssid;
|
||||
conf.ssid = sdata->u.sta.ssid;
|
||||
conf.ssid_len = sdata->u.sta.ssid_len;
|
||||
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
conf.beacon = beacon;
|
||||
ieee80211_start_mesh(dev);
|
||||
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
|
||||
conf.bssid = sdata->dev->dev_addr;
|
||||
conf.ssid = sdata->u.ap.ssid;
|
||||
conf.ssid_len = sdata->u.ap.ssid_len;
|
||||
conf.beacon = beacon;
|
||||
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
u8 zero[ETH_ALEN] = { 0 };
|
||||
conf.bssid = zero;
|
||||
conf.ssid = zero;
|
||||
conf.ssid_len = 0;
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
|
||||
return -EINVAL;
|
||||
|
||||
return local->ops->config_interface(local_to_hw(local),
|
||||
&sdata->vif, &conf);
|
||||
}
|
||||
|
||||
int ieee80211_if_config(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
|
||||
(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
|
||||
return ieee80211_if_config_beacon(dev);
|
||||
return __ieee80211_if_config(dev, NULL);
|
||||
}
|
||||
|
||||
int ieee80211_if_config_beacon(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
|
||||
return 0;
|
||||
skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
return __ieee80211_if_config(dev, skb);
|
||||
}
|
||||
|
||||
int ieee80211_hw_config(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_channel *chan;
|
||||
|
@ -1659,7 +1632,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
int result;
|
||||
enum ieee80211_band band;
|
||||
struct net_device *mdev;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct wireless_dev *mwdev;
|
||||
|
||||
/*
|
||||
* generic code guarantees at least one band,
|
||||
|
@ -1699,8 +1672,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
hw->ampdu_queues = 0;
|
||||
#endif
|
||||
|
||||
/* for now, mdev needs sub_if_data :/ */
|
||||
mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
|
||||
mdev = alloc_netdev_mq(sizeof(struct wireless_dev),
|
||||
"wmaster%d", ether_setup,
|
||||
ieee80211_num_queues(hw));
|
||||
if (!mdev)
|
||||
|
@ -1709,13 +1681,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
if (ieee80211_num_queues(hw) > 1)
|
||||
mdev->features |= NETIF_F_MULTI_QUEUE;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
|
||||
mdev->ieee80211_ptr = &sdata->wdev;
|
||||
sdata->wdev.wiphy = local->hw.wiphy;
|
||||
mwdev = netdev_priv(mdev);
|
||||
mdev->ieee80211_ptr = mwdev;
|
||||
mwdev->wiphy = local->hw.wiphy;
|
||||
|
||||
local->mdev = mdev;
|
||||
|
||||
ieee80211_rx_bss_list_init(mdev);
|
||||
ieee80211_rx_bss_list_init(local);
|
||||
|
||||
mdev->hard_start_xmit = ieee80211_master_start_xmit;
|
||||
mdev->open = ieee80211_master_open;
|
||||
|
@ -1724,16 +1696,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
mdev->header_ops = &ieee80211_header_ops;
|
||||
mdev->set_multicast_list = ieee80211_master_set_multicast_list;
|
||||
|
||||
sdata->vif.type = IEEE80211_IF_TYPE_AP;
|
||||
sdata->dev = mdev;
|
||||
sdata->local = local;
|
||||
sdata->u.ap.force_unicast_rateidx = -1;
|
||||
sdata->u.ap.max_ratectrl_rateidx = -1;
|
||||
ieee80211_if_sdata_init(sdata);
|
||||
|
||||
/* no RCU needed since we're still during init phase */
|
||||
list_add_tail(&sdata->list, &local->interfaces);
|
||||
|
||||
name = wiphy_dev(local->hw.wiphy)->driver->name;
|
||||
local->hw.workqueue = create_freezeable_workqueue(name);
|
||||
if (!local->hw.workqueue) {
|
||||
|
@ -1779,9 +1741,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
if (result < 0)
|
||||
goto fail_dev;
|
||||
|
||||
ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
|
||||
ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
|
||||
|
||||
result = ieee80211_init_rate_ctrl_alg(local,
|
||||
hw->rate_control_algorithm);
|
||||
if (result < 0) {
|
||||
|
@ -1801,13 +1760,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
ieee80211_install_qdisc(local->mdev);
|
||||
|
||||
/* add one default STA interface */
|
||||
result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
|
||||
result = ieee80211_if_add(local, "wlan%d", NULL,
|
||||
IEEE80211_IF_TYPE_STA, NULL);
|
||||
if (result)
|
||||
printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
|
||||
local->reg_state = IEEE80211_DEV_REGISTERED;
|
||||
rtnl_unlock();
|
||||
|
||||
ieee80211_led_init(local);
|
||||
|
@ -1817,7 +1775,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
fail_wep:
|
||||
rate_control_deinitialize(local);
|
||||
fail_rate:
|
||||
ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
|
||||
unregister_netdevice(local->mdev);
|
||||
local->mdev = NULL;
|
||||
fail_dev:
|
||||
|
@ -1827,10 +1784,8 @@ fail_sta_info:
|
|||
debugfs_hw_del(local);
|
||||
destroy_workqueue(local->hw.workqueue);
|
||||
fail_workqueue:
|
||||
if (local->mdev != NULL) {
|
||||
ieee80211_if_free(local->mdev);
|
||||
local->mdev = NULL;
|
||||
}
|
||||
if (local->mdev)
|
||||
free_netdev(local->mdev);
|
||||
fail_mdev_alloc:
|
||||
wiphy_unregister(local->hw.wiphy);
|
||||
return result;
|
||||
|
@ -1840,42 +1795,27 @@ EXPORT_SYMBOL(ieee80211_register_hw);
|
|||
void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata, *tmp;
|
||||
|
||||
tasklet_kill(&local->tx_pending_tasklet);
|
||||
tasklet_kill(&local->tasklet);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
|
||||
|
||||
local->reg_state = IEEE80211_DEV_UNREGISTERED;
|
||||
|
||||
/*
|
||||
* At this point, interface list manipulations are fine
|
||||
* because the driver cannot be handing us frames any
|
||||
* more and the tasklet is killed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* First, we remove all non-master interfaces. Do this because they
|
||||
* may have bss pointer dependency on the master, and when we free
|
||||
* the master these would be freed as well, breaking our list
|
||||
* iteration completely.
|
||||
*/
|
||||
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
|
||||
if (sdata->dev == local->mdev)
|
||||
continue;
|
||||
list_del(&sdata->list);
|
||||
__ieee80211_if_del(local, sdata);
|
||||
}
|
||||
/* First, we remove all virtual interfaces. */
|
||||
ieee80211_remove_interfaces(local);
|
||||
|
||||
/* then, finally, remove the master interface */
|
||||
__ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev));
|
||||
unregister_netdevice(local->mdev);
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
ieee80211_rx_bss_list_deinit(local->mdev);
|
||||
ieee80211_rx_bss_list_deinit(local);
|
||||
ieee80211_clear_tx_pending(local);
|
||||
sta_info_stop(local);
|
||||
rate_control_deinitialize(local);
|
||||
|
@ -1892,8 +1832,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
|||
wiphy_unregister(local->hw.wiphy);
|
||||
ieee80211_wep_free(local);
|
||||
ieee80211_led_exit(local);
|
||||
ieee80211_if_free(local->mdev);
|
||||
local->mdev = NULL;
|
||||
free_netdev(local->mdev);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_unregister_hw);
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
|
|||
static struct ieee80211_sta_bss *
|
||||
ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
|
||||
u8 *ssid, u8 ssid_len);
|
||||
static void ieee80211_rx_bss_put(struct net_device *dev,
|
||||
static void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
struct ieee80211_sta_bss *bss);
|
||||
static int ieee80211_sta_find_ibss(struct net_device *dev,
|
||||
struct ieee80211_if_sta *ifsta);
|
||||
|
@ -345,7 +345,7 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
|
|||
params.aifs = pos[0] & 0x0f;
|
||||
params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
|
||||
params.cw_min = ecw2cw(pos[1] & 0x0f);
|
||||
params.txop = pos[2] | (pos[3] << 8);
|
||||
params.txop = get_unaligned_le16(pos + 2);
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
|
||||
"cWmin=%d cWmax=%d txop=%d\n",
|
||||
|
@ -554,7 +554,7 @@ static void ieee80211_set_associated(struct net_device *dev,
|
|||
|
||||
changed |= ieee80211_handle_bss_capability(sdata, bss);
|
||||
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
}
|
||||
|
||||
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
|
||||
|
@ -760,7 +760,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
|
|||
(local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
|
||||
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
|
||||
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
} else {
|
||||
rates = ~0;
|
||||
rates_len = sband->n_bitrates;
|
||||
|
@ -992,7 +992,7 @@ static int ieee80211_privacy_mismatch(struct net_device *dev,
|
|||
wep_privacy = !!ieee80211_sta_wep_configured(dev);
|
||||
privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
|
||||
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
|
||||
if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
|
||||
return 0;
|
||||
|
@ -2094,7 +2094,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
sta->last_signal = bss->signal;
|
||||
sta->last_qual = bss->qual;
|
||||
sta->last_noise = bss->noise;
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
}
|
||||
|
||||
err = sta_info_insert(sta);
|
||||
|
@ -2212,10 +2212,9 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
|
|||
|
||||
|
||||
/* Caller must hold local->sta_bss_lock */
|
||||
static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
|
||||
static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
|
||||
struct ieee80211_sta_bss *bss)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sta_bss *b, *prev = NULL;
|
||||
b = local->sta_bss_hash[STA_HASH(bss->bssid)];
|
||||
while (b) {
|
||||
|
@ -2367,39 +2366,35 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
|
|||
}
|
||||
|
||||
|
||||
static void ieee80211_rx_bss_put(struct net_device *dev,
|
||||
static void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
struct ieee80211_sta_bss *bss)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
|
||||
local_bh_disable();
|
||||
if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
|
||||
local_bh_enable();
|
||||
return;
|
||||
}
|
||||
|
||||
__ieee80211_rx_bss_hash_del(dev, bss);
|
||||
__ieee80211_rx_bss_hash_del(local, bss);
|
||||
list_del(&bss->list);
|
||||
spin_unlock_bh(&local->sta_bss_lock);
|
||||
ieee80211_rx_bss_free(bss);
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_rx_bss_list_init(struct net_device *dev)
|
||||
void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
spin_lock_init(&local->sta_bss_lock);
|
||||
INIT_LIST_HEAD(&local->sta_bss_list);
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_rx_bss_list_deinit(struct net_device *dev)
|
||||
void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sta_bss *bss, *tmp;
|
||||
|
||||
list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2411,8 +2406,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
|
|||
int res, rates, i, j;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
struct ieee80211_tx_info *control;
|
||||
struct rate_selection ratesel;
|
||||
u8 *pos;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
@ -2430,7 +2423,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
|
|||
local->ops->reset_tsf(local_to_hw(local));
|
||||
}
|
||||
memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
|
||||
res = ieee80211_if_config(dev);
|
||||
res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
|
@ -2444,19 +2437,16 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
|
|||
if (res)
|
||||
return res;
|
||||
|
||||
/* Set beacon template */
|
||||
/* Build IBSS probe response */
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
|
||||
do {
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
if (skb) {
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *)
|
||||
skb_put(skb, 24 + sizeof(mgmt->u.beacon));
|
||||
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
|
||||
mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
|
||||
IEEE80211_STYPE_BEACON);
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
memset(mgmt->da, 0xff, ETH_ALEN);
|
||||
memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
|
||||
|
@ -2500,62 +2490,23 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
|
|||
memcpy(pos, &bss->supp_rates[8], rates);
|
||||
}
|
||||
|
||||
control = IEEE80211_SKB_CB(skb);
|
||||
ifsta->probe_resp = skb;
|
||||
|
||||
rate_control_get_rate(dev, sband, skb, &ratesel);
|
||||
if (ratesel.rate_idx < 0) {
|
||||
printk(KERN_DEBUG "%s: Failed to determine TX rate "
|
||||
"for IBSS beacon\n", dev->name);
|
||||
break;
|
||||
}
|
||||
control->control.vif = &sdata->vif;
|
||||
control->tx_rate_idx = ratesel.rate_idx;
|
||||
if (sdata->bss_conf.use_short_preamble &&
|
||||
sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
||||
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);
|
||||
if (ifsta->probe_resp) {
|
||||
mgmt = (struct ieee80211_mgmt *)
|
||||
ifsta->probe_resp->data;
|
||||
mgmt->frame_control =
|
||||
IEEE80211_FC(IEEE80211_FTYPE_MGMT,
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
} else {
|
||||
printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
|
||||
"template for IBSS\n", dev->name);
|
||||
}
|
||||
|
||||
if (local->ops->beacon_update &&
|
||||
local->ops->beacon_update(local_to_hw(local), skb) == 0) {
|
||||
printk(KERN_DEBUG "%s: Configured IBSS beacon "
|
||||
"template\n", dev->name);
|
||||
skb = NULL;
|
||||
}
|
||||
|
||||
rates = 0;
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
for (i = 0; i < bss->supp_rates_len; i++) {
|
||||
int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
|
||||
for (j = 0; j < sband->n_bitrates; j++)
|
||||
if (sband->bitrates[j].bitrate == bitrate)
|
||||
rates |= BIT(j);
|
||||
}
|
||||
ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
|
||||
|
||||
ieee80211_sta_def_wmm_params(dev, bss, 1);
|
||||
} while (0);
|
||||
|
||||
if (skb) {
|
||||
printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
|
||||
"template\n", dev->name);
|
||||
dev_kfree_skb(skb);
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
|
||||
}
|
||||
|
||||
rates = 0;
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
for (i = 0; i < bss->supp_rates_len; i++) {
|
||||
int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
|
||||
for (j = 0; j < sband->n_bitrates; j++)
|
||||
if (sband->bitrates[j].bitrate == bitrate)
|
||||
rates |= BIT(j);
|
||||
}
|
||||
ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
|
||||
|
||||
ieee80211_sta_def_wmm_params(dev, bss, 1);
|
||||
|
||||
ifsta->state = IEEE80211_IBSS_JOINED;
|
||||
mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
|
||||
|
||||
|
@ -2775,7 +2726,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
|
|||
*/
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
|
||||
bss->probe_resp && beacon) {
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2918,7 +2869,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3338,7 +3289,7 @@ static void ieee80211_mesh_housekeeping(struct net_device *dev,
|
|||
|
||||
free_plinks = mesh_plink_availables(sdata);
|
||||
if (free_plinks != sdata->u.sta.accepting_plinks)
|
||||
ieee80211_if_config_beacon(dev);
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
|
||||
|
||||
mod_timer(&ifsta->timer, jiffies +
|
||||
IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
|
||||
|
@ -3578,7 +3529,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
|
|||
selected->ssid_len);
|
||||
ieee80211_sta_set_bssid(dev, selected->bssid);
|
||||
ieee80211_sta_def_wmm_params(dev, selected, 0);
|
||||
ieee80211_rx_bss_put(dev, selected);
|
||||
ieee80211_rx_bss_put(local, selected);
|
||||
ifsta->state = IEEE80211_AUTHENTICATE;
|
||||
ieee80211_sta_reset_auth(dev, ifsta);
|
||||
return 0;
|
||||
|
@ -3655,7 +3606,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
|
|||
}
|
||||
|
||||
ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3711,7 +3662,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
|
|||
" based on configured SSID\n",
|
||||
dev->name, print_mac(mac, bssid));
|
||||
ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
return ret;
|
||||
}
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
|
@ -3762,28 +3713,45 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_if_sta *ifsta;
|
||||
int res;
|
||||
|
||||
if (len > IEEE80211_MAX_SSID_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
ifsta = &sdata->u.sta;
|
||||
|
||||
if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
|
||||
if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) {
|
||||
memset(ifsta->ssid, 0, sizeof(ifsta->ssid));
|
||||
memcpy(ifsta->ssid, ssid, len);
|
||||
ifsta->ssid_len = len;
|
||||
ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
|
||||
memcpy(ifsta->ssid, ssid, len);
|
||||
memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
|
||||
ifsta->ssid_len = len;
|
||||
|
||||
res = 0;
|
||||
/*
|
||||
* Hack! MLME code needs to be cleaned up to have different
|
||||
* entry points for configuration and internal selection change
|
||||
*/
|
||||
if (netif_running(sdata->dev))
|
||||
res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
|
||||
if (res) {
|
||||
printk(KERN_DEBUG "%s: Failed to config new SSID to "
|
||||
"the low-level driver\n", dev->name);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (len)
|
||||
ifsta->flags |= IEEE80211_STA_SSID_SET;
|
||||
else
|
||||
ifsta->flags &= ~IEEE80211_STA_SSID_SET;
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
|
||||
!(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
|
||||
ifsta->ibss_join_req = jiffies;
|
||||
ifsta->state = IEEE80211_IBSS_SEARCH;
|
||||
return ieee80211_sta_find_ibss(dev, ifsta);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3809,7 +3777,12 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
|
|||
|
||||
if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
|
||||
memcpy(ifsta->bssid, bssid, ETH_ALEN);
|
||||
res = ieee80211_if_config(dev);
|
||||
res = 0;
|
||||
/*
|
||||
* Hack! See also ieee80211_sta_set_ssid.
|
||||
*/
|
||||
if (netif_running(sdata->dev))
|
||||
res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
|
||||
if (res) {
|
||||
printk(KERN_DEBUG "%s: Failed to config new BSSID to "
|
||||
"the low-level driver\n", dev->name);
|
||||
|
@ -3907,11 +3880,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
|
|||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
|
||||
/* No need to wake the master device. */
|
||||
if (sdata->dev == local->mdev)
|
||||
continue;
|
||||
|
||||
/* Tell AP we're back */
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
|
||||
sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
|
||||
|
@ -4077,12 +4045,6 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
|
|||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
|
||||
/* Don't stop the master interface, otherwise we can't transmit
|
||||
* probes! */
|
||||
if (sdata->dev == local->mdev)
|
||||
continue;
|
||||
|
||||
netif_stop_queue(sdata->dev);
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
|
||||
(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
|
||||
|
@ -4398,7 +4360,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid))
|
||||
if (compare_ether_addr(bssid, sdata->u.sta.bssid))
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
|
@ -4473,12 +4435,10 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
|
|||
case IEEE80211_NOTIFY_RE_ASSOC:
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
|
||||
continue;
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
|
||||
ieee80211_sta_req_auth(sdata->dev,
|
||||
&sdata->u.sta);
|
||||
}
|
||||
|
||||
ieee80211_sta_req_auth(sdata->dev, &sdata->u.sta);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
|
|
|
@ -259,8 +259,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
|
|||
|
||||
/* Don't update the state if we're not controlling the rate. */
|
||||
sdata = sta->sdata;
|
||||
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
|
||||
sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
|
||||
if (sdata->force_unicast_rateidx > -1) {
|
||||
sta->txrate_idx = sdata->max_ratectrl_rateidx;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
@ -337,8 +337,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
|
|||
|
||||
/* If a forced rate is in effect, select it. */
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
|
||||
sta->txrate_idx = sdata->bss->force_unicast_rateidx;
|
||||
if (sdata->force_unicast_rateidx > -1)
|
||||
sta->txrate_idx = sdata->force_unicast_rateidx;
|
||||
|
||||
rateidx = sta->txrate_idx;
|
||||
|
||||
|
|
|
@ -334,13 +334,18 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
|||
else
|
||||
rx->flags &= ~IEEE80211_RX_AMSDU;
|
||||
} else {
|
||||
if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
|
||||
/* Separate TID for management frames */
|
||||
tid = NUM_RX_DATA_QUEUES - 1;
|
||||
} else {
|
||||
/* no qos control present */
|
||||
tid = 0; /* 802.1d - Best Effort */
|
||||
}
|
||||
/*
|
||||
* IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
|
||||
*
|
||||
* Sequence numbers for management frames, QoS data
|
||||
* frames with a broadcast/multicast address in the
|
||||
* Address 1 field, and all non-QoS data frames sent
|
||||
* by QoS STAs are assigned using an additional single
|
||||
* modulo-4096 counter, [...]
|
||||
*
|
||||
* We also use that counter for non-QoS STAs.
|
||||
*/
|
||||
tid = NUM_RX_DATA_QUEUES - 1;
|
||||
}
|
||||
|
||||
rx->queue = tid;
|
||||
|
@ -647,8 +652,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
|
|||
|
||||
sdata = sta->sdata;
|
||||
|
||||
if (sdata->bss)
|
||||
atomic_inc(&sdata->bss->num_sta_ps);
|
||||
atomic_inc(&sdata->bss->num_sta_ps);
|
||||
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
|
||||
|
@ -667,8 +671,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
|
|||
|
||||
sdata = sta->sdata;
|
||||
|
||||
if (sdata->bss)
|
||||
atomic_dec(&sdata->bss->num_sta_ps);
|
||||
atomic_dec(&sdata->bss->num_sta_ps);
|
||||
|
||||
clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
|
||||
|
||||
|
@ -742,7 +745,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
|||
sta->last_qual = rx->status->qual;
|
||||
sta->last_noise = rx->status->noise;
|
||||
|
||||
if (!ieee80211_has_morefrags(hdr->frame_control)) {
|
||||
if (!ieee80211_has_morefrags(hdr->frame_control) &&
|
||||
(rx->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
|
||||
rx->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) {
|
||||
/* Change STA power saving mode only in the end of a frame
|
||||
* exchange sequence */
|
||||
if (test_sta_flags(sta, WLAN_STA_PS) &&
|
||||
|
@ -1772,11 +1777,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
}
|
||||
if (sdata->dev == sdata->local->mdev &&
|
||||
!(rx->flags & IEEE80211_RX_IN_SCAN))
|
||||
/* do not receive anything via
|
||||
* master device when not scanning */
|
||||
return 0;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
if (bssid || !ieee80211_is_data(hdr->frame_control))
|
||||
|
@ -2046,8 +2046,8 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
|
|||
|
||||
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
|
||||
|
||||
/* null data frames are excluded */
|
||||
if (unlikely(ieee80211_is_nullfunc(hdr->frame_control)))
|
||||
/* qos null data frames are excluded */
|
||||
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
|
||||
goto end_reorder;
|
||||
|
||||
/* new un-ordered ampdu frame - process it */
|
||||
|
|
|
@ -320,7 +320,9 @@ int sta_info_insert(struct sta_info *sta)
|
|||
/* notify driver */
|
||||
if (local->ops->sta_notify) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
|
||||
sdata = sdata->u.vlan.ap;
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
|
||||
STA_NOTIFY_ADD, sta->addr);
|
||||
|
@ -375,8 +377,10 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
|
|||
static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
if (bss)
|
||||
__bss_tim_set(bss, sta->aid);
|
||||
BUG_ON(!bss);
|
||||
|
||||
__bss_tim_set(bss, sta->aid);
|
||||
|
||||
if (sta->local->ops->set_tim) {
|
||||
sta->local->tim_in_locked_section = true;
|
||||
sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
|
||||
|
@ -388,6 +392,8 @@ void sta_info_set_tim_bit(struct sta_info *sta)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(!sta->sdata->bss);
|
||||
|
||||
spin_lock_irqsave(&sta->local->sta_lock, flags);
|
||||
__sta_info_set_tim_bit(sta->sdata->bss, sta);
|
||||
spin_unlock_irqrestore(&sta->local->sta_lock, flags);
|
||||
|
@ -396,8 +402,10 @@ void sta_info_set_tim_bit(struct sta_info *sta)
|
|||
static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
if (bss)
|
||||
__bss_tim_clear(bss, sta->aid);
|
||||
BUG_ON(!bss);
|
||||
|
||||
__bss_tim_clear(bss, sta->aid);
|
||||
|
||||
if (sta->local->ops->set_tim) {
|
||||
sta->local->tim_in_locked_section = true;
|
||||
sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
|
||||
|
@ -409,6 +417,8 @@ void sta_info_clear_tim_bit(struct sta_info *sta)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(!sta->sdata->bss);
|
||||
|
||||
spin_lock_irqsave(&sta->local->sta_lock, flags);
|
||||
__sta_info_clear_tim_bit(sta->sdata->bss, sta);
|
||||
spin_unlock_irqrestore(&sta->local->sta_lock, flags);
|
||||
|
@ -437,8 +447,9 @@ void __sta_info_unlink(struct sta_info **sta)
|
|||
list_del(&(*sta)->list);
|
||||
|
||||
if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
|
||||
if (sdata->bss)
|
||||
atomic_dec(&sdata->bss->num_sta_ps);
|
||||
BUG_ON(!sdata->bss);
|
||||
|
||||
atomic_dec(&sdata->bss->num_sta_ps);
|
||||
__sta_info_clear_tim_bit(sdata->bss, *sta);
|
||||
}
|
||||
|
||||
|
@ -446,7 +457,9 @@ void __sta_info_unlink(struct sta_info **sta)
|
|||
|
||||
if (local->ops->sta_notify) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
|
||||
sdata = sdata->u.vlan.ap;
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
|
||||
STA_NOTIFY_REMOVE, (*sta)->addr);
|
||||
|
|
|
@ -285,6 +285,7 @@ struct sta_info {
|
|||
unsigned long tx_fragments;
|
||||
int txrate_idx;
|
||||
int last_txrate_idx;
|
||||
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
|
||||
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
|
||||
unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
|
||||
#endif
|
||||
|
|
|
@ -38,16 +38,6 @@
|
|||
|
||||
/* misc utils */
|
||||
|
||||
static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_hdr *hdr)
|
||||
{
|
||||
/* Set the sequence number for this frame. */
|
||||
hdr->seq_ctrl = cpu_to_le16(sdata->sequence);
|
||||
|
||||
/* Increase the sequence number. */
|
||||
sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
|
||||
static void ieee80211_dump_frame(const char *ifname, const char *title,
|
||||
const struct sk_buff *skb)
|
||||
|
@ -274,17 +264,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
|||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
|
||||
if (ieee80211_hdrlen(hdr->frame_control) >= 24)
|
||||
ieee80211_include_sequence(tx->sdata, hdr);
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
/* This function is called whenever the AP is about to exceed the maximum limit
|
||||
* of buffered frames for power saving STAs. This situation should not really
|
||||
* happen often during normal operation, so dropping the oldest buffered packet
|
||||
|
@ -303,8 +282,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
|
|||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
struct ieee80211_if_ap *ap;
|
||||
if (sdata->dev == local->mdev ||
|
||||
sdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
continue;
|
||||
ap = &sdata->u.ap;
|
||||
skb = skb_dequeue(&ap->ps_bc_buf);
|
||||
|
@ -346,8 +324,12 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
|
|||
* This is done either by the hardware or us.
|
||||
*/
|
||||
|
||||
/* not AP/IBSS or ordered frame */
|
||||
if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER))
|
||||
/* powersaving STAs only in AP/VLAN mode */
|
||||
if (!tx->sdata->bss)
|
||||
return TX_CONTINUE;
|
||||
|
||||
/* no buffering for ordered frames */
|
||||
if (tx->fc & IEEE80211_FCTL_ORDER)
|
||||
return TX_CONTINUE;
|
||||
|
||||
/* no stations in PS mode */
|
||||
|
@ -638,6 +620,49 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
|||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
u16 *seq;
|
||||
u8 *qc;
|
||||
int tid;
|
||||
|
||||
/* only for injected frames */
|
||||
if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (ieee80211_hdrlen(hdr->frame_control) < 24)
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This should be true for injected/management frames only, for
|
||||
* management frames we have set the IEEE80211_TX_CTL_ASSIGN_SEQ
|
||||
* above since they are not QoS-data frames.
|
||||
*/
|
||||
if (!tx->sta)
|
||||
return TX_CONTINUE;
|
||||
|
||||
/* include per-STA, per-TID sequence counter */
|
||||
|
||||
qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
||||
seq = &tx->sta->tid_seq[tid];
|
||||
|
||||
hdr->seq_ctrl = cpu_to_le16(*seq);
|
||||
|
||||
/* Increase the sequence number. */
|
||||
*seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ;
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
|
@ -1107,12 +1132,12 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
|||
goto txh_done;
|
||||
|
||||
CALL_TXH(ieee80211_tx_h_check_assoc)
|
||||
CALL_TXH(ieee80211_tx_h_sequence)
|
||||
CALL_TXH(ieee80211_tx_h_ps_buf)
|
||||
CALL_TXH(ieee80211_tx_h_select_key)
|
||||
CALL_TXH(ieee80211_tx_h_michael_mic_add)
|
||||
CALL_TXH(ieee80211_tx_h_rate_ctrl)
|
||||
CALL_TXH(ieee80211_tx_h_misc)
|
||||
CALL_TXH(ieee80211_tx_h_sequence)
|
||||
CALL_TXH(ieee80211_tx_h_fragment)
|
||||
/* handlers after fragment must be aware of tx info fragmentation! */
|
||||
CALL_TXH(ieee80211_tx_h_encrypt)
|
||||
|
@ -1785,17 +1810,17 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct net_device *bdev;
|
||||
struct ieee80211_sub_if_data *sdata = NULL;
|
||||
struct ieee80211_if_ap *ap = NULL;
|
||||
struct ieee80211_if_sta *ifsta = NULL;
|
||||
struct rate_selection rsel;
|
||||
struct beacon_data *beacon;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
int *num_beacons;
|
||||
bool err = true;
|
||||
enum ieee80211_band band = local->hw.conf.channel->band;
|
||||
u8 *pos;
|
||||
|
||||
|
@ -1824,9 +1849,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
memcpy(skb_put(skb, beacon->head_len), beacon->head,
|
||||
beacon->head_len);
|
||||
|
||||
ieee80211_include_sequence(sdata,
|
||||
(struct ieee80211_hdr *)skb->data);
|
||||
|
||||
/*
|
||||
* Not very nice, but we want to allow the driver to call
|
||||
* ieee80211_beacon_get() as a response to the set_tim()
|
||||
|
@ -1849,9 +1871,24 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
beacon->tail, beacon->tail_len);
|
||||
|
||||
num_beacons = &ap->num_beacons;
|
||||
} else
|
||||
goto out;
|
||||
} else if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
|
||||
struct ieee80211_hdr *hdr;
|
||||
ifsta = &sdata->u.sta;
|
||||
|
||||
err = false;
|
||||
}
|
||||
if (!ifsta->probe_resp)
|
||||
goto out;
|
||||
|
||||
skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
|
||||
IEEE80211_STYPE_BEACON);
|
||||
|
||||
num_beacons = &ifsta->num_beacons;
|
||||
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
/* headroom, head length, tail length and maximum TIM length */
|
||||
skb = dev_alloc_skb(local->tx_headroom + 400);
|
||||
|
@ -1878,17 +1915,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
mesh_mgmt_ies_add(skb, sdata->dev);
|
||||
|
||||
num_beacons = &sdata->u.sta.num_beacons;
|
||||
|
||||
err = false;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "no beacon data avail for %s\n",
|
||||
bdev->name);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
skb = NULL;
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -1910,14 +1938,18 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
|
||||
info->control.vif = vif;
|
||||
info->tx_rate_idx = rsel.rate_idx;
|
||||
|
||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
|
||||
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
if (sdata->bss_conf.use_short_preamble &&
|
||||
sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
||||
info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
|
||||
|
||||
info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
|
||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
|
||||
info->control.retry_limit = 1;
|
||||
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
||||
|
||||
(*num_beacons)++;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -428,8 +428,6 @@ void ieee80211_iterate_active_interfaces(
|
|||
case IEEE80211_IF_TYPE_MESH_POINT:
|
||||
break;
|
||||
}
|
||||
if (sdata->dev == local->mdev)
|
||||
continue;
|
||||
if (netif_running(sdata->dev))
|
||||
iterator(data, sdata->dev->dev_addr,
|
||||
&sdata->vif);
|
||||
|
@ -463,8 +461,6 @@ void ieee80211_iterate_active_interfaces_atomic(
|
|||
case IEEE80211_IF_TYPE_MESH_POINT:
|
||||
break;
|
||||
}
|
||||
if (sdata->dev == local->mdev)
|
||||
continue;
|
||||
if (netif_running(sdata->dev))
|
||||
iterator(data, sdata->dev->dev_addr,
|
||||
&sdata->vif);
|
||||
|
|
|
@ -296,15 +296,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type == sdata->vif.type)
|
||||
return 0;
|
||||
if (netif_running(dev))
|
||||
return -EBUSY;
|
||||
|
||||
ieee80211_if_reinit(dev);
|
||||
ieee80211_if_set_type(dev, type);
|
||||
|
||||
return 0;
|
||||
return ieee80211_if_change_type(sdata, type);
|
||||
}
|
||||
|
||||
|
||||
|
@ -452,7 +444,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
|
|||
memset(sdata->u.ap.ssid + len, 0,
|
||||
IEEE80211_MAX_SSID_LEN - len);
|
||||
sdata->u.ap.ssid_len = len;
|
||||
return ieee80211_if_config(dev);
|
||||
return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
|
||||
}
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -627,16 +619,14 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
|
|||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (!sdata->bss)
|
||||
return -ENODEV;
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
|
||||
* target_rate = X, rate->fixed = 1 means only rate X
|
||||
* target_rate = X, rate->fixed = 0 means all rates <= X */
|
||||
sdata->bss->max_ratectrl_rateidx = -1;
|
||||
sdata->bss->force_unicast_rateidx = -1;
|
||||
sdata->max_ratectrl_rateidx = -1;
|
||||
sdata->force_unicast_rateidx = -1;
|
||||
if (rate->value < 0)
|
||||
return 0;
|
||||
|
||||
|
@ -645,9 +635,9 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
|
|||
int this_rate = brate->bitrate;
|
||||
|
||||
if (target_rate == this_rate) {
|
||||
sdata->bss->max_ratectrl_rateidx = i;
|
||||
sdata->max_ratectrl_rateidx = i;
|
||||
if (rate->fixed)
|
||||
sdata->bss->force_unicast_rateidx = i;
|
||||
sdata->force_unicast_rateidx = i;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -1009,6 +999,45 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_ioctl_siwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *wrq,
|
||||
char *extra)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
|
||||
if (wrq->disabled) {
|
||||
conf->flags &= ~IEEE80211_CONF_PS;
|
||||
return ieee80211_hw_config(local);
|
||||
}
|
||||
|
||||
switch (wrq->flags & IW_POWER_MODE) {
|
||||
case IW_POWER_ON: /* If not specified */
|
||||
case IW_POWER_MODE: /* If set all mask */
|
||||
case IW_POWER_ALL_R: /* If explicitely state all */
|
||||
conf->flags |= IEEE80211_CONF_PS;
|
||||
break;
|
||||
default: /* Otherwise we don't support it */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ieee80211_hw_config(local);
|
||||
}
|
||||
|
||||
static int ieee80211_ioctl_giwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *wrqu,
|
||||
char *extra)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
|
||||
wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_ioctl_siwauth(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *data, char *extra)
|
||||
|
@ -1211,8 +1240,8 @@ static const iw_handler ieee80211_handler[] =
|
|||
(iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
|
||||
(iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */
|
||||
(iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */
|
||||
(iw_handler) NULL, /* SIOCSIWPOWER */
|
||||
(iw_handler) NULL, /* SIOCGIWPOWER */
|
||||
(iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */
|
||||
(iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */
|
||||
(iw_handler) NULL, /* -- hole -- */
|
||||
(iw_handler) NULL, /* -- hole -- */
|
||||
(iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */
|
||||
|
|
|
@ -29,3 +29,14 @@ config WIRELESS_EXT
|
|||
|
||||
Say N (if you can) unless you know you need wireless
|
||||
extensions for external modules.
|
||||
|
||||
config WIRELESS_EXT_SYSFS
|
||||
bool "Wireless extensions sysfs files"
|
||||
default y
|
||||
depends on WIRELESS_EXT && SYSFS
|
||||
help
|
||||
This option enables the deprecated wireless statistics
|
||||
files in /sys/class/net/*/wireless/. The same information
|
||||
is available via the ioctls as well.
|
||||
|
||||
Say Y if you have programs using it (we don't know of any).
|
||||
|
|
Загрузка…
Ссылка в новой задаче