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

This commit is contained in:
David S. Miller
2009-05-08 12:46:17 -07:00
125 changed files with 17193 additions and 1896 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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, &params)) {
if (drv_conf_tx(local, queue, &params) && 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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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