Another set of fixes:
* remove a warning on a check that can trigger without any errors having happened (Andrei) * correctly handle deauth request while in the process of associating (Andrei) * fix TDLS HT operation (Arik) * allow changing AID/listen interval during client setup (Ayala) * be more forgiving with WMM parameters to get HT/VHT in case of broken APs with bad WMM settings (Emmanuel, myself) * a number of other fixes (some in documentation) -----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJWOKsAAAoJEDBSmw7B7bqrNKMQAKFH81CscgJGOQb/zgGdmuF3 kNrWrnH+3XqoqM2rHpIekQLxVkeUhM+hHCyaPCK7rVnCuu53pJ0u7P0rq922XAW4 olFBGVdE1yG/69ndR9MYDjLWP+ikMmAiMLbM5qzPuDJ5XyBVACC1D82+qSRvByCK Z8PYJ+OsLk05eKa4ER7i8BVExRGM4vrce4Uh3K07yNKbfU81ztsltwflleRFGn3f OCydpuSId+C4TuSmkgBJF1718B9GazvAbZDw5t4jorIrbiZzQMZAtoi+YxwXVhev lvPCO8p1+lhWYUOK5LnO8mbdUFfe+kc3rrZjKWuXuDLp6mvPyP9FOaIFjFfnlJxT 8QadG0QDzTlLHUj29gvrnww8aob9c7iHueXP9OlcBMp9uTyklgBJ+fMyvPfXpWXB Diy9n0VJfWzg8d74wWLLQy/N1qY6gwhXXwgW8TM/49O5BpbyvVsI6jFAR+8ZT9b9 GLGEkN68RBuY03mejkf4PmhqgMVErA2JtabRI0Efm2Do85t9ZxgObF6INsrZ+o2M ffl7jhyHsFB+d38Ilwlb4cyWhxpIGrhTtt2h5zIsgNx3wmrXrarwMM3P4NGOOEbP Euqkk/LoMZdjjB/78JSi6hdQSYoQFaW85tHBzXhMXk0nYXHLWdVEJsLuAtATl8gM vzNkny8pcaLnRg/kXqgl =/d5+ -----END PGP SIGNATURE----- Merge tag 'mac80211-for-davem-2015-11-03' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211 Johannes Berg says: ==================== Another set of fixes: * remove a warning on a check that can trigger without any errors having happened (Andrei) * correctly handle deauth request while in the process of associating (Andrei) * fix TDLS HT operation (Arik) * allow changing AID/listen interval during client setup (Ayala) * be more forgiving with WMM parameters to get HT/VHT in case of broken APs with bad WMM settings (Emmanuel, myself) * a number of other fixes (some in documentation) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
b3047a77cb
|
@ -2399,6 +2399,10 @@ struct cfg80211_qos_map {
|
|||
* @set_power_mgmt: Configure WLAN power management. A timeout value of -1
|
||||
* allows the driver to adjust the dynamic ps timeout value.
|
||||
* @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
|
||||
* After configuration, the driver should (soon) send an event indicating
|
||||
* the current level is above/below the configured threshold; this may
|
||||
* need some care when the configuration is changed (without first being
|
||||
* disabled.)
|
||||
* @set_cqm_txe_config: Configure connection quality monitor TX error
|
||||
* thresholds.
|
||||
* @sched_scan_start: Tell the driver to start a scheduled scan.
|
||||
|
|
|
@ -482,7 +482,9 @@ struct ieee80211_event {
|
|||
* Note that with TDLS this can be the case (channel is HT, protection must
|
||||
* be used from this field) even when the BSS association isn't using HT.
|
||||
* @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
|
||||
* implies disabled
|
||||
* implies disabled. As with the cfg80211 callback, a change here should
|
||||
* cause an event to be sent indicating where the current value is in
|
||||
* relation to the newly configured threshold.
|
||||
* @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
|
||||
* @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
|
||||
* may filter ARP queries targeted for other addresses than listed here.
|
||||
|
@ -3170,18 +3172,24 @@ enum ieee80211_reconfig_type {
|
|||
* The callback is optional and can sleep.
|
||||
*
|
||||
* @add_chanctx: Notifies device driver about new channel context creation.
|
||||
* This callback may sleep.
|
||||
* @remove_chanctx: Notifies device driver about channel context destruction.
|
||||
* This callback may sleep.
|
||||
* @change_chanctx: Notifies device driver about channel context changes that
|
||||
* may happen when combining different virtual interfaces on the same
|
||||
* channel context with different settings
|
||||
* This callback may sleep.
|
||||
* @assign_vif_chanctx: Notifies device driver about channel context being bound
|
||||
* to vif. Possible use is for hw queue remapping.
|
||||
* This callback may sleep.
|
||||
* @unassign_vif_chanctx: Notifies device driver about channel context being
|
||||
* unbound from vif.
|
||||
* This callback may sleep.
|
||||
* @switch_vif_chanctx: switch a number of vifs from one chanctx to
|
||||
* another, as specified in the list of
|
||||
* @ieee80211_vif_chanctx_switch passed to the driver, according
|
||||
* to the mode defined in &ieee80211_chanctx_switch_mode.
|
||||
* This callback may sleep.
|
||||
*
|
||||
* @start_ap: Start operation on the AP interface, this is called after all the
|
||||
* information in bss_conf is set and beacon can be retrieved. A channel
|
||||
|
|
|
@ -2010,12 +2010,12 @@ ieee80211_sched_scan_start(struct wiphy *wiphy,
|
|||
static int
|
||||
ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
|
||||
if (!sdata->local->ops->sched_scan_stop)
|
||||
if (!local->ops->sched_scan_stop)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ieee80211_request_sched_scan_stop(sdata);
|
||||
return ieee80211_request_sched_scan_stop(local);
|
||||
}
|
||||
|
||||
static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
/*
|
||||
* Copyright 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
|
@ -8,6 +10,48 @@
|
|||
#include "trace.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
int drv_start(struct ieee80211_local *local)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (WARN_ON(local->started))
|
||||
return -EALREADY;
|
||||
|
||||
trace_drv_start(local);
|
||||
local->started = true;
|
||||
/* allow rx frames */
|
||||
smp_mb();
|
||||
ret = local->ops->start(&local->hw);
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
if (ret)
|
||||
local->started = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void drv_stop(struct ieee80211_local *local)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (WARN_ON(!local->started))
|
||||
return;
|
||||
|
||||
trace_drv_stop(local);
|
||||
local->ops->stop(&local->hw);
|
||||
trace_drv_return_void(local);
|
||||
|
||||
/* sync away all work on the tasklet before clearing started */
|
||||
tasklet_disable(&local->tasklet);
|
||||
tasklet_enable(&local->tasklet);
|
||||
|
||||
barrier();
|
||||
|
||||
local->started = false;
|
||||
}
|
||||
|
||||
int drv_add_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
|
@ -192,6 +236,8 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local,
|
|||
int ret = 0;
|
||||
int i;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!local->ops->switch_vif_chanctx)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
|
@ -66,36 +66,8 @@ static inline int drv_get_et_sset_count(struct ieee80211_sub_if_data *sdata,
|
|||
return rv;
|
||||
}
|
||||
|
||||
static inline int drv_start(struct ieee80211_local *local)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
|
||||
trace_drv_start(local);
|
||||
local->started = true;
|
||||
smp_mb();
|
||||
ret = local->ops->start(&local->hw);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_stop(struct ieee80211_local *local)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
trace_drv_stop(local);
|
||||
local->ops->stop(&local->hw);
|
||||
trace_drv_return_void(local);
|
||||
|
||||
/* sync away all work on the tasklet before clearing started */
|
||||
tasklet_disable(&local->tasklet);
|
||||
tasklet_enable(&local->tasklet);
|
||||
|
||||
barrier();
|
||||
|
||||
local->started = false;
|
||||
}
|
||||
int drv_start(struct ieee80211_local *local);
|
||||
void drv_stop(struct ieee80211_local *local);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static inline int drv_suspend(struct ieee80211_local *local,
|
||||
|
@ -871,6 +843,8 @@ static inline int drv_add_chanctx(struct ieee80211_local *local,
|
|||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
might_sleep();
|
||||
|
||||
trace_drv_add_chanctx(local, ctx);
|
||||
if (local->ops->add_chanctx)
|
||||
ret = local->ops->add_chanctx(&local->hw, &ctx->conf);
|
||||
|
@ -884,6 +858,8 @@ static inline int drv_add_chanctx(struct ieee80211_local *local,
|
|||
static inline void drv_remove_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *ctx)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (WARN_ON(!ctx->driver_present))
|
||||
return;
|
||||
|
||||
|
@ -898,6 +874,8 @@ static inline void drv_change_chanctx(struct ieee80211_local *local,
|
|||
struct ieee80211_chanctx *ctx,
|
||||
u32 changed)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
trace_drv_change_chanctx(local, ctx, changed);
|
||||
if (local->ops->change_chanctx) {
|
||||
WARN_ON_ONCE(!ctx->driver_present);
|
||||
|
@ -931,6 +909,8 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
|
|||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_chanctx *ctx)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
|
@ -953,6 +933,8 @@ static inline int drv_start_ap(struct ieee80211_local *local,
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
|
|||
* keep them at 0
|
||||
*/
|
||||
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
|
||||
chandef, 0);
|
||||
chandef, 0, false);
|
||||
|
||||
/* add VHT capability and information IEs */
|
||||
if (chandef->width != NL80211_CHAN_WIDTH_20 &&
|
||||
|
@ -356,7 +356,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
else
|
||||
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
|
||||
|
||||
ieee80211_set_wmm_default(sdata, true);
|
||||
ieee80211_set_wmm_default(sdata, true, false);
|
||||
|
||||
sdata->vif.bss_conf.ibss_joined = true;
|
||||
sdata->vif.bss_conf.ibss_creator = creator;
|
||||
|
|
|
@ -1573,7 +1573,7 @@ __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
|||
struct cfg80211_sched_scan_request *req);
|
||||
int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_sched_scan_request *req);
|
||||
int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_request_sched_scan_stop(struct ieee80211_local *local);
|
||||
void ieee80211_sched_scan_end(struct ieee80211_local *local);
|
||||
void ieee80211_sched_scan_stopped_work(struct work_struct *work);
|
||||
|
||||
|
@ -1769,7 +1769,7 @@ int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
|
|||
int rate, int erp, int short_preamble,
|
||||
int shift);
|
||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
||||
bool bss_notify);
|
||||
bool bss_notify, bool enable_qos);
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb);
|
||||
|
||||
|
@ -1962,7 +1962,7 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
|||
u16 cap);
|
||||
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
u16 prot_mode);
|
||||
u16 prot_mode, bool rifs_mode);
|
||||
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
u32 cap);
|
||||
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
|
|
|
@ -661,11 +661,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
}
|
||||
|
||||
/*
|
||||
* set default queue parameters so drivers don't
|
||||
* Set default queue parameters so drivers don't
|
||||
* need to initialise the hardware if the hardware
|
||||
* doesn't start up with sane defaults
|
||||
* doesn't start up with sane defaults.
|
||||
* Enable QoS for anything but station interfaces.
|
||||
*/
|
||||
ieee80211_set_wmm_default(sdata, true);
|
||||
ieee80211_set_wmm_default(sdata, true,
|
||||
sdata->vif.type != NL80211_IFTYPE_STATION);
|
||||
}
|
||||
|
||||
set_bit(SDATA_STATE_RUNNING, &sdata->state);
|
||||
|
|
|
@ -281,7 +281,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
|
|||
local->in_reconfig = true;
|
||||
barrier();
|
||||
|
||||
schedule_work(&local->restart_work);
|
||||
queue_work(system_freezable_wq, &local->restart_work);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_restart_hw);
|
||||
|
||||
|
|
|
@ -466,7 +466,8 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
|
||||
ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
|
||||
sdata->vif.bss_conf.ht_operation_mode);
|
||||
sdata->vif.bss_conf.ht_operation_mode,
|
||||
false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -686,6 +686,9 @@ static bool llid_in_use(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
if (sdata != sta->sdata)
|
||||
continue;
|
||||
|
||||
if (!memcmp(&sta->mesh->llid, &llid, sizeof(llid))) {
|
||||
in_use = true;
|
||||
break;
|
||||
|
|
|
@ -1744,10 +1744,10 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *wmm_param, size_t wmm_param_len)
|
||||
{
|
||||
struct ieee80211_tx_queue_params params;
|
||||
struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS];
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
size_t left;
|
||||
int count;
|
||||
int count, ac;
|
||||
const u8 *pos;
|
||||
u8 uapsd_queues = 0;
|
||||
|
||||
|
@ -1781,25 +1781,24 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
int aci = (pos[0] >> 5) & 0x03;
|
||||
int acm = (pos[0] >> 4) & 0x01;
|
||||
bool uapsd = false;
|
||||
int queue;
|
||||
|
||||
switch (aci) {
|
||||
case 1: /* AC_BK */
|
||||
queue = 3;
|
||||
ac = IEEE80211_AC_BK;
|
||||
if (acm)
|
||||
sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
|
||||
uapsd = true;
|
||||
break;
|
||||
case 2: /* AC_VI */
|
||||
queue = 1;
|
||||
ac = IEEE80211_AC_VI;
|
||||
if (acm)
|
||||
sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
|
||||
uapsd = true;
|
||||
break;
|
||||
case 3: /* AC_VO */
|
||||
queue = 0;
|
||||
ac = IEEE80211_AC_VO;
|
||||
if (acm)
|
||||
sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
||||
|
@ -1807,7 +1806,7 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
break;
|
||||
case 0: /* AC_BE */
|
||||
default:
|
||||
queue = 2;
|
||||
ac = IEEE80211_AC_BE;
|
||||
if (acm)
|
||||
sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
|
||||
|
@ -1815,25 +1814,41 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
break;
|
||||
}
|
||||
|
||||
params.aifs = pos[0] & 0x0f;
|
||||
params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
|
||||
params.cw_min = ecw2cw(pos[1] & 0x0f);
|
||||
params.txop = get_unaligned_le16(pos + 2);
|
||||
params.acm = acm;
|
||||
params.uapsd = uapsd;
|
||||
params[ac].aifs = pos[0] & 0x0f;
|
||||
|
||||
if (params[ac].aifs < 2) {
|
||||
sdata_info(sdata,
|
||||
"AP has invalid WMM params (AIFSN=%d for ACI %d), will use 2\n",
|
||||
params[ac].aifs, aci);
|
||||
params[ac].aifs = 2;
|
||||
}
|
||||
params[ac].cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
|
||||
params[ac].cw_min = ecw2cw(pos[1] & 0x0f);
|
||||
params[ac].txop = get_unaligned_le16(pos + 2);
|
||||
params[ac].acm = acm;
|
||||
params[ac].uapsd = uapsd;
|
||||
|
||||
if (params[ac].cw_min > params[ac].cw_max) {
|
||||
sdata_info(sdata,
|
||||
"AP has invalid WMM params (CWmin/max=%d/%d for ACI %d), using defaults\n",
|
||||
params[ac].cw_min, params[ac].cw_max, aci);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
mlme_dbg(sdata,
|
||||
"WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
|
||||
queue, aci, acm,
|
||||
params.aifs, params.cw_min, params.cw_max,
|
||||
params.txop, params.uapsd,
|
||||
ifmgd->tx_tspec[queue].downgraded);
|
||||
sdata->tx_conf[queue] = params;
|
||||
if (!ifmgd->tx_tspec[queue].downgraded &&
|
||||
drv_conf_tx(local, sdata, queue, ¶ms))
|
||||
"WMM AC=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
|
||||
ac, params[ac].acm,
|
||||
params[ac].aifs, params[ac].cw_min, params[ac].cw_max,
|
||||
params[ac].txop, params[ac].uapsd,
|
||||
ifmgd->tx_tspec[ac].downgraded);
|
||||
sdata->tx_conf[ac] = params[ac];
|
||||
if (!ifmgd->tx_tspec[ac].downgraded &&
|
||||
drv_conf_tx(local, sdata, ac, ¶ms[ac]))
|
||||
sdata_err(sdata,
|
||||
"failed to set TX queue parameters for queue %d\n",
|
||||
queue);
|
||||
"failed to set TX queue parameters for AC %d\n",
|
||||
ac);
|
||||
}
|
||||
|
||||
/* enable WMM or activate new settings */
|
||||
|
@ -2077,7 +2092,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
|
||||
/* disassociated - set to defaults now */
|
||||
ieee80211_set_wmm_default(sdata, false);
|
||||
ieee80211_set_wmm_default(sdata, false, false);
|
||||
|
||||
del_timer_sync(&sdata->u.mgd.conn_mon_timer);
|
||||
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
|
||||
|
@ -3044,11 +3059,21 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
ifmgd->wmm_last_param_set = -1;
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && elems.wmm_param)
|
||||
ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
|
||||
elems.wmm_param_len);
|
||||
else
|
||||
ieee80211_set_wmm_default(sdata, false);
|
||||
if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
|
||||
ieee80211_set_wmm_default(sdata, false, false);
|
||||
} else if (!ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
|
||||
elems.wmm_param_len)) {
|
||||
/* still enable QoS since we might have HT/VHT */
|
||||
ieee80211_set_wmm_default(sdata, false, true);
|
||||
/* set the disable-WMM flag in this case to disable
|
||||
* tracking WMM parameter changes in the beacon if
|
||||
* the parameters weren't actually valid. Doing so
|
||||
* avoids changing parameters very strangely when
|
||||
* the AP is going back and forth between valid and
|
||||
* invalid parameters.
|
||||
*/
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_WMM;
|
||||
}
|
||||
changed |= BSS_CHANGED_QOS;
|
||||
|
||||
/* set AID and assoc capability,
|
||||
|
@ -4543,44 +4568,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool ieee80211_usable_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *wmm_param, int len)
|
||||
{
|
||||
const u8 *pos;
|
||||
size_t left;
|
||||
|
||||
if (len < 8)
|
||||
return false;
|
||||
|
||||
if (wmm_param[5] != 1 /* version */)
|
||||
return false;
|
||||
|
||||
pos = wmm_param + 8;
|
||||
left = len - 8;
|
||||
|
||||
for (; left >= 4; left -= 4, pos += 4) {
|
||||
u8 aifsn = pos[0] & 0x0f;
|
||||
u8 ecwmin = pos[1] & 0x0f;
|
||||
u8 ecwmax = (pos[1] & 0xf0) >> 4;
|
||||
int aci = (pos[0] >> 5) & 0x03;
|
||||
|
||||
if (aifsn < 2) {
|
||||
sdata_info(sdata,
|
||||
"AP has invalid WMM params (AIFSN=%d for ACI %d), disabling WMM\n",
|
||||
aifsn, aci);
|
||||
return false;
|
||||
}
|
||||
if (ecwmin > ecwmax) {
|
||||
sdata_info(sdata,
|
||||
"AP has invalid WMM params (ECWmin/max=%d/%d for ACI %d), disabling WMM\n",
|
||||
ecwmin, ecwmax, aci);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_assoc_request *req)
|
||||
{
|
||||
|
@ -4645,39 +4632,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
assoc_data->wmm = bss->wmm_used &&
|
||||
(local->hw.queues >= IEEE80211_NUM_ACS);
|
||||
if (assoc_data->wmm) {
|
||||
/* try to check validity of WMM params IE */
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
const u8 *wp, *start, *end;
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(req->bss->ies);
|
||||
start = ies->data;
|
||||
end = start + ies->len;
|
||||
|
||||
while (true) {
|
||||
wp = cfg80211_find_vendor_ie(
|
||||
WLAN_OUI_MICROSOFT,
|
||||
WLAN_OUI_TYPE_MICROSOFT_WMM,
|
||||
start, end - start);
|
||||
if (!wp)
|
||||
break;
|
||||
start = wp + wp[1] + 2;
|
||||
/* if this IE is too short, try the next */
|
||||
if (wp[1] <= 4)
|
||||
continue;
|
||||
/* if this IE is WMM params, we found what we wanted */
|
||||
if (wp[6] == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!wp || !ieee80211_usable_wmm_params(sdata, wp + 2,
|
||||
wp[1] - 2)) {
|
||||
assoc_data->wmm = false;
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_WMM;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode.
|
||||
|
@ -4936,6 +4890,25 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (ifmgd->assoc_data &&
|
||||
ether_addr_equal(ifmgd->assoc_data->bss->bssid, req->bssid)) {
|
||||
sdata_info(sdata,
|
||||
"aborting association with %pM by local choice (Reason: %u=%s)\n",
|
||||
req->bssid, req->reason_code,
|
||||
ieee80211_get_reason_code_string(req->reason_code));
|
||||
|
||||
drv_mgd_prepare_tx(sdata->local, sdata);
|
||||
ieee80211_send_deauth_disassoc(sdata, req->bssid,
|
||||
IEEE80211_STYPE_DEAUTH,
|
||||
req->reason_code, tx,
|
||||
frame_buf);
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
ieee80211_report_disconnect(sdata, frame_buf,
|
||||
sizeof(frame_buf), true,
|
||||
req->reason_code);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ifmgd->associated &&
|
||||
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
|
||||
sdata_info(sdata,
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
#include "driver-ops.h"
|
||||
#include "led.h"
|
||||
|
||||
static void ieee80211_sched_scan_cancel(struct ieee80211_local *local)
|
||||
{
|
||||
if (ieee80211_request_sched_scan_stop(local))
|
||||
return;
|
||||
cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy);
|
||||
}
|
||||
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
@ -34,6 +41,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
mutex_unlock(&local->sta_mtx);
|
||||
}
|
||||
|
||||
/* keep sched_scan only in case of 'any' trigger */
|
||||
if (!(wowlan && wowlan->any))
|
||||
ieee80211_sched_scan_cancel(local);
|
||||
|
||||
ieee80211_stop_queues_by_reason(hw,
|
||||
IEEE80211_MAX_QUEUE_MAP,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
|
||||
|
|
|
@ -307,7 +307,7 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
|
|||
}
|
||||
WARN_ONCE(i == sband->n_bitrates,
|
||||
"no supported rates (0x%x) in rate_mask 0x%x with flags 0x%x\n",
|
||||
sta ? sta->supp_rates[sband->band] : 0,
|
||||
sta ? sta->supp_rates[sband->band] : -1,
|
||||
rate_mask, rate_flags);
|
||||
|
||||
info->control.rates[0].count =
|
||||
|
|
|
@ -1140,10 +1140,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
|
||||
int ieee80211_request_sched_scan_stop(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int ret = 0;
|
||||
struct ieee80211_sub_if_data *sched_scan_sdata;
|
||||
int ret = -ENOENT;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
|
@ -1155,8 +1155,10 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
|
|||
/* We don't want to restart sched scan anymore. */
|
||||
RCU_INIT_POINTER(local->sched_scan_req, NULL);
|
||||
|
||||
if (rcu_access_pointer(local->sched_scan_sdata)) {
|
||||
ret = drv_sched_scan_stop(local, sdata);
|
||||
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
if (sched_scan_sdata) {
|
||||
ret = drv_sched_scan_stop(local, sched_scan_sdata);
|
||||
if (!ret)
|
||||
RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
|
||||
}
|
||||
|
|
|
@ -591,12 +591,19 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
|
|||
offset = noffset;
|
||||
}
|
||||
|
||||
/* if HT support is only added in TDLS, we need an HT-operation IE */
|
||||
/*
|
||||
* if HT support is only added in TDLS, we need an HT-operation IE.
|
||||
* add the IE as required by IEEE802.11-2012 9.23.3.2.
|
||||
*/
|
||||
if (!ap_sta->sta.ht_cap.ht_supported && sta->sta.ht_cap.ht_supported) {
|
||||
u16 prot = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED |
|
||||
IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
|
||||
IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT;
|
||||
|
||||
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
|
||||
/* send an empty HT operation IE */
|
||||
ieee80211_ie_build_ht_oper(pos, &sta->sta.ht_cap,
|
||||
&sdata->vif.bss_conf.chandef, 0);
|
||||
&sdata->vif.bss_conf.chandef, prot,
|
||||
true);
|
||||
}
|
||||
|
||||
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
|
||||
|
|
|
@ -34,10 +34,10 @@
|
|||
__field(u32, center_freq1) \
|
||||
__field(u32, center_freq2)
|
||||
#define CHANDEF_ASSIGN(c) \
|
||||
__entry->control_freq = (c)->chan ? (c)->chan->center_freq : 0; \
|
||||
__entry->chan_width = (c)->width; \
|
||||
__entry->center_freq1 = (c)->center_freq1; \
|
||||
__entry->center_freq2 = (c)->center_freq2;
|
||||
__entry->control_freq = (c) ? ((c)->chan ? (c)->chan->center_freq : 0) : 0; \
|
||||
__entry->chan_width = (c) ? (c)->width : 0; \
|
||||
__entry->center_freq1 = (c) ? (c)->center_freq1 : 0; \
|
||||
__entry->center_freq2 = (c) ? (c)->center_freq2 : 0;
|
||||
#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz"
|
||||
#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
|
||||
__entry->center_freq1, __entry->center_freq2
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -1104,13 +1105,13 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
|||
}
|
||||
|
||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
||||
bool bss_notify)
|
||||
bool bss_notify, bool enable_qos)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_queue_params qparam;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
int ac;
|
||||
bool use_11b, enable_qos;
|
||||
bool use_11b;
|
||||
bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */
|
||||
int aCWmin, aCWmax;
|
||||
|
||||
|
@ -1129,13 +1130,6 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
|||
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* By default disable QoS in STA mode for old access points, which do
|
||||
* not support 802.11e. New APs will provide proper queue parameters,
|
||||
* that we will configure later.
|
||||
*/
|
||||
enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
|
||||
|
||||
is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB);
|
||||
|
||||
/* Set defaults according to 802.11-2007 Table 7-37 */
|
||||
|
@ -1664,7 +1658,6 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
|
|||
|
||||
local->resuming = false;
|
||||
local->suspended = false;
|
||||
local->started = false;
|
||||
local->in_reconfig = false;
|
||||
|
||||
/* scheduled scan clearly can't be running any more, but tell
|
||||
|
@ -1753,6 +1746,18 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In case of hw_restart during suspend (without wowlan),
|
||||
* cancel restart work, as we are reconfiguring the device
|
||||
* anyway.
|
||||
* Note that restart_work is scheduled on a frozen workqueue,
|
||||
* so we can't deadlock in this case.
|
||||
*/
|
||||
if (suspended && local->in_reconfig && !reconfig_due_to_wowlan)
|
||||
cancel_work_sync(&local->restart_work);
|
||||
|
||||
local->started = false;
|
||||
|
||||
/*
|
||||
* Upon resume hardware can sometimes be goofy due to
|
||||
* various platform / driver / bus issues, so restarting
|
||||
|
@ -1996,6 +2001,29 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
if (ieee80211_sdata_running(sdata))
|
||||
ieee80211_enable_keys(sdata);
|
||||
|
||||
/* Reconfigure sched scan if it was interrupted by FW restart */
|
||||
mutex_lock(&local->mtx);
|
||||
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
sched_scan_req = rcu_dereference_protected(local->sched_scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
if (sched_scan_sdata && sched_scan_req)
|
||||
/*
|
||||
* Sched scan stopped, but we don't want to report it. Instead,
|
||||
* we're trying to reschedule. However, if more than one scan
|
||||
* plan was set, we cannot reschedule since we don't know which
|
||||
* scan plan was currently running (and some scan plans may have
|
||||
* already finished).
|
||||
*/
|
||||
if (sched_scan_req->n_scan_plans > 1 ||
|
||||
__ieee80211_request_sched_scan_start(sched_scan_sdata,
|
||||
sched_scan_req))
|
||||
sched_scan_stopped = true;
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (sched_scan_stopped)
|
||||
cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy);
|
||||
|
||||
wake_up:
|
||||
local->in_reconfig = false;
|
||||
barrier();
|
||||
|
@ -2030,32 +2058,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
|
||||
false);
|
||||
|
||||
/*
|
||||
* Reconfigure sched scan if it was interrupted by FW restart or
|
||||
* suspend.
|
||||
*/
|
||||
mutex_lock(&local->mtx);
|
||||
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
sched_scan_req = rcu_dereference_protected(local->sched_scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
if (sched_scan_sdata && sched_scan_req)
|
||||
/*
|
||||
* Sched scan stopped, but we don't want to report it. Instead,
|
||||
* we're trying to reschedule. However, if more than one scan
|
||||
* plan was set, we cannot reschedule since we don't know which
|
||||
* scan plan was currently running (and some scan plans may have
|
||||
* already finished).
|
||||
*/
|
||||
if (sched_scan_req->n_scan_plans > 1 ||
|
||||
__ieee80211_request_sched_scan_start(sched_scan_sdata,
|
||||
sched_scan_req))
|
||||
sched_scan_stopped = true;
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (sched_scan_stopped)
|
||||
cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy);
|
||||
|
||||
/*
|
||||
* If this is for hw restart things are still running.
|
||||
* We may want to change that later, however.
|
||||
|
@ -2140,7 +2142,13 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
|
|||
chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
|
||||
if (WARN_ON_ONCE(!chanctx_conf))
|
||||
/*
|
||||
* This function can be called from a work, thus it may be possible
|
||||
* that the chanctx_conf is removed (due to a disconnection, for
|
||||
* example).
|
||||
* So nothing should be done in such case.
|
||||
*/
|
||||
if (!chanctx_conf)
|
||||
goto unlock;
|
||||
|
||||
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
|
||||
|
@ -2277,7 +2285,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
|||
|
||||
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
u16 prot_mode)
|
||||
u16 prot_mode, bool rifs_mode)
|
||||
{
|
||||
struct ieee80211_ht_operation *ht_oper;
|
||||
/* Build HT Information */
|
||||
|
@ -2305,6 +2313,9 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
|||
chandef->width != NL80211_CHAN_WIDTH_20)
|
||||
ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
|
||||
|
||||
if (rifs_mode)
|
||||
ht_oper->ht_param |= IEEE80211_HT_PARAM_RIFS_MODE;
|
||||
|
||||
ht_oper->operation_mode = cpu_to_le16(prot_mode);
|
||||
ht_oper->stbc_param = 0x0000;
|
||||
|
||||
|
@ -2958,6 +2969,13 @@ ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i)
|
|||
if (end > 0)
|
||||
return false;
|
||||
|
||||
/* One shot NOA */
|
||||
if (data->count[i] == 1)
|
||||
return false;
|
||||
|
||||
if (data->desc[i].interval == 0)
|
||||
return false;
|
||||
|
||||
/* End time is in the past, check for repetitions */
|
||||
skip = DIV_ROUND_UP(-end, data->desc[i].interval);
|
||||
if (data->count[i] < 255) {
|
||||
|
|
|
@ -3432,12 +3432,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
wdev->iftype))
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
|
||||
params.acl = parse_acl_data(&rdev->wiphy, info);
|
||||
if (IS_ERR(params.acl))
|
||||
return PTR_ERR(params.acl);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
|
||||
params.smps_mode =
|
||||
nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
|
||||
|
@ -3461,6 +3455,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
params.smps_mode = NL80211_SMPS_OFF;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
|
||||
params.acl = parse_acl_data(&rdev->wiphy, info);
|
||||
if (IS_ERR(params.acl))
|
||||
return PTR_ERR(params.acl);
|
||||
}
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = rdev_start_ap(rdev, dev, ¶ms);
|
||||
if (!err) {
|
||||
|
@ -3968,10 +3968,13 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
|
|||
struct station_parameters *params,
|
||||
enum cfg80211_station_type statype)
|
||||
{
|
||||
if (params->listen_interval != -1)
|
||||
if (params->listen_interval != -1 &&
|
||||
statype != CFG80211_STA_AP_CLIENT_UNASSOC)
|
||||
return -EINVAL;
|
||||
|
||||
if (params->aid &&
|
||||
!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
|
||||
!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
|
||||
statype != CFG80211_STA_AP_CLIENT_UNASSOC)
|
||||
return -EINVAL;
|
||||
|
||||
/* When you run into this, adjust the code below for the new flag */
|
||||
|
@ -4245,13 +4248,22 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params.listen_interval = -1;
|
||||
|
||||
if (!rdev->ops->change_station)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_STA_AID])
|
||||
return -EINVAL;
|
||||
/*
|
||||
* AID and listen_interval properties can be set only for unassociated
|
||||
* station. Include these parameters here and will check them in
|
||||
* cfg80211_check_station_change().
|
||||
*/
|
||||
if (info->attrs[NL80211_ATTR_PEER_AID])
|
||||
params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
|
||||
params.listen_interval =
|
||||
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
|
||||
else
|
||||
params.listen_interval = -1;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_MAC])
|
||||
return -EINVAL;
|
||||
|
@ -4278,9 +4290,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
|||
nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
|
||||
return -EINVAL;
|
||||
|
||||
if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
Loading…
Reference in New Issue