Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
@@ -16,12 +16,12 @@
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
u16 initiator, u16 reason)
|
||||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
int i;
|
||||
|
||||
/* check if TID is in operational state */
|
||||
@@ -41,8 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
sta->sta.addr, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL))
|
||||
if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL))
|
||||
printk(KERN_DEBUG "HW problem - can not stop rx "
|
||||
"aggregation for tid %d\n", tid);
|
||||
|
||||
@@ -68,6 +68,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
spin_lock_bh(&sta->lock);
|
||||
/* free resources */
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_time);
|
||||
|
||||
if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) {
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]);
|
||||
@@ -268,19 +269,23 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
/* prepare reordering buffer */
|
||||
tid_agg_rx->reorder_buf =
|
||||
kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
|
||||
if (!tid_agg_rx->reorder_buf) {
|
||||
tid_agg_rx->reorder_time =
|
||||
kcalloc(buf_size, sizeof(unsigned long), GFP_ATOMIC);
|
||||
if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "can not allocate reordering buffer "
|
||||
"to tid %d\n", tid);
|
||||
#endif
|
||||
kfree(tid_agg_rx->reorder_buf);
|
||||
kfree(tid_agg_rx->reorder_time);
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]);
|
||||
sta->ampdu_mlme.tid_rx[tid] = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "wme.h"
|
||||
|
||||
/**
|
||||
@@ -134,8 +135,8 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
||||
|
||||
ret = local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_STOP,
|
||||
&sta->sta, tid, NULL);
|
||||
ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP,
|
||||
&sta->sta, tid, NULL);
|
||||
|
||||
/* HW shall not deny going back to legacy */
|
||||
if (WARN_ON(ret)) {
|
||||
@@ -306,8 +307,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
|
||||
start_seq_num = sta->tid_seq[tid];
|
||||
|
||||
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
|
||||
if (ret) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
@@ -418,8 +419,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
||||
ieee80211_agg_splice_finish(local, sta, tid);
|
||||
spin_unlock(&local->ampdu_lock);
|
||||
|
||||
local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
&sta->sta, tid, NULL);
|
||||
drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
&sta->sta, tid, NULL);
|
||||
}
|
||||
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/rcupdate.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "cfg.h"
|
||||
#include "rate.h"
|
||||
#include "mesh.h"
|
||||
@@ -245,12 +246,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
iv32 = key->u.tkip.tx.iv32;
|
||||
iv16 = key->u.tkip.tx.iv16;
|
||||
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
sdata->local->ops->get_tkip_seq)
|
||||
sdata->local->ops->get_tkip_seq(
|
||||
local_to_hw(sdata->local),
|
||||
key->conf.hw_key_idx,
|
||||
&iv32, &iv16);
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
|
||||
drv_get_tkip_seq(sdata->local,
|
||||
key->conf.hw_key_idx,
|
||||
&iv32, &iv16);
|
||||
|
||||
seq[0] = iv16 & 0xff;
|
||||
seq[1] = (iv16 >> 8) & 0xff;
|
||||
@@ -451,18 +450,11 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
* This is a kludge. beacon interval should really be part
|
||||
* of the beacon information.
|
||||
*/
|
||||
if (params->interval && (sdata->local->hw.conf.beacon_int !=
|
||||
params->interval)) {
|
||||
sdata->local->hw.conf.beacon_int = params->interval;
|
||||
err = ieee80211_hw_config(sdata->local,
|
||||
IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
/*
|
||||
* We updated some parameter so if below bails out
|
||||
* it's not an error.
|
||||
*/
|
||||
err = 0;
|
||||
if (params->interval &&
|
||||
(sdata->vif.bss_conf.beacon_int != params->interval)) {
|
||||
sdata->vif.bss_conf.beacon_int = params->interval;
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
BSS_CHANGED_BEACON_INT);
|
||||
}
|
||||
|
||||
/* Need to have a beacon head if we don't have one yet */
|
||||
@@ -528,8 +520,9 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
kfree(old);
|
||||
|
||||
return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
|
||||
IEEE80211_IFCC_BEACON_ENABLED);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
|
||||
BSS_CHANGED_BEACON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
@@ -580,7 +573,8 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
|
||||
synchronize_rcu();
|
||||
kfree(old);
|
||||
|
||||
return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
|
||||
@@ -1120,7 +1114,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
|
||||
p.cw_max = params->cwmax;
|
||||
p.cw_min = params->cwmin;
|
||||
p.txop = params->txop;
|
||||
if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) {
|
||||
if (drv_conf_tx(local, params->queue, &p)) {
|
||||
printk(KERN_DEBUG "%s: failed to set TX queue "
|
||||
"parameters for queue %d\n", local->mdev->name,
|
||||
params->queue);
|
||||
@@ -1301,16 +1295,13 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
|
||||
static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
int err;
|
||||
|
||||
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
|
||||
int err;
|
||||
err = drv_set_rts_threshold(local, wiphy->rts_threshold);
|
||||
|
||||
if (local->ops->set_rts_threshold) {
|
||||
err = local->ops->set_rts_threshold(
|
||||
local_to_hw(local), wiphy->rts_threshold);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (changed & WIPHY_PARAM_RETRY_SHORT)
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "rate.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
@@ -70,11 +71,10 @@ static ssize_t tsf_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
u64 tsf = 0;
|
||||
u64 tsf;
|
||||
char buf[100];
|
||||
|
||||
if (local->ops->get_tsf)
|
||||
tsf = local->ops->get_tsf(local_to_hw(local));
|
||||
tsf = drv_get_tsf(local);
|
||||
|
||||
snprintf(buf, sizeof(buf), "0x%016llx\n", (unsigned long long) tsf);
|
||||
|
||||
@@ -97,13 +97,13 @@ static ssize_t tsf_write(struct file *file,
|
||||
|
||||
if (strncmp(buf, "reset", 5) == 0) {
|
||||
if (local->ops->reset_tsf) {
|
||||
local->ops->reset_tsf(local_to_hw(local));
|
||||
drv_reset_tsf(local);
|
||||
printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy));
|
||||
}
|
||||
} else {
|
||||
tsf = simple_strtoul(buf, NULL, 0);
|
||||
if (local->ops->set_tsf) {
|
||||
local->ops->set_tsf(local_to_hw(local), tsf);
|
||||
drv_set_tsf(local, tsf);
|
||||
printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf);
|
||||
}
|
||||
}
|
||||
@@ -150,14 +150,12 @@ static ssize_t format_devstat_counter(struct ieee80211_local *local,
|
||||
char buf[20];
|
||||
int res;
|
||||
|
||||
if (!local->ops->get_stats)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rtnl_lock();
|
||||
res = local->ops->get_stats(local_to_hw(local), &stats);
|
||||
res = drv_get_stats(local, &stats);
|
||||
rtnl_unlock();
|
||||
if (!res)
|
||||
res = printvalue(&stats, buf, sizeof(buf));
|
||||
if (res)
|
||||
return res;
|
||||
res = printvalue(&stats, buf, sizeof(buf));
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
|
||||
}
|
||||
|
||||
|
184
net/mac80211/driver-ops.h
Normal file
184
net/mac80211/driver-ops.h
Normal file
@@ -0,0 +1,184 @@
|
||||
#ifndef __MAC80211_DRIVER_OPS
|
||||
#define __MAC80211_DRIVER_OPS
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
|
||||
static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
{
|
||||
return local->ops->tx(&local->hw, skb);
|
||||
}
|
||||
|
||||
static inline int drv_start(struct ieee80211_local *local)
|
||||
{
|
||||
return local->ops->start(&local->hw);
|
||||
}
|
||||
|
||||
static inline void drv_stop(struct ieee80211_local *local)
|
||||
{
|
||||
local->ops->stop(&local->hw);
|
||||
}
|
||||
|
||||
static inline int drv_add_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_if_init_conf *conf)
|
||||
{
|
||||
return local->ops->add_interface(&local->hw, conf);
|
||||
}
|
||||
|
||||
static inline void drv_remove_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_if_init_conf *conf)
|
||||
{
|
||||
local->ops->remove_interface(&local->hw, conf);
|
||||
}
|
||||
|
||||
static inline int drv_config(struct ieee80211_local *local, u32 changed)
|
||||
{
|
||||
return local->ops->config(&local->hw, changed);
|
||||
}
|
||||
|
||||
static inline void drv_bss_info_changed(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *info,
|
||||
u32 changed)
|
||||
{
|
||||
if (local->ops->bss_info_changed)
|
||||
local->ops->bss_info_changed(&local->hw, vif, info, changed);
|
||||
}
|
||||
|
||||
static inline void drv_configure_filter(struct ieee80211_local *local,
|
||||
unsigned int changed_flags,
|
||||
unsigned int *total_flags,
|
||||
int mc_count,
|
||||
struct dev_addr_list *mc_list)
|
||||
{
|
||||
local->ops->configure_filter(&local->hw, changed_flags, total_flags,
|
||||
mc_count, mc_list);
|
||||
}
|
||||
|
||||
static inline int drv_set_tim(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta, bool set)
|
||||
{
|
||||
if (local->ops->set_tim)
|
||||
return local->ops->set_tim(&local->hw, sta, set);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int drv_set_key(struct ieee80211_local *local,
|
||||
enum set_key_cmd cmd, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
return local->ops->set_key(&local->hw, cmd, vif, sta, key);
|
||||
}
|
||||
|
||||
static inline void drv_update_tkip_key(struct ieee80211_local *local,
|
||||
struct ieee80211_key_conf *conf,
|
||||
const u8 *address, u32 iv32,
|
||||
u16 *phase1key)
|
||||
{
|
||||
if (local->ops->update_tkip_key)
|
||||
local->ops->update_tkip_key(&local->hw, conf, address,
|
||||
iv32, phase1key);
|
||||
}
|
||||
|
||||
static inline int drv_hw_scan(struct ieee80211_local *local,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
return local->ops->hw_scan(&local->hw, req);
|
||||
}
|
||||
|
||||
static inline void drv_sw_scan_start(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->ops->sw_scan_start)
|
||||
local->ops->sw_scan_start(&local->hw);
|
||||
}
|
||||
|
||||
static inline void drv_sw_scan_complete(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->ops->sw_scan_complete)
|
||||
local->ops->sw_scan_complete(&local->hw);
|
||||
}
|
||||
|
||||
static inline int drv_get_stats(struct ieee80211_local *local,
|
||||
struct ieee80211_low_level_stats *stats)
|
||||
{
|
||||
if (!local->ops->get_stats)
|
||||
return -EOPNOTSUPP;
|
||||
return local->ops->get_stats(&local->hw, stats);
|
||||
}
|
||||
|
||||
static inline void drv_get_tkip_seq(struct ieee80211_local *local,
|
||||
u8 hw_key_idx, u32 *iv32, u16 *iv16)
|
||||
{
|
||||
if (local->ops->get_tkip_seq)
|
||||
local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16);
|
||||
}
|
||||
|
||||
static inline int drv_set_rts_threshold(struct ieee80211_local *local,
|
||||
u32 value)
|
||||
{
|
||||
if (local->ops->set_rts_threshold)
|
||||
return local->ops->set_rts_threshold(&local->hw, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void drv_sta_notify(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd cmd,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
if (local->ops->sta_notify)
|
||||
local->ops->sta_notify(&local->hw, vif, cmd, sta);
|
||||
}
|
||||
|
||||
static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
if (local->ops->conf_tx)
|
||||
return local->ops->conf_tx(&local->hw, queue, params);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int drv_get_tx_stats(struct ieee80211_local *local,
|
||||
struct ieee80211_tx_queue_stats *stats)
|
||||
{
|
||||
return local->ops->get_tx_stats(&local->hw, stats);
|
||||
}
|
||||
|
||||
static inline u64 drv_get_tsf(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->ops->get_tsf)
|
||||
return local->ops->get_tsf(&local->hw);
|
||||
return -1ULL;
|
||||
}
|
||||
|
||||
static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
|
||||
{
|
||||
if (local->ops->set_tsf)
|
||||
local->ops->set_tsf(&local->hw, tsf);
|
||||
}
|
||||
|
||||
static inline void drv_reset_tsf(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->ops->reset_tsf)
|
||||
local->ops->reset_tsf(&local->hw);
|
||||
}
|
||||
|
||||
static inline int drv_tx_last_beacon(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->ops->tx_last_beacon)
|
||||
return local->ops->tx_last_beacon(&local->hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int drv_ampdu_action(struct ieee80211_local *local,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn)
|
||||
{
|
||||
if (local->ops->ampdu_action)
|
||||
return local->ops->ampdu_action(&local->hw, action,
|
||||
sta, tid, ssn);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
@@ -22,6 +22,7 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "rate.h"
|
||||
|
||||
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
|
||||
@@ -73,11 +74,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos;
|
||||
struct ieee80211_supported_band *sband;
|
||||
u32 bss_change;
|
||||
|
||||
if (local->ops->reset_tsf) {
|
||||
/* Reset own TSF to allow time synchronization work. */
|
||||
local->ops->reset_tsf(local_to_hw(local));
|
||||
}
|
||||
|
||||
/* Reset own TSF to allow time synchronization work. */
|
||||
drv_reset_tsf(local);
|
||||
|
||||
skb = ifibss->skb;
|
||||
rcu_assign_pointer(ifibss->presp, NULL);
|
||||
@@ -92,15 +93,12 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
memcpy(ifibss->bssid, bssid, ETH_ALEN);
|
||||
|
||||
local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;
|
||||
|
||||
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
|
||||
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
|
||||
|
||||
local->oper_channel = chan;
|
||||
local->oper_channel_type = NL80211_CHAN_NO_HT;
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
|
||||
sband = local->hw.wiphy->bands[chan->band];
|
||||
|
||||
/* Build IBSS probe response */
|
||||
@@ -111,7 +109,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
memset(mgmt->da, 0xff, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
|
||||
mgmt->u.beacon.beacon_int = cpu_to_le16(local->hw.conf.beacon_int);
|
||||
mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int);
|
||||
mgmt->u.beacon.timestamp = cpu_to_le64(tsf);
|
||||
mgmt->u.beacon.capab_info = cpu_to_le16(capability);
|
||||
|
||||
@@ -156,8 +154,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
rcu_assign_pointer(ifibss->presp, skb);
|
||||
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
|
||||
IEEE80211_IFCC_BEACON_ENABLED);
|
||||
sdata->vif.bss_conf.beacon_int = beacon_int;
|
||||
bss_change = BSS_CHANGED_BEACON_INT;
|
||||
bss_change |= ieee80211_reset_erp_info(sdata);
|
||||
bss_change |= BSS_CHANGED_BSSID;
|
||||
bss_change |= BSS_CHANGED_BEACON;
|
||||
bss_change |= BSS_CHANGED_BEACON_ENABLED;
|
||||
ieee80211_bss_info_change_notify(sdata, bss_change);
|
||||
|
||||
rates = 0;
|
||||
for (i = 0; i < supp_rates_len; i++) {
|
||||
@@ -181,8 +184,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_bss *bss)
|
||||
{
|
||||
u16 beacon_int = bss->cbss.beacon_interval;
|
||||
|
||||
if (beacon_int < 10)
|
||||
beacon_int = 10;
|
||||
|
||||
__ieee80211_sta_join_ibss(sdata, bss->cbss.bssid,
|
||||
bss->cbss.beacon_interval,
|
||||
beacon_int,
|
||||
bss->cbss.channel,
|
||||
bss->supp_rates_len, bss->supp_rates,
|
||||
bss->cbss.capability,
|
||||
@@ -307,12 +315,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
bitrates[rx_status->rate_idx].bitrate;
|
||||
|
||||
rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
|
||||
} else if (local && local->ops && local->ops->get_tsf)
|
||||
/* second best option: get current TSF */
|
||||
rx_timestamp = local->ops->get_tsf(local_to_hw(local));
|
||||
else
|
||||
/* can't merge without knowing the TSF */
|
||||
rx_timestamp = -1LLU;
|
||||
} else {
|
||||
/*
|
||||
* second best option: get current TSF
|
||||
* (will return -1 if not supported)
|
||||
*/
|
||||
rx_timestamp = drv_get_tsf(local);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
|
||||
@@ -432,14 +441,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
|
||||
"IBSS networks with same SSID (merge)\n", sdata->dev->name);
|
||||
|
||||
/* XXX maybe racy? */
|
||||
if (sdata->local->scan_req)
|
||||
return;
|
||||
|
||||
memcpy(sdata->local->int_scan_req.ssids[0].ssid,
|
||||
ifibss->ssid, IEEE80211_MAX_SSID_LEN);
|
||||
sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len;
|
||||
ieee80211_request_scan(sdata, &sdata->local->int_scan_req);
|
||||
ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len);
|
||||
}
|
||||
|
||||
static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
@@ -471,9 +473,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
sband = local->hw.wiphy->bands[ifibss->channel->band];
|
||||
|
||||
if (local->hw.conf.beacon_int == 0)
|
||||
local->hw.conf.beacon_int = 100;
|
||||
|
||||
capability = WLAN_CAPABILITY_IBSS;
|
||||
|
||||
if (sdata->default_key)
|
||||
@@ -487,7 +486,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
*pos++ = (u8) (rate / 5);
|
||||
}
|
||||
|
||||
__ieee80211_sta_join_ibss(sdata, bssid, local->hw.conf.beacon_int,
|
||||
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
|
||||
ifibss->channel, sband->n_bitrates,
|
||||
supp_rates, capability, 0);
|
||||
}
|
||||
@@ -552,15 +551,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
|
||||
"join\n", sdata->dev->name);
|
||||
|
||||
/* XXX maybe racy? */
|
||||
if (local->scan_req)
|
||||
return;
|
||||
|
||||
memcpy(local->int_scan_req.ssids[0].ssid,
|
||||
ifibss->ssid, IEEE80211_MAX_SSID_LEN);
|
||||
local->int_scan_req.ssids[0].ssid_len =
|
||||
ifibss->ssid_len;
|
||||
ieee80211_request_scan(sdata, &local->int_scan_req);
|
||||
ieee80211_request_internal_scan(sdata, ifibss->ssid,
|
||||
ifibss->ssid_len);
|
||||
} else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) {
|
||||
int interval = IEEE80211_SCAN_INTERVAL;
|
||||
|
||||
@@ -600,10 +592,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
len < 24 + 2 || !ifibss->presp)
|
||||
return;
|
||||
|
||||
if (local->ops->tx_last_beacon)
|
||||
tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local));
|
||||
else
|
||||
tx_last_beacon = 1;
|
||||
tx_last_beacon = drv_tx_last_beacon(local);
|
||||
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
|
||||
@@ -786,8 +775,12 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||
continue;
|
||||
if (!sdata->u.ibss.ssid_len)
|
||||
continue;
|
||||
sdata->u.ibss.last_scan_completed = jiffies;
|
||||
ieee80211_sta_find_ibss(sdata);
|
||||
}
|
||||
@@ -827,15 +820,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
|
||||
sdata->u.ibss.ssid_len = params->ssid_len;
|
||||
|
||||
if (params->bssid) {
|
||||
memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
|
||||
sdata->u.ibss.fixed_bssid = true;
|
||||
} else
|
||||
sdata->u.ibss.fixed_bssid = false;
|
||||
|
||||
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
|
||||
|
||||
sdata->u.ibss.channel = params->channel;
|
||||
sdata->u.ibss.fixed_channel = params->channel_fixed;
|
||||
|
||||
@@ -859,6 +851,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
|
||||
sdata->u.ibss.ibss_join_req = jiffies;
|
||||
|
||||
memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
|
||||
|
||||
/*
|
||||
* The ssid_len setting below is used to see whether
|
||||
* we are active, and we need all other settings
|
||||
* before that may get visible.
|
||||
*/
|
||||
mb();
|
||||
|
||||
sdata->u.ibss.ssid_len = params->ssid_len;
|
||||
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
|
||||
set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
|
||||
queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work);
|
||||
|
||||
@@ -880,12 +885,15 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
||||
kfree(sdata->u.ibss.ie);
|
||||
skb = sdata->u.ibss.presp;
|
||||
rcu_assign_pointer(sdata->u.ibss.presp, NULL);
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
synchronize_rcu();
|
||||
kfree_skb(skb);
|
||||
|
||||
skb_queue_purge(&sdata->u.ibss.skb_queue);
|
||||
memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
|
||||
sdata->u.ibss.ssid_len = 0;
|
||||
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -248,9 +248,8 @@ struct mesh_preq_queue {
|
||||
#define IEEE80211_STA_EXT_SME BIT(17)
|
||||
/* flags for MLME request */
|
||||
#define IEEE80211_STA_REQ_SCAN 0
|
||||
#define IEEE80211_STA_REQ_DIRECT_PROBE 1
|
||||
#define IEEE80211_STA_REQ_AUTH 2
|
||||
#define IEEE80211_STA_REQ_RUN 3
|
||||
#define IEEE80211_STA_REQ_AUTH 1
|
||||
#define IEEE80211_STA_REQ_RUN 2
|
||||
|
||||
/* bitfield of allowed auth algs */
|
||||
#define IEEE80211_AUTH_ALG_OPEN BIT(0)
|
||||
@@ -659,6 +658,7 @@ struct ieee80211_local {
|
||||
|
||||
|
||||
/* Scanning and BSS list */
|
||||
struct mutex scan_mtx;
|
||||
bool sw_scanning, hw_scanning;
|
||||
struct cfg80211_ssid scan_ssid;
|
||||
struct cfg80211_scan_request int_scan_req;
|
||||
@@ -905,7 +905,6 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
|
||||
|
||||
|
||||
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed);
|
||||
int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
|
||||
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
|
||||
void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
u32 changed);
|
||||
@@ -947,6 +946,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
/* scan/BSS handling */
|
||||
void ieee80211_scan_work(struct work_struct *work);
|
||||
int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *ssid, u8 ssid_len);
|
||||
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_scan_request *req);
|
||||
int ieee80211_scan_results(struct ieee80211_local *local,
|
||||
@@ -960,9 +961,6 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
|
||||
const char *ie, size_t len);
|
||||
|
||||
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
|
||||
void ieee80211_scan_failed(struct ieee80211_local *local);
|
||||
int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
struct cfg80211_scan_request *req);
|
||||
struct ieee80211_bss *
|
||||
ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
@@ -987,6 +985,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type);
|
||||
void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_remove_interfaces(struct ieee80211_local *local);
|
||||
u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local);
|
||||
|
||||
/* tx handling */
|
||||
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "debugfs_netdev.h"
|
||||
#include "mesh.h"
|
||||
#include "led.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
/**
|
||||
* DOC: Interface list locking
|
||||
@@ -164,9 +165,7 @@ static int ieee80211_open(struct net_device *dev)
|
||||
}
|
||||
|
||||
if (local->open_count == 0) {
|
||||
res = 0;
|
||||
if (local->ops->start)
|
||||
res = local->ops->start(local_to_hw(local));
|
||||
res = drv_start(local);
|
||||
if (res)
|
||||
goto err_del_bss;
|
||||
/* we're brought up, everything changes */
|
||||
@@ -199,8 +198,8 @@ static int ieee80211_open(struct net_device *dev)
|
||||
* Validate the MAC address for this device.
|
||||
*/
|
||||
if (!is_valid_ether_addr(dev->dev_addr)) {
|
||||
if (!local->open_count && local->ops->stop)
|
||||
local->ops->stop(local_to_hw(local));
|
||||
if (!local->open_count)
|
||||
drv_stop(local);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
@@ -241,7 +240,7 @@ static int ieee80211_open(struct net_device *dev)
|
||||
conf.vif = &sdata->vif;
|
||||
conf.type = sdata->vif.type;
|
||||
conf.mac_addr = dev->dev_addr;
|
||||
res = local->ops->add_interface(local_to_hw(local), &conf);
|
||||
res = drv_add_interface(local, &conf);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
|
||||
@@ -302,6 +301,8 @@ static int ieee80211_open(struct net_device *dev)
|
||||
if (sdata->flags & IEEE80211_SDATA_PROMISC)
|
||||
atomic_inc(&local->iff_promiscs);
|
||||
|
||||
hw_reconf_flags |= __ieee80211_recalc_idle(local);
|
||||
|
||||
local->open_count++;
|
||||
if (hw_reconf_flags) {
|
||||
ieee80211_hw_config(local, hw_reconf_flags);
|
||||
@@ -328,10 +329,10 @@ static int ieee80211_open(struct net_device *dev)
|
||||
|
||||
return 0;
|
||||
err_del_interface:
|
||||
local->ops->remove_interface(local_to_hw(local), &conf);
|
||||
drv_remove_interface(local, &conf);
|
||||
err_stop:
|
||||
if (!local->open_count && local->ops->stop)
|
||||
local->ops->stop(local_to_hw(local));
|
||||
if (!local->open_count)
|
||||
drv_stop(local);
|
||||
err_del_bss:
|
||||
sdata->bss = NULL;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
@@ -544,17 +545,20 @@ static int ieee80211_stop(struct net_device *dev)
|
||||
conf.mac_addr = dev->dev_addr;
|
||||
/* disable all keys for as long as this netdev is down */
|
||||
ieee80211_disable_keys(sdata);
|
||||
local->ops->remove_interface(local_to_hw(local), &conf);
|
||||
drv_remove_interface(local, &conf);
|
||||
}
|
||||
|
||||
sdata->bss = NULL;
|
||||
|
||||
hw_reconf_flags |= __ieee80211_recalc_idle(local);
|
||||
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
|
||||
if (local->open_count == 0) {
|
||||
if (netif_running(local->mdev))
|
||||
dev_close(local->mdev);
|
||||
|
||||
if (local->ops->stop)
|
||||
local->ops->stop(local_to_hw(local));
|
||||
drv_stop(local);
|
||||
|
||||
ieee80211_led_radio(local, 0);
|
||||
|
||||
@@ -567,8 +571,6 @@ static int ieee80211_stop(struct net_device *dev)
|
||||
hw_reconf_flags = 0;
|
||||
}
|
||||
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
|
||||
/* do after stop to avoid reconfiguring when we stop anyway */
|
||||
if (hw_reconf_flags)
|
||||
ieee80211_hw_config(local, hw_reconf_flags);
|
||||
@@ -894,3 +896,73 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
|
||||
unregister_netdevice(sdata->dev);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ieee80211_idle_off(struct ieee80211_local *local,
|
||||
const char *reason)
|
||||
{
|
||||
if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: device no longer idle - %s\n",
|
||||
wiphy_name(local->hw.wiphy), reason);
|
||||
#endif
|
||||
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
|
||||
return IEEE80211_CONF_CHANGE_IDLE;
|
||||
}
|
||||
|
||||
static u32 ieee80211_idle_on(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: device now idle\n",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
#endif
|
||||
|
||||
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
|
||||
return IEEE80211_CONF_CHANGE_IDLE;
|
||||
}
|
||||
|
||||
u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int count = 0;
|
||||
|
||||
if (local->hw_scanning || local->sw_scanning)
|
||||
return ieee80211_idle_off(local, "scanning");
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
/* do not count disabled managed interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED)
|
||||
continue;
|
||||
/* do not count unused IBSS interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
!sdata->u.ibss.ssid_len)
|
||||
continue;
|
||||
/* count everything else */
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return ieee80211_idle_on(local);
|
||||
else
|
||||
return ieee80211_idle_off(local, "in use");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
{
|
||||
u32 chg;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
chg = __ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
ieee80211_hw_config(local, chg);
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "debugfs_key.h"
|
||||
#include "aes_ccm.h"
|
||||
#include "aes_cmac.h"
|
||||
@@ -136,8 +137,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY,
|
||||
&sdata->vif, sta, &key->conf);
|
||||
ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
|
||||
|
||||
if (!ret) {
|
||||
spin_lock(&todo_lock);
|
||||
@@ -179,8 +179,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY,
|
||||
&sdata->vif, sta, &key->conf);
|
||||
ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif,
|
||||
sta, &key->conf);
|
||||
|
||||
if (ret)
|
||||
printk(KERN_ERR "mac80211-%s: failed to remove key "
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "rate.h"
|
||||
#include "mesh.h"
|
||||
#include "wep.h"
|
||||
@@ -81,10 +82,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
|
||||
/* be a bit nasty */
|
||||
new_flags |= (1<<31);
|
||||
|
||||
local->ops->configure_filter(local_to_hw(local),
|
||||
changed_flags, &new_flags,
|
||||
local->mdev->mc_count,
|
||||
local->mdev->mc_list);
|
||||
drv_configure_filter(local, changed_flags, &new_flags,
|
||||
local->mdev->mc_count,
|
||||
local->mdev->mc_list);
|
||||
|
||||
WARN_ON(new_flags & (1<<31));
|
||||
|
||||
@@ -152,82 +152,6 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev)
|
||||
ieee80211_configure_filter(local);
|
||||
}
|
||||
|
||||
/* everything else */
|
||||
|
||||
int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_conf conf;
|
||||
|
||||
if (WARN_ON(!netif_running(sdata->dev)))
|
||||
return 0;
|
||||
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
conf.bssid = sdata->u.mgd.bssid;
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
conf.bssid = sdata->u.ibss.bssid;
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
conf.bssid = sdata->dev->dev_addr;
|
||||
else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
static const u8 zero[ETH_ALEN] = { 0 };
|
||||
conf.bssid = zero;
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!local->ops->config_interface)
|
||||
return 0;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
break;
|
||||
default:
|
||||
/* do not warn to simplify caller in scan.c */
|
||||
changed &= ~IEEE80211_IFCC_BEACON_ENABLED;
|
||||
if (WARN_ON(changed & IEEE80211_IFCC_BEACON))
|
||||
return -EINVAL;
|
||||
changed &= ~IEEE80211_IFCC_BEACON;
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_IFCC_BEACON_ENABLED) {
|
||||
if (local->sw_scanning) {
|
||||
conf.enable_beacon = false;
|
||||
} else {
|
||||
/*
|
||||
* Beacon should be enabled, but AP mode must
|
||||
* check whether there is a beacon configured.
|
||||
*/
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
conf.enable_beacon =
|
||||
!!rcu_dereference(sdata->u.ap.beacon);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
conf.enable_beacon = !!sdata->u.ibss.presp;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
conf.enable_beacon = true;
|
||||
break;
|
||||
default:
|
||||
/* not reached */
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conf.changed = changed;
|
||||
|
||||
return local->ops->config_interface(local_to_hw(local),
|
||||
&sdata->vif, &conf);
|
||||
}
|
||||
|
||||
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
||||
{
|
||||
struct ieee80211_channel *chan;
|
||||
@@ -268,7 +192,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
||||
}
|
||||
|
||||
if (changed && local->open_count) {
|
||||
ret = local->ops->config(local_to_hw(local), changed);
|
||||
ret = drv_config(local, changed);
|
||||
/*
|
||||
* Goal:
|
||||
* HW reconfiguration should never fail, the driver has told
|
||||
@@ -294,17 +218,77 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
|
||||
return;
|
||||
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
if (local->ops->bss_info_changed)
|
||||
local->ops->bss_info_changed(local_to_hw(local),
|
||||
&sdata->vif,
|
||||
&sdata->vif.bss_conf,
|
||||
changed);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
sdata->vif.bss_conf.bssid = sdata->dev->dev_addr;
|
||||
else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
static const u8 zero[ETH_ALEN] = { 0 };
|
||||
sdata->vif.bss_conf.bssid = zero;
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
break;
|
||||
default:
|
||||
/* do not warn to simplify caller in scan.c */
|
||||
changed &= ~BSS_CHANGED_BEACON_ENABLED;
|
||||
if (WARN_ON(changed & BSS_CHANGED_BEACON))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
if (local->sw_scanning) {
|
||||
sdata->vif.bss_conf.enable_beacon = false;
|
||||
} else {
|
||||
/*
|
||||
* Beacon should be enabled, but AP mode must
|
||||
* check whether there is a beacon configured.
|
||||
*/
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
sdata->vif.bss_conf.enable_beacon =
|
||||
!!rcu_dereference(sdata->u.ap.beacon);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
sdata->vif.bss_conf.enable_beacon =
|
||||
!!rcu_dereference(sdata->u.ibss.presp);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
sdata->vif.bss_conf.enable_beacon = true;
|
||||
break;
|
||||
default:
|
||||
/* not reached */
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drv_bss_info_changed(local, &sdata->vif,
|
||||
&sdata->vif.bss_conf, changed);
|
||||
|
||||
/*
|
||||
* DEPRECATED
|
||||
*
|
||||
* ~changed is just there to not do this at resume time
|
||||
*/
|
||||
if (changed & BSS_CHANGED_BEACON_INT && ~changed) {
|
||||
local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int;
|
||||
ieee80211_hw_config(local,
|
||||
_IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
|
||||
@@ -783,6 +767,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
|
||||
INIT_LIST_HEAD(&local->interfaces);
|
||||
mutex_init(&local->iflist_mtx);
|
||||
mutex_init(&local->scan_mtx);
|
||||
|
||||
spin_lock_init(&local->key_lock);
|
||||
|
||||
@@ -970,9 +955,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
|
||||
debugfs_hw_add(local);
|
||||
|
||||
if (local->hw.conf.beacon_int < 10)
|
||||
local->hw.conf.beacon_int = 100;
|
||||
|
||||
if (local->hw.max_listen_interval == 0)
|
||||
local->hw.max_listen_interval = 1;
|
||||
|
||||
@@ -1126,6 +1108,7 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
mutex_destroy(&local->iflist_mtx);
|
||||
mutex_destroy(&local->scan_mtx);
|
||||
|
||||
wiphy_free(local->hw.wiphy);
|
||||
}
|
||||
|
@@ -417,7 +417,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
free_plinks = mesh_plink_availables(sdata);
|
||||
if (free_plinks != sdata->u.mesh.accepting_plinks)
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
|
||||
|
||||
ifmsh->housekeeping = false;
|
||||
mod_timer(&ifmsh->housekeeping_timer,
|
||||
@@ -432,8 +432,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
ifmsh->housekeeping = true;
|
||||
queue_work(local->hw.workqueue, &ifmsh->work);
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
|
||||
IEEE80211_IFCC_BEACON_ENABLED);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
|
||||
BSS_CHANGED_BEACON_ENABLED);
|
||||
}
|
||||
|
||||
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "rate.h"
|
||||
#include "led.h"
|
||||
|
||||
@@ -487,6 +488,13 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
|
||||
{
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
|
||||
/*
|
||||
* If we are scanning right now then the parameters will
|
||||
* take effect when scan finishes.
|
||||
*/
|
||||
if (local->hw_scanning || local->sw_scanning)
|
||||
return;
|
||||
|
||||
if (conf->dynamic_ps_timeout > 0 &&
|
||||
!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) {
|
||||
mod_timer(&local->dynamic_ps_timer, jiffies +
|
||||
@@ -555,7 +563,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
||||
maxslp = min_t(int, dtimper,
|
||||
latency / beaconint_us);
|
||||
|
||||
local->hw.conf.max_sleep_interval = maxslp;
|
||||
local->hw.conf.max_sleep_period = maxslp;
|
||||
local->ps_sdata = found;
|
||||
}
|
||||
} else {
|
||||
@@ -676,11 +684,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
|
||||
params.cw_max, params.txop);
|
||||
#endif
|
||||
if (local->ops->conf_tx &&
|
||||
local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) {
|
||||
if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx)
|
||||
printk(KERN_DEBUG "%s: failed to set TX queue "
|
||||
"parameters for queue %d\n", local->mdev->name, queue);
|
||||
}
|
||||
"parameters for queue %d\n", local->mdev->name,
|
||||
queue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,6 +842,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
||||
sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
|
||||
sdata->vif.bss_conf.dtim_period = bss->dtim_period;
|
||||
|
||||
bss_info_changed |= BSS_CHANGED_BEACON_INT;
|
||||
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
|
||||
bss->cbss.capability, bss->has_erp_value, bss->erp_value);
|
||||
|
||||
@@ -882,7 +890,8 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
|
||||
printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
|
||||
sdata->dev->name, ifmgd->bssid);
|
||||
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
|
||||
ieee80211_sta_send_apinfo(sdata);
|
||||
ieee80211_recalc_idle(local);
|
||||
cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
|
||||
|
||||
/*
|
||||
* Most likely AP is not in the range so remove the
|
||||
@@ -907,8 +916,6 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
|
||||
|
||||
set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request);
|
||||
|
||||
/* Direct probe is sent to broadcast address as some APs
|
||||
* will not answer to direct packet in unassociated state.
|
||||
*/
|
||||
@@ -932,6 +939,7 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
|
||||
" timed out\n",
|
||||
sdata->dev->name, ifmgd->bssid);
|
||||
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
|
||||
ieee80211_recalc_idle(local);
|
||||
cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
|
||||
ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
|
||||
sdata->local->hw.conf.channel->center_freq,
|
||||
@@ -1035,6 +1043,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
/* channel(_type) changes are handled by ieee80211_hw_config */
|
||||
local->oper_channel_type = NL80211_CHAN_NO_HT;
|
||||
|
||||
@@ -1115,6 +1125,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
|
||||
" timed out\n",
|
||||
sdata->dev->name, ifmgd->bssid);
|
||||
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
|
||||
ieee80211_recalc_idle(local);
|
||||
cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid);
|
||||
ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
|
||||
sdata->local->hw.conf.channel->center_freq,
|
||||
@@ -1135,6 +1146,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
|
||||
printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
|
||||
"mixed-cell disabled - abort association\n", sdata->dev->name);
|
||||
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
|
||||
ieee80211_recalc_idle(local);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1273,6 +1285,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata)
|
||||
if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
|
||||
/* Wait for SME to request association */
|
||||
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
} else
|
||||
ieee80211_associate(sdata);
|
||||
}
|
||||
@@ -1509,6 +1522,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
|
||||
/* Wait for SME to decide what to do next */
|
||||
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
|
||||
ieee80211_recalc_idle(local);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1730,8 +1744,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
|
||||
|
||||
/* direct probe may be part of the association flow */
|
||||
if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE,
|
||||
&ifmgd->request)) {
|
||||
if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) {
|
||||
printk(KERN_DEBUG "%s direct probe responded\n",
|
||||
sdata->dev->name);
|
||||
ieee80211_authenticate(sdata);
|
||||
@@ -1974,10 +1987,8 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata)
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (local->ops->reset_tsf) {
|
||||
/* Reset own TSF to allow time synchronization work. */
|
||||
local->ops->reset_tsf(local_to_hw(local));
|
||||
}
|
||||
/* Reset own TSF to allow time synchronization work. */
|
||||
drv_reset_tsf(local);
|
||||
|
||||
ifmgd->wmm_last_param_set = -1; /* allow any WMM update */
|
||||
|
||||
@@ -2065,25 +2076,18 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)
|
||||
return 0;
|
||||
} else {
|
||||
if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
|
||||
ifmgd->assoc_scan_tries++;
|
||||
/* XXX maybe racy? */
|
||||
if (local->scan_req)
|
||||
return -1;
|
||||
memcpy(local->int_scan_req.ssids[0].ssid,
|
||||
ifmgd->ssid, IEEE80211_MAX_SSID_LEN);
|
||||
if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL)
|
||||
local->int_scan_req.ssids[0].ssid_len = 0;
|
||||
else
|
||||
local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len;
|
||||
|
||||
if (ieee80211_start_scan(sdata, &local->int_scan_req))
|
||||
ieee80211_scan_failed(local);
|
||||
ifmgd->assoc_scan_tries++;
|
||||
|
||||
ieee80211_request_internal_scan(sdata, ifmgd->ssid,
|
||||
ssid_len);
|
||||
|
||||
ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
|
||||
set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
|
||||
} else {
|
||||
ifmgd->assoc_scan_tries = 0;
|
||||
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
|
||||
ieee80211_recalc_idle(local);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -2115,14 +2119,8 @@ static void ieee80211_sta_work(struct work_struct *work)
|
||||
ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE &&
|
||||
ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE &&
|
||||
test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) {
|
||||
/*
|
||||
* The call to ieee80211_start_scan can fail but ieee80211_request_scan
|
||||
* (which queued ieee80211_sta_work) did not return an error. Thus, call
|
||||
* ieee80211_scan_failed here if ieee80211_start_scan fails in order to
|
||||
* notify the scan requester.
|
||||
*/
|
||||
if (ieee80211_start_scan(sdata, local->scan_req))
|
||||
ieee80211_scan_failed(local);
|
||||
queue_delayed_work(local->hw.workqueue, &local->scan_work,
|
||||
round_jiffies_relative(0));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2133,6 +2131,8 @@ static void ieee80211_sta_work(struct work_struct *work)
|
||||
} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request))
|
||||
return;
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
switch (ifmgd->state) {
|
||||
case IEEE80211_STA_MLME_DISABLED:
|
||||
break;
|
||||
@@ -2291,12 +2291,8 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
|
||||
ifmgd->flags &= ~IEEE80211_STA_BSSID_SET;
|
||||
}
|
||||
|
||||
if (netif_running(sdata->dev)) {
|
||||
if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) {
|
||||
printk(KERN_DEBUG "%s: Failed to config new BSSID to "
|
||||
"the low-level driver\n", sdata->dev->name);
|
||||
}
|
||||
}
|
||||
if (netif_running(sdata->dev))
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
|
||||
|
||||
return ieee80211_sta_commit(sdata);
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include <net/rtnetlink.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "led.h"
|
||||
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
@@ -43,8 +44,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
local->ops->sta_notify(hw, &sdata->vif,
|
||||
STA_NOTIFY_REMOVE, &sta->sta);
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
|
||||
&sta->sta);
|
||||
}
|
||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
}
|
||||
@@ -57,7 +58,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
conf.vif = &sdata->vif;
|
||||
conf.type = sdata->vif.type;
|
||||
conf.mac_addr = sdata->dev->dev_addr;
|
||||
local->ops->remove_interface(hw, &conf);
|
||||
drv_remove_interface(local, &conf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +68,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
/* stop hardware */
|
||||
if (local->open_count) {
|
||||
ieee80211_led_radio(local, false);
|
||||
local->ops->stop(hw);
|
||||
drv_stop(local);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@@ -80,8 +80,7 @@ use_low_rate(struct sk_buff *skb)
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
return ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
|
||||
(fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
|
||||
is_multicast_ether_addr(hdr->addr1));
|
||||
(fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA);
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +244,10 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
|
||||
|
||||
if (!sta || !mi || use_low_rate(skb)) {
|
||||
ar[0].idx = rate_lowest_index(sband, sta);
|
||||
ar[0].count = mp->max_retry;
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||
ar[0].count = 1;
|
||||
else
|
||||
ar[0].count = mp->max_retry;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -289,13 +289,15 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
|
||||
info->control.rates[0].count =
|
||||
txrc->hw->conf.short_frame_max_tx_count;
|
||||
|
||||
/* Send management frames and broadcast/multicast data using lowest
|
||||
* rate. */
|
||||
/* Send management frames and NO_ACK data using lowest rate. */
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
if (!sta || !spinfo ||
|
||||
(fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
|
||||
is_multicast_ether_addr(hdr->addr1)) {
|
||||
info->flags & IEEE80211_TX_CTL_NO_ACK) {
|
||||
info->control.rates[0].idx = rate_lowest_index(sband, sta);
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||
info->control.rates[0].count = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "led.h"
|
||||
#include "mesh.h"
|
||||
#include "wep.h"
|
||||
@@ -773,9 +774,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
|
||||
|
||||
atomic_inc(&sdata->bss->num_sta_ps);
|
||||
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
|
||||
if (local->ops->sta_notify)
|
||||
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
|
||||
STA_NOTIFY_SLEEP, &sta->sta);
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
|
||||
sdata->dev->name, sta->sta.addr, sta->sta.aid);
|
||||
@@ -792,9 +791,7 @@ static int ap_sta_ps_end(struct sta_info *sta)
|
||||
atomic_dec(&sdata->bss->num_sta_ps);
|
||||
|
||||
clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
|
||||
if (local->ops->sta_notify)
|
||||
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
|
||||
STA_NOTIFY_AWAKE, &sta->sta);
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
|
||||
|
||||
if (!skb_queue_empty(&sta->ps_tx_buf))
|
||||
sta_info_clear_tim_bit(sta);
|
||||
@@ -2287,6 +2284,43 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
|
||||
}
|
||||
|
||||
|
||||
static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
int index)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_rate *rate;
|
||||
struct ieee80211_rx_status status;
|
||||
|
||||
if (!tid_agg_rx->reorder_buf[index])
|
||||
goto no_frame;
|
||||
|
||||
/* release the reordered frames to stack */
|
||||
memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status));
|
||||
sband = hw->wiphy->bands[status.band];
|
||||
if (status.flag & RX_FLAG_HT)
|
||||
rate = sband->bitrates; /* TODO: HT rates */
|
||||
else
|
||||
rate = &sband->bitrates[status.rate_idx];
|
||||
__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
|
||||
&status, rate);
|
||||
tid_agg_rx->stored_mpdu_num--;
|
||||
tid_agg_rx->reorder_buf[index] = NULL;
|
||||
|
||||
no_frame:
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
|
||||
* the skb was added to the buffer longer than this time ago, the earlier
|
||||
* frames that have not yet been received are assumed to be lost and the skb
|
||||
* can be released for processing. This may also release other skb's from the
|
||||
* reorder buffer if there are no additional gaps between the frames.
|
||||
*/
|
||||
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
|
||||
|
||||
/*
|
||||
* As it function blongs to Rx path it must be called with
|
||||
* the proper rcu_read_lock protection for its flow.
|
||||
@@ -2298,12 +2332,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
|
||||
u16 mpdu_seq_num,
|
||||
int bar_req)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_rx_status status;
|
||||
u16 head_seq_num, buf_size;
|
||||
int index;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_rate *rate;
|
||||
|
||||
buf_size = tid_agg_rx->buf_size;
|
||||
head_seq_num = tid_agg_rx->head_seq_num;
|
||||
@@ -2328,28 +2358,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
|
||||
index = seq_sub(tid_agg_rx->head_seq_num,
|
||||
tid_agg_rx->ssn)
|
||||
% tid_agg_rx->buf_size;
|
||||
|
||||
if (tid_agg_rx->reorder_buf[index]) {
|
||||
/* release the reordered frames to stack */
|
||||
memcpy(&status,
|
||||
tid_agg_rx->reorder_buf[index]->cb,
|
||||
sizeof(status));
|
||||
sband = local->hw.wiphy->bands[status.band];
|
||||
if (status.flag & RX_FLAG_HT) {
|
||||
/* TODO: HT rates */
|
||||
rate = sband->bitrates;
|
||||
} else {
|
||||
rate = &sband->bitrates
|
||||
[status.rate_idx];
|
||||
}
|
||||
__ieee80211_rx_handle_packet(hw,
|
||||
tid_agg_rx->reorder_buf[index],
|
||||
&status, rate);
|
||||
tid_agg_rx->stored_mpdu_num--;
|
||||
tid_agg_rx->reorder_buf[index] = NULL;
|
||||
}
|
||||
tid_agg_rx->head_seq_num =
|
||||
seq_inc(tid_agg_rx->head_seq_num);
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx,
|
||||
index);
|
||||
}
|
||||
if (bar_req)
|
||||
return 1;
|
||||
@@ -2376,26 +2386,50 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
|
||||
|
||||
/* put the frame in the reordering buffer */
|
||||
tid_agg_rx->reorder_buf[index] = skb;
|
||||
tid_agg_rx->reorder_time[index] = jiffies;
|
||||
memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus,
|
||||
sizeof(*rxstatus));
|
||||
tid_agg_rx->stored_mpdu_num++;
|
||||
/* release the buffer until next missing frame */
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
|
||||
% tid_agg_rx->buf_size;
|
||||
while (tid_agg_rx->reorder_buf[index]) {
|
||||
/* release the reordered frame back to stack */
|
||||
memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
|
||||
sizeof(status));
|
||||
sband = local->hw.wiphy->bands[status.band];
|
||||
if (status.flag & RX_FLAG_HT)
|
||||
rate = sband->bitrates; /* TODO: HT rates */
|
||||
else
|
||||
rate = &sband->bitrates[status.rate_idx];
|
||||
__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
|
||||
&status, rate);
|
||||
tid_agg_rx->stored_mpdu_num--;
|
||||
tid_agg_rx->reorder_buf[index] = NULL;
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
if (!tid_agg_rx->reorder_buf[index] &&
|
||||
tid_agg_rx->stored_mpdu_num > 1) {
|
||||
/*
|
||||
* No buffers ready to be released, but check whether any
|
||||
* frames in the reorder buffer have timed out.
|
||||
*/
|
||||
int j;
|
||||
int skipped = 1;
|
||||
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
|
||||
j = (j + 1) % tid_agg_rx->buf_size) {
|
||||
if (tid_agg_rx->reorder_buf[j] == NULL) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
|
||||
HZ / 10))
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: release an RX reorder "
|
||||
"frame due to timeout on earlier "
|
||||
"frames\n",
|
||||
wiphy_name(hw->wiphy));
|
||||
#endif
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
|
||||
|
||||
/*
|
||||
* Increment the head seq# also for the skipped slots.
|
||||
*/
|
||||
tid_agg_rx->head_seq_num =
|
||||
(tid_agg_rx->head_seq_num + skipped) &
|
||||
SEQ_MASK;
|
||||
skipped = 0;
|
||||
}
|
||||
} else while (tid_agg_rx->reorder_buf[index]) {
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
|
||||
index = seq_sub(tid_agg_rx->head_seq_num,
|
||||
tid_agg_rx->ssn) % tid_agg_rx->buf_size;
|
||||
}
|
||||
@@ -2517,6 +2551,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* In theory, the block ack reordering should happen after duplicate
|
||||
* removal (ieee80211_rx_h_check(), which is an RX handler). As such,
|
||||
* the call to ieee80211_rx_reorder_ampdu() should really be moved to
|
||||
* happen as a new RX handler between ieee80211_rx_h_check and
|
||||
* ieee80211_rx_h_decrypt. This cleanup may eventually happen, but for
|
||||
* the time being, the call can be here since RX reorder buf processing
|
||||
* will implicitly skip duplicates. We could, in theory at least,
|
||||
* process frames that ieee80211_rx_h_passive_scan would drop (e.g.,
|
||||
* frames from other than operational channel), but that should not
|
||||
* happen in normal networks.
|
||||
*/
|
||||
if (!ieee80211_rx_reorder_ampdu(local, skb, status))
|
||||
__ieee80211_rx_handle_packet(hw, skb, status, rate);
|
||||
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "mesh.h"
|
||||
|
||||
#define IEEE80211_PROBE_DELAY (HZ / 33)
|
||||
@@ -202,18 +203,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
||||
void ieee80211_scan_failed(struct ieee80211_local *local)
|
||||
{
|
||||
if (WARN_ON(!local->scan_req))
|
||||
return;
|
||||
|
||||
/* notify cfg80211 about the failed scan */
|
||||
if (local->scan_req != &local->int_scan_req)
|
||||
cfg80211_scan_done(local->scan_req, true);
|
||||
|
||||
local->scan_req = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* inform AP that we will go to sleep so that it will buffer the frames
|
||||
* while we scan
|
||||
@@ -274,55 +263,61 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_restore_scan_ies(struct ieee80211_local *local)
|
||||
{
|
||||
kfree(local->scan_req->ie);
|
||||
local->scan_req->ie = local->orig_ies;
|
||||
local->scan_req->ie_len = local->orig_ies_len;
|
||||
}
|
||||
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
bool was_hw_scan;
|
||||
|
||||
if (WARN_ON(!local->hw_scanning && !local->sw_scanning))
|
||||
mutex_lock(&local->scan_mtx);
|
||||
|
||||
if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) {
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
return;
|
||||
|
||||
if (WARN_ON(!local->scan_req))
|
||||
return;
|
||||
|
||||
if (local->hw_scanning) {
|
||||
kfree(local->scan_req->ie);
|
||||
local->scan_req->ie = local->orig_ies;
|
||||
local->scan_req->ie_len = local->orig_ies_len;
|
||||
}
|
||||
|
||||
if (WARN_ON(!local->scan_req)) {
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (local->hw_scanning)
|
||||
ieee80211_restore_scan_ies(local);
|
||||
|
||||
if (local->scan_req != &local->int_scan_req)
|
||||
cfg80211_scan_done(local->scan_req, aborted);
|
||||
local->scan_req = NULL;
|
||||
|
||||
if (local->hw_scanning) {
|
||||
local->hw_scanning = false;
|
||||
/*
|
||||
* Somebody might have requested channel change during scan
|
||||
* that we won't have acted upon, try now. ieee80211_hw_config
|
||||
* will set the flag based on actual changes.
|
||||
*/
|
||||
ieee80211_hw_config(local, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
was_hw_scan = local->hw_scanning;
|
||||
local->hw_scanning = false;
|
||||
local->sw_scanning = false;
|
||||
|
||||
/* we only have to protect scan_req and hw/sw scan */
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
if (was_hw_scan)
|
||||
goto done;
|
||||
|
||||
netif_tx_lock_bh(local->mdev);
|
||||
netif_addr_lock(local->mdev);
|
||||
local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
|
||||
local->ops->configure_filter(local_to_hw(local),
|
||||
FIF_BCN_PRBRESP_PROMISC,
|
||||
&local->filter_flags,
|
||||
local->mdev->mc_count,
|
||||
local->mdev->mc_list);
|
||||
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
|
||||
&local->filter_flags,
|
||||
local->mdev->mc_count,
|
||||
local->mdev->mc_list);
|
||||
|
||||
netif_addr_unlock(local->mdev);
|
||||
netif_tx_unlock_bh(local->mdev);
|
||||
|
||||
if (local->ops->sw_scan_complete)
|
||||
local->ops->sw_scan_complete(local_to_hw(local));
|
||||
drv_sw_scan_complete(local);
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
@@ -342,18 +337,160 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
ieee80211_if_config(sdata,
|
||||
IEEE80211_IFCC_BEACON_ENABLED);
|
||||
ieee80211_bss_info_change_notify(
|
||||
sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
done:
|
||||
ieee80211_recalc_idle(local);
|
||||
ieee80211_mlme_notify_scan_completed(local);
|
||||
ieee80211_ibss_notify_scan_completed(local);
|
||||
ieee80211_mesh_notify_scan_completed(local);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_scan_completed);
|
||||
|
||||
static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
/*
|
||||
* Hardware/driver doesn't support hw_scan, so use software
|
||||
* scanning instead. First send a nullfunc frame with power save
|
||||
* bit on so that AP will buffer the frames for us while we are not
|
||||
* listening, then send probe requests to each channel and wait for
|
||||
* the responses. After all channels are scanned, tune back to the
|
||||
* original channel and send a nullfunc frame with power save bit
|
||||
* off to trigger the AP to send us all the buffered frames.
|
||||
*
|
||||
* Note that while local->sw_scanning is true everything else but
|
||||
* nullfunc frames and probe requests will be dropped in
|
||||
* ieee80211_tx_h_check_assoc().
|
||||
*/
|
||||
drv_sw_scan_start(local);
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
|
||||
/* disable beaconing */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
ieee80211_bss_info_change_notify(
|
||||
sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
ieee80211_scan_ps_enable(sdata);
|
||||
}
|
||||
} else
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
local->scan_state = SCAN_SET_CHANNEL;
|
||||
local->scan_channel_idx = 0;
|
||||
|
||||
netif_addr_lock_bh(local->mdev);
|
||||
local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
|
||||
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
|
||||
&local->filter_flags,
|
||||
local->mdev->mc_count,
|
||||
local->mdev->mc_list);
|
||||
netif_addr_unlock_bh(local->mdev);
|
||||
|
||||
/* TODO: start scan as soon as all nullfunc frames are ACKed */
|
||||
queue_delayed_work(local->hw.workqueue, &local->scan_work,
|
||||
IEEE80211_CHANNEL_TIME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
int rc;
|
||||
|
||||
if (local->scan_req)
|
||||
return -EBUSY;
|
||||
|
||||
if (local->ops->hw_scan) {
|
||||
u8 *ies;
|
||||
int ielen;
|
||||
|
||||
ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN +
|
||||
local->scan_ies_len + req->ie_len, GFP_KERNEL);
|
||||
if (!ies)
|
||||
return -ENOMEM;
|
||||
|
||||
ielen = ieee80211_build_preq_ies(local, ies,
|
||||
req->ie, req->ie_len);
|
||||
local->orig_ies = req->ie;
|
||||
local->orig_ies_len = req->ie_len;
|
||||
req->ie = ies;
|
||||
req->ie_len = ielen;
|
||||
}
|
||||
|
||||
local->scan_req = req;
|
||||
local->scan_sdata = sdata;
|
||||
|
||||
if (req != &local->int_scan_req &&
|
||||
sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
(ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE ||
|
||||
ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
|
||||
ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) {
|
||||
/* actually wait for the assoc to finish/time out */
|
||||
set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (local->ops->hw_scan)
|
||||
local->hw_scanning = true;
|
||||
else
|
||||
local->sw_scanning = true;
|
||||
/*
|
||||
* Kicking off the scan need not be protected,
|
||||
* only the scan variable stuff, since now
|
||||
* local->scan_req is assigned and other callers
|
||||
* will abort their scan attempts.
|
||||
*
|
||||
* This avoids getting a scan_mtx -> iflist_mtx
|
||||
* dependency, so that the scan completed calls
|
||||
* have more locking freedom.
|
||||
*/
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
|
||||
if (local->ops->hw_scan)
|
||||
rc = drv_hw_scan(local, local->scan_req);
|
||||
else
|
||||
rc = ieee80211_start_sw_scan(local);
|
||||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
|
||||
if (rc) {
|
||||
if (local->ops->hw_scan) {
|
||||
local->hw_scanning = false;
|
||||
ieee80211_restore_scan_ies(local);
|
||||
} else
|
||||
local->sw_scanning = false;
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
local->scan_req = NULL;
|
||||
local->scan_sdata = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ieee80211_scan_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
@@ -363,17 +500,41 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
int skip, i;
|
||||
unsigned long next_delay = 0;
|
||||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
if (!sdata || !local->scan_req) {
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) {
|
||||
struct cfg80211_scan_request *req = local->scan_req;
|
||||
int rc;
|
||||
|
||||
local->scan_req = NULL;
|
||||
|
||||
rc = __ieee80211_start_scan(sdata, req);
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
|
||||
if (rc)
|
||||
ieee80211_scan_completed(&local->hw, true);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
|
||||
/*
|
||||
* Avoid re-scheduling when the sdata is going away.
|
||||
*/
|
||||
if (!netif_running(sdata->dev))
|
||||
if (!netif_running(sdata->dev)) {
|
||||
ieee80211_scan_completed(&local->hw, true);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (local->scan_state) {
|
||||
case SCAN_SET_CHANNEL:
|
||||
/* if no more bands/channels left, complete scan */
|
||||
if (local->scan_channel_idx >= local->scan_req->n_channels) {
|
||||
ieee80211_scan_completed(local_to_hw(local), false);
|
||||
ieee80211_scan_completed(&local->hw, false);
|
||||
return;
|
||||
}
|
||||
skip = 0;
|
||||
@@ -422,166 +583,35 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
next_delay);
|
||||
}
|
||||
|
||||
|
||||
int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct ieee80211_local *local = scan_sdata->local;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (!req)
|
||||
return -EINVAL;
|
||||
|
||||
if (local->scan_req && local->scan_req != req)
|
||||
return -EBUSY;
|
||||
|
||||
local->scan_req = req;
|
||||
|
||||
/* MLME-SCAN.request (page 118) page 144 (11.1.3.1)
|
||||
* BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
|
||||
* BSSID: MACAddress
|
||||
* SSID
|
||||
* ScanType: ACTIVE, PASSIVE
|
||||
* ProbeDelay: delay (in microseconds) to be used prior to transmitting
|
||||
* a Probe frame during active scanning
|
||||
* ChannelList
|
||||
* MinChannelTime (>= ProbeDelay), in TU
|
||||
* MaxChannelTime: (>= MinChannelTime), in TU
|
||||
*/
|
||||
|
||||
/* MLME-SCAN.confirm
|
||||
* BSSDescriptionSet
|
||||
* ResultCode: SUCCESS, INVALID_PARAMETERS
|
||||
*/
|
||||
|
||||
if (local->sw_scanning || local->hw_scanning) {
|
||||
if (local->scan_sdata == scan_sdata)
|
||||
return 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (local->ops->hw_scan) {
|
||||
u8 *ies;
|
||||
int rc, ielen;
|
||||
|
||||
ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN +
|
||||
local->scan_ies_len + req->ie_len, GFP_KERNEL);
|
||||
if (!ies)
|
||||
return -ENOMEM;
|
||||
|
||||
ielen = ieee80211_build_preq_ies(local, ies,
|
||||
req->ie, req->ie_len);
|
||||
local->orig_ies = req->ie;
|
||||
local->orig_ies_len = req->ie_len;
|
||||
req->ie = ies;
|
||||
req->ie_len = ielen;
|
||||
|
||||
local->hw_scanning = true;
|
||||
rc = local->ops->hw_scan(local_to_hw(local), req);
|
||||
if (rc) {
|
||||
local->hw_scanning = false;
|
||||
kfree(ies);
|
||||
req->ie_len = local->orig_ies_len;
|
||||
req->ie = local->orig_ies;
|
||||
return rc;
|
||||
}
|
||||
local->scan_sdata = scan_sdata;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware/driver doesn't support hw_scan, so use software
|
||||
* scanning instead. First send a nullfunc frame with power save
|
||||
* bit on so that AP will buffer the frames for us while we are not
|
||||
* listening, then send probe requests to each channel and wait for
|
||||
* the responses. After all channels are scanned, tune back to the
|
||||
* original channel and send a nullfunc frame with power save bit
|
||||
* off to trigger the AP to send us all the buffered frames.
|
||||
*
|
||||
* Note that while local->sw_scanning is true everything else but
|
||||
* nullfunc frames and probe requests will be dropped in
|
||||
* ieee80211_tx_h_check_assoc().
|
||||
*/
|
||||
local->sw_scanning = true;
|
||||
if (local->ops->sw_scan_start)
|
||||
local->ops->sw_scan_start(local_to_hw(local));
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
|
||||
/* disable beaconing */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
ieee80211_if_config(sdata,
|
||||
IEEE80211_IFCC_BEACON_ENABLED);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
ieee80211_scan_ps_enable(sdata);
|
||||
}
|
||||
} else
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
local->scan_state = SCAN_SET_CHANNEL;
|
||||
local->scan_channel_idx = 0;
|
||||
local->scan_sdata = scan_sdata;
|
||||
local->scan_req = req;
|
||||
|
||||
netif_addr_lock_bh(local->mdev);
|
||||
local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
|
||||
local->ops->configure_filter(local_to_hw(local),
|
||||
FIF_BCN_PRBRESP_PROMISC,
|
||||
&local->filter_flags,
|
||||
local->mdev->mc_count,
|
||||
local->mdev->mc_list);
|
||||
netif_addr_unlock_bh(local->mdev);
|
||||
|
||||
/* TODO: start scan as soon as all nullfunc frames are ACKed */
|
||||
queue_delayed_work(local->hw.workqueue, &local->scan_work,
|
||||
IEEE80211_CHANNEL_TIME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd;
|
||||
int res;
|
||||
|
||||
if (!req)
|
||||
return -EINVAL;
|
||||
mutex_lock(&sdata->local->scan_mtx);
|
||||
res = __ieee80211_start_scan(sdata, req);
|
||||
mutex_unlock(&sdata->local->scan_mtx);
|
||||
|
||||
if (local->scan_req && local->scan_req != req)
|
||||
return -EBUSY;
|
||||
|
||||
local->scan_req = req;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return ieee80211_start_scan(sdata, req);
|
||||
|
||||
/*
|
||||
* STA has a state machine that might need to defer scanning
|
||||
* while it's trying to associate/authenticate, therefore we
|
||||
* queue it up to the state machine in that case.
|
||||
*/
|
||||
|
||||
if (local->sw_scanning || local->hw_scanning) {
|
||||
if (local->scan_sdata == sdata)
|
||||
return 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ifmgd = &sdata->u.mgd;
|
||||
set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
|
||||
queue_work(local->hw.workqueue, &ifmgd->work);
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *ssid, u8 ssid_len)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int ret = -EBUSY;
|
||||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
|
||||
/* busy scanning */
|
||||
if (local->scan_req)
|
||||
goto unlock;
|
||||
|
||||
memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
|
||||
local->int_scan_req.ssids[0].ssid_len = ssid_len;
|
||||
|
||||
ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req);
|
||||
unlock:
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "rate.h"
|
||||
#include "sta_info.h"
|
||||
#include "debugfs_sta.h"
|
||||
@@ -346,8 +347,7 @@ int sta_info_insert(struct sta_info *sta)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
|
||||
STA_NOTIFY_ADD, &sta->sta);
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
@@ -405,8 +405,7 @@ static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
|
||||
|
||||
if (sta->local->ops->set_tim) {
|
||||
sta->local->tim_in_locked_section = true;
|
||||
sta->local->ops->set_tim(local_to_hw(sta->local),
|
||||
&sta->sta, true);
|
||||
drv_set_tim(sta->local, &sta->sta, true);
|
||||
sta->local->tim_in_locked_section = false;
|
||||
}
|
||||
}
|
||||
@@ -431,8 +430,7 @@ static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
|
||||
|
||||
if (sta->local->ops->set_tim) {
|
||||
sta->local->tim_in_locked_section = true;
|
||||
sta->local->ops->set_tim(local_to_hw(sta->local),
|
||||
&sta->sta, false);
|
||||
drv_set_tim(sta->local, &sta->sta, false);
|
||||
sta->local->tim_in_locked_section = false;
|
||||
}
|
||||
}
|
||||
@@ -482,8 +480,8 @@ static void __sta_info_unlink(struct sta_info **sta)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
|
||||
STA_NOTIFY_REMOVE, &(*sta)->sta);
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
|
||||
&(*sta)->sta);
|
||||
}
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
@@ -543,9 +541,8 @@ void sta_info_unlink(struct sta_info **sta)
|
||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
}
|
||||
|
||||
static inline int sta_info_buffer_expired(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct sk_buff *skb)
|
||||
static int sta_info_buffer_expired(struct sta_info *sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
int timeout;
|
||||
@@ -556,8 +553,9 @@ static inline int sta_info_buffer_expired(struct ieee80211_local *local,
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
/* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
|
||||
timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
|
||||
15625) * HZ;
|
||||
timeout = (sta->listen_interval *
|
||||
sta->sdata->vif.bss_conf.beacon_int *
|
||||
32 / 15625) * HZ;
|
||||
if (timeout < STA_TX_BUFFER_EXPIRE)
|
||||
timeout = STA_TX_BUFFER_EXPIRE;
|
||||
return time_after(jiffies, info->control.jiffies + timeout);
|
||||
@@ -577,7 +575,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
|
||||
for (;;) {
|
||||
spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
|
||||
skb = skb_peek(&sta->ps_tx_buf);
|
||||
if (sta_info_buffer_expired(local, sta, skb))
|
||||
if (sta_info_buffer_expired(sta, skb))
|
||||
skb = __skb_dequeue(&sta->ps_tx_buf);
|
||||
else
|
||||
skb = NULL;
|
||||
|
@@ -88,6 +88,7 @@ struct tid_ampdu_tx {
|
||||
* struct tid_ampdu_rx - TID aggregation information (Rx).
|
||||
*
|
||||
* @reorder_buf: buffer to reorder incoming aggregated MPDUs
|
||||
* @reorder_time: jiffies when skb was added
|
||||
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
|
||||
* @head_seq_num: head sequence number in reordering buffer.
|
||||
* @stored_mpdu_num: number of MPDUs in reordering buffer
|
||||
@@ -99,6 +100,7 @@ struct tid_ampdu_tx {
|
||||
*/
|
||||
struct tid_ampdu_rx {
|
||||
struct sk_buff **reorder_buf;
|
||||
unsigned long *reorder_time;
|
||||
struct timer_list session_timer;
|
||||
u16 head_seq_num;
|
||||
u16 stored_mpdu_num;
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "driver-ops.h"
|
||||
#include "key.h"
|
||||
#include "tkip.h"
|
||||
#include "wep.h"
|
||||
@@ -307,9 +308,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
|
||||
if (is_multicast_ether_addr(ra))
|
||||
sta_addr = bcast;
|
||||
|
||||
key->local->ops->update_tkip_key(
|
||||
local_to_hw(key->local), &key->conf,
|
||||
sta_addr, iv32, key->u.tkip.rx[queue].p1k);
|
||||
drv_update_tkip_key(key->local, &key->conf, sta_addr,
|
||||
iv32, key->u.tkip.rx[queue].p1k);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "led.h"
|
||||
#include "mesh.h"
|
||||
#include "wep.h"
|
||||
@@ -557,6 +558,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
||||
if (unlikely(!info->control.rates[0].count))
|
||||
info->control.rates[0].count = 1;
|
||||
|
||||
if (WARN_ON_ONCE((info->control.rates[0].count > 1) &&
|
||||
(info->flags & IEEE80211_TX_CTL_NO_ACK)))
|
||||
info->control.rates[0].count = 1;
|
||||
|
||||
if (is_multicast_ether_addr(hdr->addr1)) {
|
||||
/*
|
||||
* XXX: verify the rate is in the basic rateset
|
||||
@@ -1162,7 +1167,7 @@ static int __ieee80211_tx(struct ieee80211_local *local,
|
||||
|
||||
next = skb->next;
|
||||
len = skb->len;
|
||||
ret = local->ops->tx(local_to_hw(local), skb);
|
||||
ret = drv_tx(local, skb);
|
||||
if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
|
||||
dev_kfree_skb(skb);
|
||||
ret = NETDEV_TX_OK;
|
||||
@@ -2132,7 +2137,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
/* BSSID is left zeroed, wildcard value */
|
||||
mgmt->u.beacon.beacon_int =
|
||||
cpu_to_le16(local->hw.conf.beacon_int);
|
||||
cpu_to_le16(sdata->vif.bss_conf.beacon_int);
|
||||
mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
|
||||
|
||||
pos = skb_put(skb, 2);
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <net/rtnetlink.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "rate.h"
|
||||
#include "mesh.h"
|
||||
#include "wme.h"
|
||||
@@ -726,7 +727,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
|
||||
qparam.txop = 0;
|
||||
|
||||
for (i = 0; i < local_to_hw(local)->queues; i++)
|
||||
local->ops->conf_tx(local_to_hw(local), i, &qparam);
|
||||
drv_conf_tx(local, i, &qparam);
|
||||
}
|
||||
|
||||
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
@@ -1000,7 +1001,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
|
||||
/* restart hardware */
|
||||
if (local->open_count) {
|
||||
res = local->ops->start(hw);
|
||||
res = drv_start(local);
|
||||
|
||||
ieee80211_led_radio(local, hw->conf.radio_enabled);
|
||||
}
|
||||
@@ -1013,7 +1014,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
conf.vif = &sdata->vif;
|
||||
conf.type = sdata->vif.type;
|
||||
conf.mac_addr = sdata->dev->dev_addr;
|
||||
res = local->ops->add_interface(hw, &conf);
|
||||
res = drv_add_interface(local, &conf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1026,8 +1027,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
local->ops->sta_notify(hw, &sdata->vif,
|
||||
STA_NOTIFY_ADD, &sta->sta);
|
||||
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD,
|
||||
&sta->sta);
|
||||
}
|
||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
}
|
||||
@@ -1045,8 +1046,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
rcu_read_unlock();
|
||||
|
||||
/* setup RTS threshold */
|
||||
if (local->ops->set_rts_threshold)
|
||||
local->ops->set_rts_threshold(hw, hw->wiphy->rts_threshold);
|
||||
drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
|
||||
|
||||
/* reconfigure hardware */
|
||||
ieee80211_hw_config(local, ~0);
|
||||
@@ -1063,24 +1063,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* disable beacon change bits */
|
||||
changed &= ~IEEE80211_IFCC_BEACON;
|
||||
changed &= ~(BSS_CHANGED_BEACON |
|
||||
BSS_CHANGED_BEACON_ENABLED);
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
/*
|
||||
* Driver's config_interface can fail if rfkill is
|
||||
* enabled. Accommodate this return code.
|
||||
* FIXME: When mac80211 has knowledge of rfkill
|
||||
* state the code below can change back to:
|
||||
* WARN(ieee80211_if_config(sdata, changed));
|
||||
* ieee80211_bss_info_change_notify(sdata, ~0);
|
||||
*/
|
||||
if (ieee80211_if_config(sdata, changed))
|
||||
printk(KERN_DEBUG "%s: failed to configure interface during resume\n",
|
||||
sdata->dev->name);
|
||||
else
|
||||
ieee80211_bss_info_change_notify(sdata, ~0);
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
break;
|
||||
|
@@ -185,7 +185,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev,
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
|
||||
|
||||
freq->m = local->hw.conf.channel->center_freq;
|
||||
freq->m = local->oper_channel->center_freq;
|
||||
freq->e = 6;
|
||||
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user