mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
commit
fa5978447c
19 changed files with 772 additions and 34 deletions
|
|
@ -862,8 +862,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_beacon_data *params)
|
||||
int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_beacon_data *params)
|
||||
{
|
||||
struct beacon_data *new, *old;
|
||||
int new_head_len, new_tail_len;
|
||||
|
|
@ -1026,6 +1026,12 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
/* don't allow changing the beacon while CSA is in place - offset
|
||||
* of channel switch counter may change
|
||||
*/
|
||||
if (sdata->vif.csa_active)
|
||||
return -EBUSY;
|
||||
|
||||
old = rtnl_dereference(sdata->u.ap.beacon);
|
||||
if (!old)
|
||||
return -ENOENT;
|
||||
|
|
@ -1050,6 +1056,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
|||
return -ENOENT;
|
||||
old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
|
||||
|
||||
/* abort any running channel switch */
|
||||
sdata->vif.csa_active = false;
|
||||
cancel_work_sync(&sdata->csa_finalize_work);
|
||||
|
||||
/* turn off carrier for this interface and dependent VLANs */
|
||||
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
||||
netif_carrier_off(vlan->dev);
|
||||
|
|
@ -2777,6 +2787,178 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct cfg80211_beacon_data *
|
||||
cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
|
||||
{
|
||||
struct cfg80211_beacon_data *new_beacon;
|
||||
u8 *pos;
|
||||
int len;
|
||||
|
||||
len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
|
||||
beacon->proberesp_ies_len + beacon->assocresp_ies_len +
|
||||
beacon->probe_resp_len;
|
||||
|
||||
new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
|
||||
if (!new_beacon)
|
||||
return NULL;
|
||||
|
||||
pos = (u8 *)(new_beacon + 1);
|
||||
if (beacon->head_len) {
|
||||
new_beacon->head_len = beacon->head_len;
|
||||
new_beacon->head = pos;
|
||||
memcpy(pos, beacon->head, beacon->head_len);
|
||||
pos += beacon->head_len;
|
||||
}
|
||||
if (beacon->tail_len) {
|
||||
new_beacon->tail_len = beacon->tail_len;
|
||||
new_beacon->tail = pos;
|
||||
memcpy(pos, beacon->tail, beacon->tail_len);
|
||||
pos += beacon->tail_len;
|
||||
}
|
||||
if (beacon->beacon_ies_len) {
|
||||
new_beacon->beacon_ies_len = beacon->beacon_ies_len;
|
||||
new_beacon->beacon_ies = pos;
|
||||
memcpy(pos, beacon->beacon_ies, beacon->beacon_ies_len);
|
||||
pos += beacon->beacon_ies_len;
|
||||
}
|
||||
if (beacon->proberesp_ies_len) {
|
||||
new_beacon->proberesp_ies_len = beacon->proberesp_ies_len;
|
||||
new_beacon->proberesp_ies = pos;
|
||||
memcpy(pos, beacon->proberesp_ies, beacon->proberesp_ies_len);
|
||||
pos += beacon->proberesp_ies_len;
|
||||
}
|
||||
if (beacon->assocresp_ies_len) {
|
||||
new_beacon->assocresp_ies_len = beacon->assocresp_ies_len;
|
||||
new_beacon->assocresp_ies = pos;
|
||||
memcpy(pos, beacon->assocresp_ies, beacon->assocresp_ies_len);
|
||||
pos += beacon->assocresp_ies_len;
|
||||
}
|
||||
if (beacon->probe_resp_len) {
|
||||
new_beacon->probe_resp_len = beacon->probe_resp_len;
|
||||
beacon->probe_resp = pos;
|
||||
memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
|
||||
pos += beacon->probe_resp_len;
|
||||
}
|
||||
|
||||
return new_beacon;
|
||||
}
|
||||
|
||||
void ieee80211_csa_finalize_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
container_of(work, struct ieee80211_sub_if_data,
|
||||
csa_finalize_work);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int err, changed;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return;
|
||||
|
||||
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
|
||||
return;
|
||||
|
||||
sdata->radar_required = sdata->csa_radar_required;
|
||||
err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
|
||||
&changed);
|
||||
if (WARN_ON(err < 0))
|
||||
return;
|
||||
|
||||
err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
changed |= err;
|
||||
kfree(sdata->u.ap.next_beacon);
|
||||
sdata->u.ap.next_beacon = NULL;
|
||||
sdata->vif.csa_active = false;
|
||||
|
||||
ieee80211_wake_queues_by_reason(&sdata->local->hw,
|
||||
IEEE80211_MAX_QUEUE_MAP,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
|
||||
cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
|
||||
}
|
||||
|
||||
static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_csa_settings *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_chanctx *chanctx;
|
||||
int err, num_chanctx;
|
||||
|
||||
if (!list_empty(&local->roc_list) || local->scanning)
|
||||
return -EBUSY;
|
||||
|
||||
if (sdata->wdev.cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (cfg80211_chandef_identical(¶ms->chandef,
|
||||
&sdata->vif.bss_conf.chandef))
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!chanctx_conf) {
|
||||
rcu_read_unlock();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* don't handle for multi-VIF cases */
|
||||
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
|
||||
if (chanctx->refcount > 1) {
|
||||
rcu_read_unlock();
|
||||
return -EBUSY;
|
||||
}
|
||||
num_chanctx = 0;
|
||||
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
|
||||
num_chanctx++;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (num_chanctx > 1)
|
||||
return -EBUSY;
|
||||
|
||||
/* don't allow another channel switch if one is already active. */
|
||||
if (sdata->vif.csa_active)
|
||||
return -EBUSY;
|
||||
|
||||
/* only handle AP for now. */
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
sdata->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after);
|
||||
if (!sdata->u.ap.next_beacon)
|
||||
return -ENOMEM;
|
||||
|
||||
sdata->csa_counter_offset_beacon = params->counter_offset_beacon;
|
||||
sdata->csa_counter_offset_presp = params->counter_offset_presp;
|
||||
sdata->csa_radar_required = params->radar_required;
|
||||
|
||||
if (params->block_tx)
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
IEEE80211_MAX_QUEUE_MAP,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
|
||||
err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
local->csa_chandef = params->chandef;
|
||||
sdata->vif.csa_active = true;
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, err);
|
||||
drv_channel_switch_beacon(sdata, ¶ms->chandef);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan, bool offchan,
|
||||
unsigned int wait, const u8 *buf, size_t len,
|
||||
|
|
@ -3494,4 +3676,5 @@ struct cfg80211_ops mac80211_config_ops = {
|
|||
.get_et_strings = ieee80211_get_et_strings,
|
||||
.get_channel = ieee80211_cfg_get_channel,
|
||||
.start_radar_detection = ieee80211_start_radar_detection,
|
||||
.channel_switch = ieee80211_channel_switch,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -410,6 +410,64 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
u32 *changed)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
struct ieee80211_chanctx *ctx;
|
||||
int ret;
|
||||
u32 chanctx_changed = 0;
|
||||
|
||||
/* should never be called if not performing a channel switch. */
|
||||
if (WARN_ON(!sdata->vif.csa_active))
|
||||
return -EINVAL;
|
||||
|
||||
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
|
||||
IEEE80211_CHAN_DISABLED))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
if (!conf) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx = container_of(conf, struct ieee80211_chanctx, conf);
|
||||
if (ctx->refcount != 1) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sdata->vif.bss_conf.chandef.width != chandef->width) {
|
||||
chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
|
||||
*changed |= BSS_CHANGED_BANDWIDTH;
|
||||
}
|
||||
|
||||
sdata->vif.bss_conf.chandef = *chandef;
|
||||
ctx->conf.def = *chandef;
|
||||
|
||||
chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
|
||||
drv_change_chanctx(local, ctx, chanctx_changed);
|
||||
|
||||
if (!local->use_chanctx) {
|
||||
local->_oper_chandef = *chandef;
|
||||
ieee80211_hw_config(local, 0);
|
||||
}
|
||||
|
||||
ieee80211_recalc_chanctx_chantype(local, ctx);
|
||||
ieee80211_recalc_smps_chanctx(local, ctx);
|
||||
ieee80211_recalc_radar_chanctx(local, ctx);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
u32 *changed)
|
||||
|
|
|
|||
|
|
@ -455,6 +455,15 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
|||
DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
|
||||
DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count);
|
||||
|
||||
if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
|
||||
debugfs_create_x32("driver_buffered_tids", 0400,
|
||||
sta->debugfs.dir,
|
||||
(u32 *)&sta->driver_buffered_tids);
|
||||
else
|
||||
debugfs_create_x64("driver_buffered_tids", 0400,
|
||||
sta->debugfs.dir,
|
||||
(u64 *)&sta->driver_buffered_tids);
|
||||
|
||||
drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1072,4 +1072,17 @@ static inline void drv_ipv6_addr_change(struct ieee80211_local *local,
|
|||
}
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (local->ops->channel_switch_beacon) {
|
||||
trace_drv_channel_switch_beacon(local, sdata, chandef);
|
||||
local->ops->channel_switch_beacon(&local->hw, &sdata->vif,
|
||||
chandef);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
|
||||
#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
|
||||
#define IEEE80211_IBSS_RSN_INACTIVITY_LIMIT (10 * HZ)
|
||||
|
||||
#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
|
||||
|
||||
|
|
@ -740,6 +741,33 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
return active;
|
||||
}
|
||||
|
||||
static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta, *tmp;
|
||||
unsigned long exp_time = IEEE80211_IBSS_INACTIVITY_LIMIT;
|
||||
unsigned long exp_rsn_time = IEEE80211_IBSS_RSN_INACTIVITY_LIMIT;
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
|
||||
if (sdata != sta->sdata)
|
||||
continue;
|
||||
|
||||
if (time_after(jiffies, sta->last_rx + exp_time) ||
|
||||
(time_after(jiffies, sta->last_rx + exp_rsn_time) &&
|
||||
sta->sta_state != IEEE80211_STA_AUTHORIZED)) {
|
||||
sta_dbg(sta->sdata, "expiring inactive %sSTA %pM\n",
|
||||
sta->sta_state != IEEE80211_STA_AUTHORIZED ?
|
||||
"not authorized " : "", sta->sta.addr);
|
||||
|
||||
WARN_ON(__sta_info_destroy(sta));
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called with state == IEEE80211_IBSS_MLME_JOINED
|
||||
*/
|
||||
|
|
@ -754,7 +782,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
mod_timer(&ifibss->timer,
|
||||
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
|
||||
|
||||
ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);
|
||||
ieee80211_ibss_sta_expire(sdata);
|
||||
|
||||
if (time_before(jiffies, ifibss->last_scan_completed +
|
||||
IEEE80211_IBSS_MERGE_INTERVAL))
|
||||
|
|
|
|||
|
|
@ -259,6 +259,8 @@ struct ieee80211_if_ap {
|
|||
struct beacon_data __rcu *beacon;
|
||||
struct probe_resp __rcu *probe_resp;
|
||||
|
||||
/* to be used after channel switch. */
|
||||
struct cfg80211_beacon_data *next_beacon;
|
||||
struct list_head vlans;
|
||||
|
||||
struct ps_data ps;
|
||||
|
|
@ -716,6 +718,11 @@ struct ieee80211_sub_if_data {
|
|||
|
||||
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
|
||||
|
||||
struct work_struct csa_finalize_work;
|
||||
int csa_counter_offset_beacon;
|
||||
int csa_counter_offset_presp;
|
||||
bool csa_radar_required;
|
||||
|
||||
/* used to reconfigure hardware SM PS */
|
||||
struct work_struct recalc_smps;
|
||||
|
||||
|
|
@ -1094,7 +1101,6 @@ struct ieee80211_local {
|
|||
u32 dot11TransmittedFrameCount;
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
int tx_led_counter, rx_led_counter;
|
||||
struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
|
||||
struct tpt_led_trigger *tpt_led_trigger;
|
||||
char tx_led_name[32], rx_led_name[32],
|
||||
|
|
@ -1373,6 +1379,9 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
|
|||
void ieee80211_sw_roc_work(struct work_struct *work);
|
||||
void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
|
||||
|
||||
/* channel switch handling */
|
||||
void ieee80211_csa_finalize_work(struct work_struct *work);
|
||||
|
||||
/* interface handling */
|
||||
int ieee80211_iface_init(void);
|
||||
void ieee80211_iface_exit(void);
|
||||
|
|
@ -1394,6 +1403,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
|
|||
|
||||
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_beacon_data *params);
|
||||
|
||||
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
|
|
@ -1655,6 +1666,11 @@ int __must_check
|
|||
ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
u32 *changed);
|
||||
/* NOTE: only use ieee80211_vif_change_channel() for channel switch */
|
||||
int __must_check
|
||||
ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
u32 *changed);
|
||||
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
|||
|
|
@ -274,6 +274,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
|
|||
if (iftype == NL80211_IFTYPE_ADHOC &&
|
||||
nsdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
return -EBUSY;
|
||||
/*
|
||||
* will not add another interface while any channel
|
||||
* switch is active.
|
||||
*/
|
||||
if (nsdata->vif.csa_active)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* The remaining checks are only performed for interfaces
|
||||
|
|
@ -804,6 +810,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
cancel_work_sync(&local->dynamic_ps_enable_work);
|
||||
|
||||
cancel_work_sync(&sdata->recalc_smps);
|
||||
sdata->vif.csa_active = false;
|
||||
cancel_work_sync(&sdata->csa_finalize_work);
|
||||
|
||||
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
|
||||
|
||||
|
|
@ -1267,6 +1275,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
|||
skb_queue_head_init(&sdata->skb_queue);
|
||||
INIT_WORK(&sdata->work, ieee80211_iface_work);
|
||||
INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
|
||||
INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
|
|
|
|||
|
|
@ -12,27 +12,22 @@
|
|||
#include <linux/export.h>
|
||||
#include "led.h"
|
||||
|
||||
#define MAC80211_BLINK_DELAY 50 /* ms */
|
||||
|
||||
void ieee80211_led_rx(struct ieee80211_local *local)
|
||||
{
|
||||
unsigned long led_delay = MAC80211_BLINK_DELAY;
|
||||
if (unlikely(!local->rx_led))
|
||||
return;
|
||||
if (local->rx_led_counter++ % 2 == 0)
|
||||
led_trigger_event(local->rx_led, LED_OFF);
|
||||
else
|
||||
led_trigger_event(local->rx_led, LED_FULL);
|
||||
led_trigger_blink_oneshot(local->rx_led, &led_delay, &led_delay, 0);
|
||||
}
|
||||
|
||||
/* q is 1 if a packet was enqueued, 0 if it has been transmitted */
|
||||
void ieee80211_led_tx(struct ieee80211_local *local, int q)
|
||||
void ieee80211_led_tx(struct ieee80211_local *local)
|
||||
{
|
||||
unsigned long led_delay = MAC80211_BLINK_DELAY;
|
||||
if (unlikely(!local->tx_led))
|
||||
return;
|
||||
/* not sure how this is supposed to work ... */
|
||||
local->tx_led_counter += 2*q-1;
|
||||
if (local->tx_led_counter % 2 == 0)
|
||||
led_trigger_event(local->tx_led, LED_OFF);
|
||||
else
|
||||
led_trigger_event(local->tx_led, LED_FULL);
|
||||
led_trigger_blink_oneshot(local->tx_led, &led_delay, &led_delay, 0);
|
||||
}
|
||||
|
||||
void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
void ieee80211_led_rx(struct ieee80211_local *local);
|
||||
void ieee80211_led_tx(struct ieee80211_local *local, int q);
|
||||
void ieee80211_led_tx(struct ieee80211_local *local);
|
||||
void ieee80211_led_assoc(struct ieee80211_local *local,
|
||||
bool associated);
|
||||
void ieee80211_led_radio(struct ieee80211_local *local,
|
||||
|
|
@ -27,7 +27,7 @@ void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
|
|||
static inline void ieee80211_led_rx(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_tx(struct ieee80211_local *local, int q)
|
||||
static inline void ieee80211_led_tx(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_assoc(struct ieee80211_local *local,
|
||||
|
|
|
|||
|
|
@ -235,7 +235,8 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
|
|||
|
||||
/* IEEE80211_RADIOTAP_RATE rate */
|
||||
if (info->status.rates[0].idx >= 0 &&
|
||||
!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
|
||||
!(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS |
|
||||
IEEE80211_TX_RC_VHT_MCS)))
|
||||
len += 2;
|
||||
|
||||
/* IEEE80211_RADIOTAP_TX_FLAGS */
|
||||
|
|
@ -244,16 +245,21 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
|
|||
/* IEEE80211_RADIOTAP_DATA_RETRIES */
|
||||
len += 1;
|
||||
|
||||
/* IEEE80211_TX_RC_MCS */
|
||||
if (info->status.rates[0].idx >= 0 &&
|
||||
info->status.rates[0].flags & IEEE80211_TX_RC_MCS)
|
||||
len += 3;
|
||||
/* IEEE80211_RADIOTAP_MCS
|
||||
* IEEE80211_RADIOTAP_VHT */
|
||||
if (info->status.rates[0].idx >= 0) {
|
||||
if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS)
|
||||
len += 3;
|
||||
else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS)
|
||||
len = ALIGN(len, 2) + 12;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
|
||||
ieee80211_add_tx_radiotap_header(struct ieee80211_local *local,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct sk_buff *skb, int retry_count,
|
||||
int rtap_len, int shift)
|
||||
{
|
||||
|
|
@ -280,7 +286,8 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
|
|||
|
||||
/* IEEE80211_RADIOTAP_RATE */
|
||||
if (info->status.rates[0].idx >= 0 &&
|
||||
!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) {
|
||||
!(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS |
|
||||
IEEE80211_TX_RC_VHT_MCS))) {
|
||||
u16 rate;
|
||||
|
||||
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
|
||||
|
|
@ -310,9 +317,12 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
|
|||
*pos = retry_count;
|
||||
pos++;
|
||||
|
||||
/* IEEE80211_TX_RC_MCS */
|
||||
if (info->status.rates[0].idx >= 0 &&
|
||||
info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
|
||||
if (info->status.rates[0].idx < 0)
|
||||
return;
|
||||
|
||||
/* IEEE80211_RADIOTAP_MCS
|
||||
* IEEE80211_RADIOTAP_VHT */
|
||||
if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
|
||||
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS);
|
||||
pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
|
||||
IEEE80211_RADIOTAP_MCS_HAVE_GI |
|
||||
|
|
@ -325,8 +335,48 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
|
|||
pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF;
|
||||
pos[2] = info->status.rates[0].idx;
|
||||
pos += 3;
|
||||
}
|
||||
} else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
|
||||
u16 known = local->hw.radiotap_vht_details &
|
||||
(IEEE80211_RADIOTAP_VHT_KNOWN_GI |
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH);
|
||||
|
||||
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT);
|
||||
|
||||
/* required alignment from rthdr */
|
||||
pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2);
|
||||
|
||||
/* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */
|
||||
put_unaligned_le16(known, pos);
|
||||
pos += 2;
|
||||
|
||||
/* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */
|
||||
if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
|
||||
*pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
|
||||
pos++;
|
||||
|
||||
/* u8 bandwidth */
|
||||
if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
|
||||
*pos = 1;
|
||||
else if (info->status.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
|
||||
*pos = 4;
|
||||
else if (info->status.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
|
||||
*pos = 11;
|
||||
else /* IEEE80211_TX_RC_{20_MHZ_WIDTH,FIXME:DUP_DATA} */
|
||||
*pos = 0;
|
||||
pos++;
|
||||
|
||||
/* u8 mcs_nss[4] */
|
||||
*pos = (ieee80211_rate_get_vht_mcs(&info->status.rates[0]) << 4) |
|
||||
ieee80211_rate_get_vht_nss(&info->status.rates[0]);
|
||||
pos += 4;
|
||||
|
||||
/* u8 coding */
|
||||
pos++;
|
||||
/* u8 group_id */
|
||||
pos++;
|
||||
/* u16 partial_aid */
|
||||
pos += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_report_used_skb(struct ieee80211_local *local,
|
||||
|
|
@ -564,7 +614,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
|
||||
rcu_read_unlock();
|
||||
|
||||
ieee80211_led_tx(local, 0);
|
||||
ieee80211_led_tx(local);
|
||||
|
||||
/* SNMP counters
|
||||
* Fragments are passed to low-level drivers as separate skbs, so these
|
||||
|
|
@ -631,8 +681,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len,
|
||||
shift);
|
||||
ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
|
||||
rtap_len, shift);
|
||||
|
||||
/* XXX: is this sufficient for BPF? */
|
||||
skb_set_mac_header(skb, 0);
|
||||
|
|
|
|||
|
|
@ -1906,6 +1906,32 @@ TRACE_EVENT(api_radar_detected,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_channel_switch_beacon,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_chan_def *chandef),
|
||||
|
||||
TP_ARGS(local, sdata, chandef),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
CHANDEF_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
CHANDEF_ASSIGN(chandef);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT " channel switch to " CHANDEF_PR_FMT,
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESSAGE_TRACING
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM mac80211_msg
|
||||
|
|
|
|||
|
|
@ -1300,7 +1300,6 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
|
|||
txpending);
|
||||
|
||||
ieee80211_tpt_led_trig_tx(local, fc, led_len);
|
||||
ieee80211_led_tx(local, 1);
|
||||
|
||||
WARN_ON_ONCE(!skb_queue_empty(skbs));
|
||||
|
||||
|
|
@ -2339,6 +2338,81 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_csa_finish(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
|
||||
ieee80211_queue_work(&sdata->local->hw,
|
||||
&sdata->csa_finalize_work);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_csa_finish);
|
||||
|
||||
static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
|
||||
struct beacon_data *beacon)
|
||||
{
|
||||
struct probe_resp *resp;
|
||||
int counter_offset_beacon = sdata->csa_counter_offset_beacon;
|
||||
int counter_offset_presp = sdata->csa_counter_offset_presp;
|
||||
|
||||
/* warn if the driver did not check for/react to csa completeness */
|
||||
if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0))
|
||||
return;
|
||||
|
||||
((u8 *)beacon->tail)[counter_offset_beacon]--;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP &&
|
||||
counter_offset_presp) {
|
||||
rcu_read_lock();
|
||||
resp = rcu_dereference(sdata->u.ap.probe_resp);
|
||||
|
||||
/* if nl80211 accepted the offset, this should not happen. */
|
||||
if (WARN_ON(!resp)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
resp->data[counter_offset_presp]--;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct beacon_data *beacon = NULL;
|
||||
u8 *beacon_data;
|
||||
size_t beacon_data_len;
|
||||
int counter_beacon = sdata->csa_counter_offset_beacon;
|
||||
int ret = false;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return false;
|
||||
|
||||
rcu_read_lock();
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
struct ieee80211_if_ap *ap = &sdata->u.ap;
|
||||
|
||||
beacon = rcu_dereference(ap->beacon);
|
||||
if (WARN_ON(!beacon || !beacon->tail))
|
||||
goto out;
|
||||
beacon_data = beacon->tail;
|
||||
beacon_data_len = beacon->tail_len;
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WARN_ON(counter_beacon > beacon_data_len))
|
||||
goto out;
|
||||
|
||||
if (beacon_data[counter_beacon] == 0)
|
||||
ret = true;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_csa_is_complete);
|
||||
|
||||
struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u16 *tim_offset, u16 *tim_length)
|
||||
|
|
@ -2369,6 +2443,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|||
struct beacon_data *beacon = rcu_dereference(ap->beacon);
|
||||
|
||||
if (beacon) {
|
||||
if (sdata->vif.csa_active)
|
||||
ieee80211_update_csa(sdata, beacon);
|
||||
|
||||
/*
|
||||
* headroom, head length,
|
||||
* tail length and maximum TIM length
|
||||
|
|
|
|||
Loading…
Reference in a new issue