One more set of new features:

* beacon report (for radio measurement) support in cfg80211/mac80211
  * hwsim: allow wmediumd in namespaces
  * mac80211: extend 160MHz workaround to CSA IEs
  * mesh: properly encrypt group-addressed privacy action frames
  * mesh: allow setting peer AID
  * first steps for MU-MIMO monitor mode
  * along with various other cleanups and improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABCgAGBQJXfSCuAAoJEGt7eEactAAdaugP/ilrcELQRsIN5ZXCAKYZuwXV
 T01JPwgOaWL9ILu7h1SfG/+j9kzMnyk4WmRpeoj2FGNcyfG2AvULWSLpQJ2abwgQ
 8o/emuLinQwRENevaMUTRSOE0HkXoFPCbbq37+a2i6bAv1QSYY3A0xvWpcU5fZ4D
 7CKYDYPBAdMXYwEwy1g4nYWfDAYqS4rthr3l3rS1Cy7Q2T1ZlMlD90GjD7oeQAEw
 orKulhkkDSzvxfvZCYTzXmUoBQE8sNXGDD+OFsJyowyt+ugM/xan+2tmhCaHSnda
 HpdCS2aRj779UBn9cOfELjffTNpS++PM6KFd8ZDaPcJSMginn/BAHTOeNfNUfL0Q
 +Enu59I82qMDzbG2z1Qezzjv7OTzyEvyvYzNbLOqljTBSBklDa3rHwhyk+g1oVBH
 +4xX1Vk5QBLde+Q0NS0gTkcqOQK8KT5+HEqiUfgLSNDETN0lSGsKbtvMfU/ikE1Y
 aLRkTp7nzUd03qjIFLS6RMf7JjucWWzH1ZXTHvbpDFAG7riOhYRD3Sw+0e7madTd
 +HXjH9dnOGnGPDL+FyDwtW6iclYwNjcIPQiNdOjwWfMA2Wmr7iq+aFUptRCwQTHB
 WtgJ3f8OHax2JXcm4grYfxELZip5vbWJJHUC84Drvmzw3X7FRITf+OEWjdNOzsRD
 Fc7w5ceThh9Id1BvcH2+
 =R1qP
 -----END PGP SIGNATURE-----

Merge tag 'mac80211-next-for-davem-2016-07-06' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
One more set of new features:
 * beacon report (for radio measurement) support in cfg80211/mac80211
 * hwsim: allow wmediumd in namespaces
 * mac80211: extend 160MHz workaround to CSA IEs
 * mesh: properly encrypt group-addressed privacy action frames
 * mesh: allow setting peer AID
 * first steps for MU-MIMO monitor mode
 * along with various other cleanups and improvements
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2016-07-06 22:32:15 -07:00
commit a90a6e55f3
46 changed files with 742 additions and 203 deletions

View file

@ -3858,12 +3858,16 @@ void __ath10k_scan_finish(struct ath10k *ar)
break;
case ATH10K_SCAN_RUNNING:
case ATH10K_SCAN_ABORTING:
if (!ar->scan.is_roc)
ieee80211_scan_completed(ar->hw,
(ar->scan.state ==
ATH10K_SCAN_ABORTING));
else if (ar->scan.roc_notify)
if (!ar->scan.is_roc) {
struct cfg80211_scan_info info = {
.aborted = (ar->scan.state ==
ATH10K_SCAN_ABORTING),
};
ieee80211_scan_completed(ar->hw, &info);
} else if (ar->scan.roc_notify) {
ieee80211_remain_on_channel_expired(ar->hw);
}
/* fall through */
case ATH10K_SCAN_STARTING:
ar->scan.state = ATH10K_SCAN_IDLE;

View file

@ -859,7 +859,11 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
struct ath6kl *ar = vif->ar;
if (vif->scan_req) {
cfg80211_scan_done(vif->scan_req, true);
struct cfg80211_scan_info info = {
.aborted = true,
};
cfg80211_scan_done(vif->scan_req, &info);
vif->scan_req = NULL;
}
@ -1069,6 +1073,9 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy,
void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
{
struct ath6kl *ar = vif->ar;
struct cfg80211_scan_info info = {
.aborted = aborted,
};
int i;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
@ -1089,7 +1096,7 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
}
out:
cfg80211_scan_done(vif->scan_req, aborted);
cfg80211_scan_done(vif->scan_req, &info);
vif->scan_req = NULL;
}
@ -3614,7 +3621,11 @@ void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready)
}
if (vif->scan_req) {
cfg80211_scan_done(vif->scan_req, true);
struct cfg80211_scan_info info = {
.aborted = true,
};
cfg80211_scan_done(vif->scan_req, &info);
vif->scan_req = NULL;
}

View file

@ -960,6 +960,9 @@ void ath_roc_complete(struct ath_softc *sc, enum ath_roc_complete_reason reason)
void ath_scan_complete(struct ath_softc *sc, bool abort)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct cfg80211_scan_info info = {
.aborted = abort,
};
if (abort)
ath_dbg(common, CHAN_CTX, "HW scan aborted\n");
@ -969,7 +972,7 @@ void ath_scan_complete(struct ath_softc *sc, bool abort)
sc->offchannel.scan_req = NULL;
sc->offchannel.scan_vif = NULL;
sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
ieee80211_scan_completed(sc->hw, abort);
ieee80211_scan_completed(sc->hw, &info);
clear_bit(ATH_OP_SCANNING, &common->op_flags);
spin_lock_bh(&sc->chan_lock);
if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))

View file

@ -1369,7 +1369,11 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
started = wil_p2p_stop_discovery(wil);
if (started && wil->scan_request) {
cfg80211_scan_done(wil->scan_request, 1);
struct cfg80211_scan_info info = {
.aborted = true,
};
cfg80211_scan_done(wil->scan_request, &info);
wil->scan_request = NULL;
wil->radio_wdev = wil->wdev;
}

View file

@ -850,10 +850,14 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
mutex_unlock(&wil->wmi_mutex);
if (wil->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
wil->scan_request);
del_timer_sync(&wil->scan_timer);
cfg80211_scan_done(wil->scan_request, true);
cfg80211_scan_done(wil->scan_request, &info);
wil->scan_request = NULL;
}
@ -1049,10 +1053,14 @@ int __wil_down(struct wil6210_priv *wil)
(void)wil_p2p_stop_discovery(wil);
if (wil->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
wil->scan_request);
del_timer_sync(&wil->scan_timer);
cfg80211_scan_done(wil->scan_request, true);
cfg80211_scan_done(wil->scan_request, &info);
wil->scan_request = NULL;
}

View file

@ -252,8 +252,12 @@ void wil_p2p_search_expired(struct work_struct *work)
mutex_unlock(&wil->mutex);
if (started) {
struct cfg80211_scan_info info = {
.aborted = false,
};
mutex_lock(&wil->p2p_wdev_mutex);
cfg80211_scan_done(wil->scan_request, 0);
cfg80211_scan_done(wil->scan_request, &info);
wil->scan_request = NULL;
wil->radio_wdev = wil->wdev;
mutex_unlock(&wil->p2p_wdev_mutex);

View file

@ -426,15 +426,17 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
{
if (wil->scan_request) {
struct wmi_scan_complete_event *data = d;
bool aborted = (data->status != WMI_SCAN_SUCCESS);
struct cfg80211_scan_info info = {
.aborted = (data->status != WMI_SCAN_SUCCESS),
};
wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
wil->scan_request, aborted);
wil->scan_request, info.aborted);
del_timer_sync(&wil->scan_timer);
mutex_lock(&wil->p2p_wdev_mutex);
cfg80211_scan_done(wil->scan_request, aborted);
cfg80211_scan_done(wil->scan_request, &info);
wil->radio_wdev = wil->wdev;
mutex_unlock(&wil->p2p_wdev_mutex);
wil->scan_request = NULL;

View file

@ -1922,6 +1922,9 @@ static void at76_dwork_hw_scan(struct work_struct *work)
{
struct at76_priv *priv = container_of(work, struct at76_priv,
dwork_hw_scan.work);
struct cfg80211_scan_info info = {
.aborted = false,
};
int ret;
if (priv->device_unplugged)
@ -1948,7 +1951,7 @@ static void at76_dwork_hw_scan(struct work_struct *work)
mutex_unlock(&priv->mtx);
ieee80211_scan_completed(priv->hw, false);
ieee80211_scan_completed(priv->hw, &info);
ieee80211_wake_queues(priv->hw);
}

View file

@ -775,9 +775,13 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
if (!aborted)
cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
} else if (scan_request) {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
aborted ? "Aborted" : "Done");
cfg80211_scan_done(scan_request, aborted);
cfg80211_scan_done(scan_request, &info);
}
if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");

View file

@ -1305,10 +1305,14 @@ il_send_scan_abort(struct il_priv *il)
static void
il_complete_scan(struct il_priv *il, bool aborted)
{
struct cfg80211_scan_info info = {
.aborted = aborted,
};
/* check if scan was requested from mac80211 */
if (il->scan_request) {
D_SCAN("Complete scan in mac80211\n");
ieee80211_scan_completed(il->hw, aborted);
ieee80211_scan_completed(il->hw, &info);
}
il->scan_vif = NULL;

View file

@ -94,10 +94,14 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
{
struct cfg80211_scan_info info = {
.aborted = aborted,
};
/* check if scan was requested from mac80211 */
if (priv->scan_request) {
IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
ieee80211_scan_completed(priv->hw, aborted);
ieee80211_scan_completed(priv->hw, &info);
}
priv->scan_type = IWL_SCAN_NORMAL;

View file

@ -391,13 +391,16 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
ieee80211_sched_scan_stopped(mvm->hw);
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
} else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n",
aborted ? "aborted" : "completed",
iwl_mvm_ebs_status_str(scan_notif->ebs_status));
mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR;
ieee80211_scan_completed(mvm->hw,
scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
ieee80211_scan_completed(mvm->hw, &info);
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
del_timer(&mvm->scan_timer);
} else {
@ -1430,7 +1433,11 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
/* if the scan is already stopping, we don't need to notify mac80211 */
if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) {
ieee80211_scan_completed(mvm->hw, aborted);
struct cfg80211_scan_info info = {
.aborted = aborted,
};
ieee80211_scan_completed(mvm->hw, &info);
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
del_timer(&mvm->scan_timer);
} else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
@ -1564,7 +1571,11 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_REGULAR);
if (uid >= 0) {
ieee80211_scan_completed(mvm->hw, true);
struct cfg80211_scan_info info = {
.aborted = true,
};
ieee80211_scan_completed(mvm->hw, &info);
mvm->scan_uid_status[uid] = 0;
}
uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED);
@ -1585,8 +1596,13 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
mvm->scan_uid_status[i] = 0;
}
} else {
if (mvm->scan_status & IWL_MVM_SCAN_REGULAR)
ieee80211_scan_completed(mvm->hw, true);
if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
struct cfg80211_scan_info info = {
.aborted = true,
};
ieee80211_scan_completed(mvm->hw, &info);
}
/* Sched scan will be restarted by mac80211 in
* restart_hw, so do not report if FW is about to be
@ -1629,8 +1645,13 @@ out:
*/
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
del_timer(&mvm->scan_timer);
if (notify)
ieee80211_scan_completed(mvm->hw, true);
if (notify) {
struct cfg80211_scan_info info = {
.aborted = true,
};
ieee80211_scan_completed(mvm->hw, &info);
}
} else if (notify) {
ieee80211_sched_scan_stopped(mvm->hw);
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;

View file

@ -237,7 +237,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv,
scan_abort:
if (priv->scan_request) {
cfg80211_scan_done(priv->scan_request, abort);
struct cfg80211_scan_info info = {
.aborted = abort,
};
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
}
@ -245,7 +249,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv,
void orinoco_scan_done(struct orinoco_private *priv, bool abort)
{
if (priv->scan_request) {
cfg80211_scan_done(priv->scan_request, abort);
struct cfg80211_scan_info info = {
.aborted = abort,
};
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
}

View file

@ -41,8 +41,6 @@ MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
MODULE_LICENSE("GPL");
static u32 wmediumd_portid;
static int radios = 2;
module_param(radios, int, 0444);
MODULE_PARM_DESC(radios, "Number of simulated radios");
@ -252,12 +250,13 @@ static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c)
cp->magic = 0;
}
static unsigned int hwsim_net_id;
static int hwsim_net_id;
static int hwsim_netgroup;
struct hwsim_net {
int netgroup;
u32 wmediumd;
};
static inline int hwsim_net_get_netgroup(struct net *net)
@ -274,6 +273,20 @@ static inline void hwsim_net_set_netgroup(struct net *net)
hwsim_net->netgroup = hwsim_netgroup++;
}
static inline u32 hwsim_net_get_wmediumd(struct net *net)
{
struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
return hwsim_net->wmediumd;
}
static inline void hwsim_net_set_wmediumd(struct net *net, u32 portid)
{
struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
hwsim_net->wmediumd = portid;
}
static struct class *hwsim_class;
static struct net_device *hwsim_mon; /* global monitor netdev */
@ -444,10 +457,6 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }
};
static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
{ .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
};
static const struct ieee80211_iface_combination hwsim_if_comb[] = {
{
.limits = hwsim_if_limits,
@ -455,18 +464,12 @@ static const struct ieee80211_iface_combination hwsim_if_comb[] = {
.n_limits = ARRAY_SIZE(hwsim_if_limits) - 1,
.max_interfaces = 2048,
.num_different_channels = 1,
},
{
.limits = hwsim_if_dfs_limits,
.n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
.max_interfaces = 8,
.num_different_channels = 1,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
}
},
};
static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
@ -475,18 +478,12 @@ static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
.num_different_channels = 1,
},
{
.limits = hwsim_if_dfs_limits,
.n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
.max_interfaces = 8,
.num_different_channels = 1,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
}
},
};
static spinlock_t hwsim_radio_lock;
@ -552,6 +549,8 @@ struct mac80211_hwsim_data {
/* group shared by radios created in the same netns */
int netgroup;
/* wmediumd portid responsible for netgroup of this radio */
u32 wmediumd;
int power_level;
@ -983,6 +982,29 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
return true;
}
static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data,
struct sk_buff *skb, int portid)
{
struct net *net;
bool found = false;
int res = -ENOENT;
rcu_read_lock();
for_each_net_rcu(net) {
if (data->netgroup == hwsim_net_get_netgroup(net)) {
res = genlmsg_unicast(net, skb, portid);
found = true;
break;
}
}
rcu_read_unlock();
if (!found)
nlmsg_free(skb);
return res;
}
static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
struct sk_buff *my_skb,
int dst_portid)
@ -1062,7 +1084,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
goto nla_put_failure;
genlmsg_end(skb, msg_head);
if (genlmsg_unicast(&init_net, skb, dst_portid))
if (hwsim_unicast_netgroup(data, skb, dst_portid))
goto err_free_txskb;
/* Enqueue the packet */
@ -1355,7 +1377,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
mac80211_hwsim_monitor_rx(hw, skb, channel);
/* wmediumd mode check */
_portid = ACCESS_ONCE(wmediumd_portid);
_portid = ACCESS_ONCE(data->wmediumd);
if (_portid)
return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
@ -1451,7 +1473,8 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_channel *chan)
{
u32 _pid = ACCESS_ONCE(wmediumd_portid);
struct mac80211_hwsim_data *data = hw->priv;
u32 _pid = ACCESS_ONCE(data->wmediumd);
if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) {
struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
@ -1918,8 +1941,12 @@ static void hw_scan_work(struct work_struct *work)
mutex_lock(&hwsim->mutex);
if (hwsim->scan_chan_idx >= req->n_channels) {
struct cfg80211_scan_info info = {
.aborted = false,
};
wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n");
ieee80211_scan_completed(hwsim->hw, false);
ieee80211_scan_completed(hwsim->hw, &info);
hwsim->hw_scan_request = NULL;
hwsim->hw_scan_vif = NULL;
hwsim->tmp_chan = NULL;
@ -2004,13 +2031,16 @@ static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *hwsim = hw->priv;
struct cfg80211_scan_info info = {
.aborted = true,
};
wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n");
cancel_delayed_work_sync(&hwsim->hw_scan);
mutex_lock(&hwsim->mutex);
ieee80211_scan_completed(hwsim->hw, true);
ieee80211_scan_completed(hwsim->hw, &info);
hwsim->tmp_chan = NULL;
hwsim->hw_scan_request = NULL;
hwsim->hw_scan_vif = NULL;
@ -2448,13 +2478,14 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
hw->wiphy->max_remain_on_channel_duration = 1000;
/* For channels > 1 DFS is not allowed */
hw->wiphy->n_iface_combinations = 1;
hw->wiphy->iface_combinations = &data->if_combination;
if (param->p2p_device)
data->if_combination = hwsim_if_comb_p2p_dev[0];
else
data->if_combination = hwsim_if_comb[0];
hw->wiphy->n_iface_combinations = 1;
/* For channels > 1 DFS is not allowed */
data->if_combination.radar_detect_widths = 0;
data->if_combination.num_different_channels = data->channels;
} else if (param->p2p_device) {
hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
@ -2796,6 +2827,20 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)
return data;
}
static void hwsim_register_wmediumd(struct net *net, u32 portid)
{
struct mac80211_hwsim_data *data;
hwsim_net_set_wmediumd(net, portid);
spin_lock_bh(&hwsim_radio_lock);
list_for_each_entry(data, &hwsim_radios, list) {
if (data->netgroup == hwsim_net_get_netgroup(net))
data->wmediumd = portid;
}
spin_unlock_bh(&hwsim_radio_lock);
}
static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
struct genl_info *info)
{
@ -2811,9 +2856,6 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
int i;
bool found = false;
if (info->snd_portid != wmediumd_portid)
return -EINVAL;
if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
!info->attrs[HWSIM_ATTR_FLAGS] ||
!info->attrs[HWSIM_ATTR_COOKIE] ||
@ -2829,6 +2871,12 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
if (!data2)
goto out;
if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
goto out;
if (info->snd_portid != data2->wmediumd)
goto out;
/* look for the skb matching the cookie passed back from user */
skb_queue_walk_safe(&data2->pending, skb, tmp) {
u64 skb_cookie;
@ -2892,9 +2940,6 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
void *frame_data;
struct sk_buff *skb = NULL;
if (info->snd_portid != wmediumd_portid)
return -EINVAL;
if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
!info->attrs[HWSIM_ATTR_FRAME] ||
!info->attrs[HWSIM_ATTR_RX_RATE] ||
@ -2920,6 +2965,12 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
if (!data2)
goto out;
if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
goto out;
if (info->snd_portid != data2->wmediumd)
goto out;
/* check if radio is configured properly */
if (data2->idle || !data2->started)
@ -2966,6 +3017,7 @@ out:
static int hwsim_register_received_nl(struct sk_buff *skb_2,
struct genl_info *info)
{
struct net *net = genl_info_net(info);
struct mac80211_hwsim_data *data;
int chans = 1;
@ -2982,10 +3034,10 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
if (chans > 1)
return -EOPNOTSUPP;
if (wmediumd_portid)
if (hwsim_net_get_wmediumd(net))
return -EBUSY;
wmediumd_portid = info->snd_portid;
hwsim_register_wmediumd(net, info->snd_portid);
printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, "
"switching to wmediumd mode with pid %d\n", info->snd_portid);
@ -3152,7 +3204,7 @@ static const struct genl_ops hwsim_ops[] = {
.cmd = HWSIM_CMD_REGISTER,
.policy = hwsim_genl_policy,
.doit = hwsim_register_received_nl,
.flags = GENL_ADMIN_PERM,
.flags = GENL_UNS_ADMIN_PERM,
},
{
.cmd = HWSIM_CMD_FRAME,
@ -3218,10 +3270,10 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
remove_user_radios(notify->portid);
if (notify->portid == wmediumd_portid) {
if (notify->portid == hwsim_net_get_wmediumd(notify->net)) {
printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
" socket, switching to perfect channel medium\n");
wmediumd_portid = 0;
hwsim_register_wmediumd(notify->net, 0);
}
return NOTIFY_DONE;

View file

@ -796,10 +796,15 @@ void lbs_scan_done(struct lbs_private *priv)
{
WARN_ON(!priv->scan_req);
if (priv->internal_scan)
if (priv->internal_scan) {
kfree(priv->scan_req);
else
cfg80211_scan_done(priv->scan_req, false);
} else {
struct cfg80211_scan_info info = {
.aborted = false,
};
cfg80211_scan_done(priv->scan_req, &info);
}
priv->scan_req = NULL;
}

View file

@ -1057,8 +1057,12 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
if (!priv)
continue;
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
}
@ -1112,8 +1116,12 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
if (!priv)
continue;
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
}

View file

@ -697,9 +697,13 @@ mwifiex_close(struct net_device *dev)
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
mwifiex_dbg(priv->adapter, INFO,
"aborting scan on ndo_stop\n");
cfg80211_scan_done(priv->scan_request, 1);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
priv->scan_aborting = true;
}

View file

@ -1956,9 +1956,13 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
mwifiex_complete_scan(priv);
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = false,
};
mwifiex_dbg(adapter, INFO,
"info: notifying scan done\n");
cfg80211_scan_done(priv->scan_request, 0);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;
@ -1977,9 +1981,13 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
if (!adapter->active_scan_triggered) {
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
mwifiex_dbg(adapter, INFO,
"info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;

View file

@ -2134,6 +2134,7 @@ static void rndis_get_scan_results(struct work_struct *work)
struct rndis_wlan_private *priv =
container_of(work, struct rndis_wlan_private, scan_work.work);
struct usbnet *usbdev = priv->usbdev;
struct cfg80211_scan_info info = {};
int ret;
netdev_dbg(usbdev->net, "get_scan_results\n");
@ -2143,7 +2144,8 @@ static void rndis_get_scan_results(struct work_struct *work)
ret = rndis_check_bssid_list(usbdev, NULL, NULL);
cfg80211_scan_done(priv->scan_request, ret < 0);
info.aborted = ret < 0;
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
@ -3574,7 +3576,11 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
flush_workqueue(priv->workqueue);
if (priv->scan_request) {
cfg80211_scan_done(priv->scan_request, true);
struct cfg80211_scan_info info = {
.aborted = true,
};
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}

View file

@ -167,6 +167,10 @@ void cw1200_scan_work(struct work_struct *work)
}
if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) {
struct cfg80211_scan_info info = {
.aborted = priv->scan.status ? 1 : 0,
};
if (priv->scan.output_power != priv->output_power)
wsm_set_output_power(priv, priv->output_power * 10);
if (priv->join_status == CW1200_JOIN_STATUS_STA &&
@ -188,7 +192,7 @@ void cw1200_scan_work(struct work_struct *work)
cw1200_scan_restart_delayed(priv);
wsm_unlock_tx(priv);
mutex_unlock(&priv->conf_mutex);
ieee80211_scan_completed(priv->hw, priv->scan.status ? 1 : 0);
ieee80211_scan_completed(priv->hw, &info);
up(&priv->scan.lock);
return;
} else {

View file

@ -36,7 +36,11 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
mbox->scheduled_scan_channels);
if (wl->scanning) {
ieee80211_scan_completed(wl->hw, false);
struct cfg80211_scan_info info = {
.aborted = false,
};
ieee80211_scan_completed(wl->hw, &info);
wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
wl->scanning = false;
if (wl->hw->conf.flags & IEEE80211_CONF_IDLE)

View file

@ -448,7 +448,11 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
WARN_ON(wl->state != WL1251_STATE_ON);
if (wl->scanning) {
ieee80211_scan_completed(wl->hw, true);
struct cfg80211_scan_info info = {
.aborted = true,
};
ieee80211_scan_completed(wl->hw, &info);
wl->scanning = false;
}

View file

@ -2615,6 +2615,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
wl->scan_wlvif == wlvif) {
struct cfg80211_scan_info info = {
.aborted = true,
};
/*
* Rearm the tx watchdog just before idling scan. This
* prevents just-finished scans from triggering the watchdog
@ -2625,7 +2629,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan_wlvif = NULL;
wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true);
ieee80211_scan_completed(wl->hw, &info);
}
if (wl->sched_vif == wlvif)
@ -3649,6 +3653,9 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct cfg80211_scan_info info = {
.aborted = true,
};
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
@ -3681,7 +3688,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan_wlvif = NULL;
wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true);
ieee80211_scan_completed(wl->hw, &info);
out_sleep:
wl1271_ps_elp_sleep(wl);

View file

@ -36,6 +36,9 @@ void wl1271_scan_complete_work(struct work_struct *work)
struct delayed_work *dwork;
struct wl1271 *wl;
struct wl12xx_vif *wlvif;
struct cfg80211_scan_info info = {
.aborted = false,
};
int ret;
dwork = to_delayed_work(work);
@ -82,7 +85,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
wlcore_cmd_regdomain_config_locked(wl);
ieee80211_scan_completed(wl->hw, false);
ieee80211_scan_completed(wl->hw, &info);
out:
mutex_unlock(&wl->mutex);

View file

@ -1256,10 +1256,15 @@ void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv,
DBG_8723A("%s with scan req\n", __func__);
if (pwdev_priv->scan_request->wiphy !=
pwdev_priv->rtw_wdev->wiphy)
pwdev_priv->rtw_wdev->wiphy) {
DBG_8723A("error wiphy compare\n");
else
cfg80211_scan_done(pwdev_priv->scan_request, aborted);
} else {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
cfg80211_scan_done(pwdev_priv->scan_request, &info);
}
pwdev_priv->scan_request = NULL;
} else {

View file

@ -454,7 +454,11 @@ static void CfgScanResult(enum scan_event scan_event,
mutex_lock(&priv->scan_req_lock);
if (priv->pstrScanReq) {
cfg80211_scan_done(priv->pstrScanReq, false);
struct cfg80211_scan_info info = {
.aborted = false,
};
cfg80211_scan_done(priv->pstrScanReq, &info);
priv->u32RcvdChCount = 0;
priv->bCfgScanning = false;
priv->pstrScanReq = NULL;
@ -464,10 +468,14 @@ static void CfgScanResult(enum scan_event scan_event,
mutex_lock(&priv->scan_req_lock);
if (priv->pstrScanReq) {
struct cfg80211_scan_info info = {
.aborted = false,
};
update_scan_time();
refresh_scan(priv, 1, false);
cfg80211_scan_done(priv->pstrScanReq, false);
cfg80211_scan_done(priv->pstrScanReq, &info);
priv->bCfgScanning = false;
priv->pstrScanReq = NULL;
}

View file

@ -338,6 +338,8 @@ static int prism2_scan(struct wiphy *wiphy,
struct p80211msg_dot11req_scan msg1;
struct p80211msg_dot11req_scan_results msg2;
struct cfg80211_bss *bss;
struct cfg80211_scan_info info = {};
int result;
int err = 0;
int numbss = 0;
@ -440,7 +442,8 @@ static int prism2_scan(struct wiphy *wiphy,
err = prism2_result2err(msg2.resultcode.data);
exit:
cfg80211_scan_done(request, err ? 1 : 0);
info.aborted = !!(err);
cfg80211_scan_done(request, &info);
priv->scan_request = NULL;
return err;
}

View file

@ -19,6 +19,7 @@
#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/etherdevice.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@ -2464,7 +2465,7 @@ static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
*/
static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
{
if (skb->len < 25)
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
return false;
return _ieee80211_is_robust_mgmt_frame((void *)skb->data);
}
@ -2486,6 +2487,35 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr,
return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC;
}
/**
* _ieee80211_is_group_privacy_action - check if frame is a group addressed
* privacy action frame
* @hdr: the frame
*/
static inline bool _ieee80211_is_group_privacy_action(struct ieee80211_hdr *hdr)
{
struct ieee80211_mgmt *mgmt = (void *)hdr;
if (!ieee80211_is_action(hdr->frame_control) ||
!is_multicast_ether_addr(hdr->addr1))
return false;
return mgmt->u.action.category == WLAN_CATEGORY_MESH_ACTION ||
mgmt->u.action.category == WLAN_CATEGORY_MULTIHOP_ACTION;
}
/**
* ieee80211_is_group_privacy_action - check if frame is a group addressed
* privacy action frame
* @skb: the skb containing the frame, length will be checked
*/
static inline bool ieee80211_is_group_privacy_action(struct sk_buff *skb)
{
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
return false;
return _ieee80211_is_group_privacy_action((void *)skb->data);
}
/**
* ieee80211_tu_to_usec - convert time units (TU) to microseconds
* @tu: the TUs

View file

@ -330,6 +330,9 @@ struct ieee80211_supported_band {
* in a separate chapter.
*/
#define VHT_MUMIMO_GROUPS_DATA_LEN (WLAN_MEMBERSHIP_LEN +\
WLAN_USER_POSITION_LEN)
/**
* struct vif_params - describes virtual interface parameters
* @use_4addr: use 4-address frames
@ -339,10 +342,13 @@ struct ieee80211_supported_band {
* This feature is only fully supported by drivers that enable the
* %NL80211_FEATURE_MAC_ON_CREATE flag. Others may support creating
** only p2p devices with specified MAC.
* @vht_mumimo_groups: MU-MIMO groupID. used for monitoring only
* packets belonging to that MU-MIMO groupID.
*/
struct vif_params {
int use_4addr;
u8 macaddr[ETH_ALEN];
int use_4addr;
u8 macaddr[ETH_ALEN];
u8 vht_mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN];
};
/**
@ -774,6 +780,7 @@ enum station_parameters_apply_mask {
* (bitmask of BIT(NL80211_STA_FLAG_...))
* @listen_interval: listen interval or -1 for no change
* @aid: AID or zero for no change
* @peer_aid: mesh peer AID or zero for no change
* @plink_action: plink action to take
* @plink_state: set the peer link state for a station
* @ht_capa: HT capabilities of station
@ -805,6 +812,7 @@ struct station_parameters {
u32 sta_modify_mask;
int listen_interval;
u16 aid;
u16 peer_aid;
u8 supported_rates_len;
u8 plink_action;
u8 plink_state;
@ -1417,6 +1425,21 @@ struct cfg80211_ssid {
u8 ssid_len;
};
/**
* struct cfg80211_scan_info - information about completed scan
* @scan_start_tsf: scan start time in terms of the TSF of the BSS that the
* wireless device that requested the scan is connected to. If this
* information is not available, this field is left zero.
* @tsf_bssid: the BSSID according to which %scan_start_tsf is set.
* @aborted: set to true if the scan was aborted for any reason,
* userspace will be notified of that
*/
struct cfg80211_scan_info {
u64 scan_start_tsf;
u8 tsf_bssid[ETH_ALEN] __aligned(2);
bool aborted;
};
/**
* struct cfg80211_scan_request - scan request description
*
@ -1427,12 +1450,17 @@ struct cfg80211_ssid {
* @scan_width: channel width for scanning
* @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets
* @duration: how long to listen on each channel, in TUs. If
* %duration_mandatory is not set, this is the maximum dwell time and
* the actual dwell time may be shorter.
* @duration_mandatory: if set, the scan duration must be as specified by the
* %duration field.
* @flags: bit field of flags controlling operation
* @rates: bitmap of rates to advertise for each band
* @wiphy: the wiphy this was for
* @scan_start: time (in jiffies) when the scan started
* @wdev: the wireless device to scan for
* @aborted: (internal) scan request was notified as aborted
* @info: (internal) information about completed scan
* @notified: (internal) scan request was notified as done or aborted
* @no_cck: used to send probe requests at non CCK rate in 2GHz band
* @mac_addr: MAC address used with randomisation
@ -1448,6 +1476,8 @@ struct cfg80211_scan_request {
enum nl80211_bss_scan_width scan_width;
const u8 *ie;
size_t ie_len;
u16 duration;
bool duration_mandatory;
u32 flags;
u32 rates[NUM_NL80211_BANDS];
@ -1461,7 +1491,8 @@ struct cfg80211_scan_request {
/* internal */
struct wiphy *wiphy;
unsigned long scan_start;
bool aborted, notified;
struct cfg80211_scan_info info;
bool notified;
bool no_cck;
/* keep last */
@ -1594,12 +1625,19 @@ enum cfg80211_signal_type {
* buffered on the device) and be accurate to about 10ms.
* If the frame isn't buffered, just passing the return value of
* ktime_get_boot_ns() is likely appropriate.
* @parent_tsf: the time at the start of reception of the first octet of the
* timestamp field of the frame. The time is the TSF of the BSS specified
* by %parent_bssid.
* @parent_bssid: the BSS according to which %parent_tsf is set. This is set to
* the BSS that requested the scan in which the beacon/probe was received.
*/
struct cfg80211_inform_bss {
struct ieee80211_channel *chan;
enum nl80211_bss_scan_width scan_width;
s32 signal;
u64 boottime_ns;
u64 parent_tsf;
u8 parent_bssid[ETH_ALEN] __aligned(2);
};
/**
@ -4061,10 +4099,10 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator);
* cfg80211_scan_done - notify that scan finished
*
* @request: the corresponding scan request
* @aborted: set to true if the scan was aborted for any reason,
* userspace will be notified of that
* @info: information about the completed scan
*/
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
void cfg80211_scan_done(struct cfg80211_scan_request *request,
struct cfg80211_scan_info *info);
/**
* cfg80211_sched_scan_results - notify that new scan results are available

View file

@ -4697,9 +4697,10 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
* any context, including hardirq context.
*
* @hw: the hardware that finished the scan
* @aborted: set to true if scan was aborted
* @info: information about the completed scan
*/
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
void ieee80211_scan_completed(struct ieee80211_hw *hw,
struct cfg80211_scan_info *info);
/**
* ieee80211_sched_scan_results - got results from scheduled scan

View file

@ -1829,6 +1829,44 @@ enum nl80211_commands {
* %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
* interface type.
*
* @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO
* groupID for monitor mode.
* The first 8 bytes are a mask that defines the membership in each
* group (there are 64 groups, group 0 and 63 are reserved),
* each bit represents a group and set to 1 for being a member in
* that group and 0 for not being a member.
* The remaining 16 bytes define the position in each group: 2 bits for
* each group.
* (smaller group numbers represented on most significant bits and bigger
* group numbers on least significant bits.)
* This attribute is used only if all interfaces are in monitor mode.
* Set this attribute in order to monitor packets using the given MU-MIMO
* groupID data.
* to turn off that feature set all the bits of the groupID to zero.
* @NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR: mac address for the sniffer to follow
* when using MU-MIMO air sniffer.
* to turn that feature off set an invalid mac address
* (e.g. FF:FF:FF:FF:FF:FF)
*
* @NL80211_ATTR_SCAN_START_TIME_TSF: The time at which the scan was actually
* started (u64). The time is the TSF of the BSS the interface that
* requested the scan is connected to (if available, otherwise this
* attribute must not be included).
* @NL80211_ATTR_SCAN_START_TIME_TSF_BSSID: The BSS according to which
* %NL80211_ATTR_SCAN_START_TIME_TSF is set.
* @NL80211_ATTR_MEASUREMENT_DURATION: measurement duration in TUs (u16). If
* %NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY is not set, this is the
* maximum measurement duration allowed. This attribute is used with
* measurement requests. It can also be used with %NL80211_CMD_TRIGGER_SCAN
* if the scan is used for beacon report radio measurement.
* @NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY: flag attribute that indicates
* that the duration specified with %NL80211_ATTR_MEASUREMENT_DURATION is
* mandatory. If this flag is not set, the duration is the maximum duration
* and the actual measurement duration may be shorter.
*
* @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is
* used to pull the stored data for mesh peer in power save state.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -2213,6 +2251,16 @@ enum nl80211_attrs {
NL80211_ATTR_IFTYPE_EXT_CAPA,
NL80211_ATTR_MU_MIMO_GROUP_DATA,
NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR,
NL80211_ATTR_SCAN_START_TIME_TSF,
NL80211_ATTR_SCAN_START_TIME_TSF_BSSID,
NL80211_ATTR_MEASUREMENT_DURATION,
NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY,
NL80211_ATTR_MESH_PEER_AID,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -3474,6 +3522,12 @@ enum nl80211_bss_scan_width {
* was last updated by a received frame. The value is expected to be
* accurate to about 10ms. (u64, nanoseconds)
* @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment
* @NL80211_BSS_PARENT_TSF: the time at the start of reception of the first
* octet of the timestamp field of the last beacon/probe received for
* this BSS. The time is the TSF of the BSS specified by
* @NL80211_BSS_PARENT_BSSID. (u64).
* @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
* is set.
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@ -3495,6 +3549,8 @@ enum nl80211_bss {
NL80211_BSS_PRESP_DATA,
NL80211_BSS_LAST_SEEN_BOOTTIME,
NL80211_BSS_PAD,
NL80211_BSS_PARENT_TSF,
NL80211_BSS_PARENT_BSSID,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@ -4479,6 +4535,22 @@ enum nl80211_feature_flags {
* %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
* the ASSOC_REQ_USE_RRM flag in the association request even if
* NL80211_FEATURE_QUIET is not advertized.
* @NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER: This device supports MU-MIMO air
* sniffer which means that it can be configured to hear packets from
* certain groups which can be configured by the
* %NL80211_ATTR_MU_MIMO_GROUP_DATA attribute,
* or can be configured to follow a station by configuring the
* %NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR attribute.
* @NL80211_EXT_FEATURE_SCAN_START_TIME: This driver includes the actual
* time the scan started in scan results event. The time is the TSF of
* the BSS that the interface that requested the scan is connected to
* (if available).
* @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the
* time the last beacon/probe was received. The time is the TSF of the
* BSS that the interface that requested the scan is connected to
* (if available).
* @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of
* channel dwell time.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@ -4486,6 +4558,10 @@ enum nl80211_feature_flags {
enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_VHT_IBSS,
NL80211_EXT_FEATURE_RRM,
NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER,
NL80211_EXT_FEATURE_SCAN_START_TIME,
NL80211_EXT_FEATURE_BSS_PARENT_TSF,
NL80211_EXT_FEATURE_SET_SCAN_DWELL,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,

View file

@ -306,6 +306,24 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
mutex_lock(&sta->ampdu_mlme.mtx);
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
tid_agg_rx = rcu_dereference_protected(
sta->ampdu_mlme.tid_rx[tid],
lockdep_is_held(&sta->ampdu_mlme.mtx));
if (tid_agg_rx->dialog_token == dialog_token) {
ht_dbg_ratelimited(sta->sdata,
"updated AddBA Req from %pM on tid %u\n",
sta->sta.addr, tid);
/* We have no API to update the timeout value in the
* driver so reject the timeout update.
*/
status = WLAN_STATUS_REQUEST_DECLINED;
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr,
tid, dialog_token, status,
1, buf_size, timeout);
goto end;
}
ht_dbg_ratelimited(sta->sdata,
"unexpected AddBA Req from %pM on tid %u\n",
sta->sta.addr, tid);

View file

@ -997,6 +997,7 @@ static void sta_apply_mesh_params(struct ieee80211_local *local,
if (sta->mesh->plink_state != NL80211_PLINK_ESTAB)
changed = mesh_plink_inc_estab_count(sdata);
sta->mesh->plink_state = params->plink_state;
sta->mesh->aid = params->peer_aid;
ieee80211_mps_sta_status_update(sta);
changed |= ieee80211_mps_set_sta_local_pm(sta,

View file

@ -1250,6 +1250,7 @@ struct ieee80211_local {
int scan_channel_idx;
int scan_ies_len;
int hw_scan_ies_bufsize;
struct cfg80211_scan_info scan_info;
struct work_struct sched_scan_stopped_work;
struct ieee80211_sub_if_data __rcu *sched_scan_sdata;

View file

@ -148,25 +148,7 @@ u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
void mesh_sta_cleanup(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
u32 changed = 0;
/*
* maybe userspace handles peer allocation and peering, but in either
* case the beacon is still generated by the kernel and we might need
* an update.
*/
if (sdata->u.mesh.user_mpm &&
sta->mesh->plink_state == NL80211_PLINK_ESTAB)
changed |= mesh_plink_dec_estab_count(sdata);
changed |= mesh_accept_plinks_update(sdata);
if (!sdata->u.mesh.user_mpm) {
changed |= mesh_plink_deactivate(sta);
del_timer_sync(&sta->mesh->plink_timer);
}
/* make sure no readers can access nexthop sta from here on */
mesh_path_flush_by_nexthop(sta);
synchronize_net();
u32 changed = mesh_plink_deactivate(sta);
if (changed)
ieee80211_mbss_info_change_notify(sdata, changed);

View file

@ -370,13 +370,21 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
spin_lock_bh(&sta->mesh->plink_lock);
changed = __mesh_plink_deactivate(sta);
sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED;
mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_CLOSE,
sta->sta.addr, sta->mesh->llid, sta->mesh->plid,
sta->mesh->reason);
if (!sdata->u.mesh.user_mpm) {
sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED;
mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_CLOSE,
sta->sta.addr, sta->mesh->llid,
sta->mesh->plid, sta->mesh->reason);
}
spin_unlock_bh(&sta->mesh->plink_lock);
if (!sdata->u.mesh.user_mpm)
del_timer_sync(&sta->mesh->plink_timer);
mesh_path_flush_by_nexthop(sta);
/* make sure no readers can access nexthop sta from here on */
synchronize_net();
return changed;
}

View file

@ -1624,8 +1624,13 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (mmie_keyidx < NUM_DEFAULT_KEYS ||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
if (rx->sta)
if (rx->sta) {
if (ieee80211_is_group_privacy_action(skb) &&
test_sta_flag(rx->sta, WLAN_STA_MFP))
return RX_DROP_MONITOR;
rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]);
}
if (!rx->key)
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
} else if (!ieee80211_has_protected(fc)) {

View file

@ -7,6 +7,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2013-2015 Intel Mobile Communications GmbH
* Copyright 2016 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
@ -70,6 +71,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
.boottime_ns = rx_status->boottime_ns,
};
bool signal_valid;
struct ieee80211_sub_if_data *scan_sdata;
if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
bss_meta.signal = rx_status->signal * 100;
@ -83,6 +85,20 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
bss_meta.chan = channel;
rcu_read_lock();
scan_sdata = rcu_dereference(local->scan_sdata);
if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION &&
scan_sdata->vif.bss_conf.assoc &&
ieee80211_have_rx_timestamp(rx_status)) {
bss_meta.parent_tsf =
ieee80211_calculate_rx_timestamp(local, rx_status,
len + FCS_LEN, 24);
ether_addr_copy(bss_meta.parent_bssid,
scan_sdata->vif.bss_conf.bssid);
}
rcu_read_unlock();
cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
mgmt, len, GFP_ATOMIC);
if (!cbss)
@ -345,6 +361,12 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (rc == 0)
return;
/* HW scan failed and is going to be reported as aborted,
* so clear old scan info.
*/
memset(&local->scan_info, 0, sizeof(local->scan_info));
aborted = true;
}
kfree(local->hw_scan_req);
@ -353,8 +375,10 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
scan_req = rcu_dereference_protected(local->scan_req,
lockdep_is_held(&local->mtx));
if (scan_req != local->int_scan_req)
cfg80211_scan_done(scan_req, aborted);
if (scan_req != local->int_scan_req) {
local->scan_info.aborted = aborted;
cfg80211_scan_done(scan_req, &local->scan_info);
}
RCU_INIT_POINTER(local->scan_req, NULL);
scan_sdata = rcu_dereference_protected(local->scan_sdata,
@ -391,15 +415,19 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
ieee80211_start_next_roc(local);
}
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
void ieee80211_scan_completed(struct ieee80211_hw *hw,
struct cfg80211_scan_info *info)
{
struct ieee80211_local *local = hw_to_local(hw);
trace_api_scan_completed(local, aborted);
trace_api_scan_completed(local, info);
set_bit(SCAN_COMPLETED, &local->scanning);
if (aborted)
if (info->aborted)
set_bit(SCAN_ABORTED, &local->scanning);
memcpy(&local->scan_info, info, sizeof(*info));
ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
}
EXPORT_SYMBOL(ieee80211_scan_completed);
@ -566,6 +594,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
local->hw_scan_req->req.ie = ies;
local->hw_scan_req->req.flags = req->flags;
eth_broadcast_addr(local->hw_scan_req->req.bssid);
local->hw_scan_req->req.duration = req->duration;
local->hw_scan_req->req.duration_mandatory =
req->duration_mandatory;
local->hw_scan_band = 0;
@ -1073,6 +1104,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
*/
cancel_delayed_work(&local->scan_work);
/* and clean up */
memset(&local->scan_info, 0, sizeof(local->scan_info));
__ieee80211_scan_completed(&local->hw, true);
out:
mutex_unlock(&local->mtx);

View file

@ -129,42 +129,31 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
}
if (wide_bw_chansw_ie) {
new_vht_chandef.chan = new_chan;
new_vht_chandef.center_freq1 =
ieee80211_channel_to_frequency(
struct ieee80211_vht_operation vht_oper = {
.chan_width =
wide_bw_chansw_ie->new_channel_width,
.center_freq_seg1_idx =
wide_bw_chansw_ie->new_center_freq_seg0,
new_band);
.center_freq_seg2_idx =
wide_bw_chansw_ie->new_center_freq_seg1,
/* .basic_mcs_set doesn't matter */
};
switch (wide_bw_chansw_ie->new_channel_width) {
default:
/* hmmm, ignore VHT and use HT if present */
case IEEE80211_VHT_CHANWIDTH_USE_HT:
/* default, for the case of IEEE80211_VHT_CHANWIDTH_USE_HT,
* to the previously parsed chandef
*/
new_vht_chandef = csa_ie->chandef;
/* ignore if parsing fails */
if (!ieee80211_chandef_vht_oper(&vht_oper, &new_vht_chandef))
new_vht_chandef.chan = NULL;
break;
case IEEE80211_VHT_CHANWIDTH_80MHZ:
new_vht_chandef.width = NL80211_CHAN_WIDTH_80;
break;
case IEEE80211_VHT_CHANWIDTH_160MHZ:
new_vht_chandef.width = NL80211_CHAN_WIDTH_160;
break;
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
/* field is otherwise reserved */
new_vht_chandef.center_freq2 =
ieee80211_channel_to_frequency(
wide_bw_chansw_ie->new_center_freq_seg1,
new_band);
new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
break;
}
if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
ieee80211_chandef_downgrade(&new_vht_chandef);
if (sta_flags & IEEE80211_STA_DISABLE_160MHZ &&
new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
ieee80211_chandef_downgrade(&new_vht_chandef);
if (sta_flags & IEEE80211_STA_DISABLE_40MHZ &&
new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
ieee80211_chandef_downgrade(&new_vht_chandef);
}
/* if VHT data is there validate & use it */

View file

@ -1747,6 +1747,7 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata,
goto out;
}
ret = 0;
call_drv:
drv_tdls_recv_channel_switch(sdata->local, sdata, &params);

View file

@ -593,6 +593,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
else if (tx->sta &&
(key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
tx->key = key;
else if (ieee80211_is_group_privacy_action(tx->skb) &&
(key = rcu_dereference(tx->sdata->default_multicast_key)))
tx->key = key;
else if (ieee80211_is_mgmt(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1) &&
ieee80211_is_robust_mgmt_frame(tx->skb) &&
@ -625,7 +628,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
case WLAN_CIPHER_SUITE_GCMP_256:
if (!ieee80211_is_data_present(hdr->frame_control) &&
!ieee80211_use_mfp(hdr->frame_control, tx->sta,
tx->skb))
tx->skb) &&
!ieee80211_is_group_privacy_action(tx->skb))
tx->key = NULL;
else
skip_hw = (tx->key->conf.flags &
@ -1445,7 +1449,9 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local)
local->cvars = kcalloc(fq->flows_cnt, sizeof(local->cvars[0]),
GFP_KERNEL);
if (!local->cvars) {
spin_lock_bh(&fq->lock);
fq_reset(fq, fq_skb_free_func);
spin_unlock_bh(&fq->lock);
return -ENOMEM;
}
@ -1465,7 +1471,9 @@ void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
kfree(local->cvars);
local->cvars = NULL;
spin_lock_bh(&fq->lock);
fq_reset(fq, fq_skb_free_func);
spin_unlock_bh(&fq->lock);
}
struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,

View file

@ -220,7 +220,7 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
if (WARN_ON(!rdev->scan_req->notified))
rdev->scan_req->aborted = true;
rdev->scan_req->info.aborted = true;
___cfg80211_scan_done(rdev, false);
}
}
@ -1087,7 +1087,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
if (WARN_ON(!rdev->scan_req->notified))
rdev->scan_req->aborted = true;
rdev->scan_req->info.aborted = true;
___cfg80211_scan_done(rdev, false);
}

View file

@ -141,6 +141,18 @@ struct cfg80211_internal_bss {
unsigned long refcount;
atomic_t hold;
/* time at the start of the reception of the first octet of the
* timestamp field of the last beacon/probe received for this BSS.
* The time is the TSF of the BSS specified by %parent_bssid.
*/
u64 parent_tsf;
/* the BSS according to which %parent_tsf is set. This is set to
* the BSS that the interface that requested the scan was connected to
* when the beacon/probe was received.
*/
u8 parent_bssid[ETH_ALEN] __aligned(2);
/* must be last because of priv member */
struct cfg80211_bss pub;
};

View file

@ -405,6 +405,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
[NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_SUPPORT_P2P_PS] = { .type = NLA_U8 },
[NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
.len = VHT_MUMIMO_GROUPS_DATA_LEN
},
[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN },
};
/* policy for the key attributes */
@ -2695,6 +2699,38 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
change = true;
}
if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
const u8 *mumimo_groups;
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
return -EOPNOTSUPP;
mumimo_groups =
nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
/* bits 0 and 63 are reserved and must be zero */
if ((mumimo_groups[0] & BIT(7)) ||
(mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
return -EINVAL;
memcpy(params.vht_mumimo_groups, mumimo_groups,
VHT_MUMIMO_GROUPS_DATA_LEN);
change = true;
}
if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
return -EOPNOTSUPP;
nla_memcpy(params.macaddr,
info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR],
ETH_ALEN);
change = true;
}
if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
return -EOPNOTSUPP;
@ -4410,6 +4446,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
if (params.plink_state >= NUM_NL80211_PLINK_STATES)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) {
params.peer_aid = nla_get_u16(
info->attrs[NL80211_ATTR_MESH_PEER_AID]);
if (params.peer_aid > IEEE80211_MAX_AID)
return -EINVAL;
}
params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
}
@ -5287,6 +5329,51 @@ static const struct nla_policy
[NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
};
static int nl80211_check_bool(const struct nlattr *nla, u8 min, u8 max, bool *out)
{
u8 val = nla_get_u8(nla);
if (val < min || val > max)
return -EINVAL;
*out = val;
return 0;
}
static int nl80211_check_u8(const struct nlattr *nla, u8 min, u8 max, u8 *out)
{
u8 val = nla_get_u8(nla);
if (val < min || val > max)
return -EINVAL;
*out = val;
return 0;
}
static int nl80211_check_u16(const struct nlattr *nla, u16 min, u16 max, u16 *out)
{
u16 val = nla_get_u16(nla);
if (val < min || val > max)
return -EINVAL;
*out = val;
return 0;
}
static int nl80211_check_u32(const struct nlattr *nla, u32 min, u32 max, u32 *out)
{
u32 val = nla_get_u32(nla);
if (val < min || val > max)
return -EINVAL;
*out = val;
return 0;
}
static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *out)
{
s32 val = nla_get_s32(nla);
if (val < min || val > max)
return -EINVAL;
*out = val;
return 0;
}
static int nl80211_parse_mesh_config(struct genl_info *info,
struct mesh_config *cfg,
u32 *mask_out)
@ -5297,9 +5384,8 @@ static int nl80211_parse_mesh_config(struct genl_info *info,
#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
do { \
if (tb[attr]) { \
if (fn(tb[attr]) < min || fn(tb[attr]) > max) \
if (fn(tb[attr], min, max, &cfg->param)) \
return -EINVAL; \
cfg->param = fn(tb[attr]); \
mask |= (1 << (attr - 1)); \
} \
} while (0)
@ -5318,99 +5404,99 @@ do { \
/* Fill in the params struct */
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
mask, NL80211_MESHCONF_RETRY_TIMEOUT,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
mask, NL80211_MESHCONF_MAX_PEER_LINKS,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
mask, NL80211_MESHCONF_MAX_RETRIES,
nla_get_u8);
nl80211_check_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
mask, NL80211_MESHCONF_TTL, nla_get_u8);
mask, NL80211_MESHCONF_TTL, nl80211_check_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
mask, NL80211_MESHCONF_ELEMENT_TTL,
nla_get_u8);
nl80211_check_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
nla_get_u8);
nl80211_check_bool);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
1, 255, mask,
NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
nla_get_u32);
nl80211_check_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
nla_get_u8);
nl80211_check_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
nla_get_u32);
nl80211_check_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
1, 65535, mask,
NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
nla_get_u32);
nl80211_check_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
1, 65535, mask,
NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
1, 65535, mask,
NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
dot11MeshHWMPnetDiameterTraversalTime,
1, 65535, mask,
NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
mask, NL80211_MESHCONF_HWMP_ROOTMODE,
nla_get_u8);
nl80211_check_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
dot11MeshGateAnnouncementProtocol, 0, 1,
mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
nla_get_u8);
nl80211_check_bool);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
mask, NL80211_MESHCONF_FORWARDING,
nla_get_u8);
nl80211_check_bool);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
mask, NL80211_MESHCONF_RSSI_THRESHOLD,
nla_get_s32);
nl80211_check_s32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
mask, NL80211_MESHCONF_HT_OPMODE,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
1, 65535, mask,
NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
nla_get_u32);
nl80211_check_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
dot11MeshHWMPconfirmationInterval,
1, 65535, mask,
NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
nla_get_u16);
nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
NL80211_MESH_POWER_ACTIVE,
NL80211_MESH_POWER_MAX,
mask, NL80211_MESHCONF_POWER_MODE,
nla_get_u32);
nl80211_check_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
0, 65535, mask,
NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
mask, NL80211_MESHCONF_PLINK_TIMEOUT,
nla_get_u32);
nl80211_check_u32);
if (mask_out)
*mask_out = mask;
@ -6143,6 +6229,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
}
if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
if (!wiphy_ext_feature_isset(wiphy,
NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
err = -EOPNOTSUPP;
goto out_free;
}
request->duration =
nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
request->duration_mandatory =
nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
}
if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
request->flags = nla_get_u32(
info->attrs[NL80211_ATTR_SCAN_FLAGS]);
@ -6976,6 +7075,13 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
jiffies_to_msecs(jiffies - intbss->ts)))
goto nla_put_failure;
if (intbss->parent_tsf &&
(nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
intbss->parent_tsf, NL80211_BSS_PAD) ||
nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
intbss->parent_bssid)))
goto nla_put_failure;
if (intbss->ts_boottime &&
nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
intbss->ts_boottime, NL80211_BSS_PAD))
@ -11749,6 +11855,13 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
goto nla_put_failure;
if (req->info.scan_start_tsf &&
(nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
req->info.scan_start_tsf, NL80211_BSS_PAD) ||
nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
req->info.tsf_bssid)))
goto nla_put_failure;
return 0;
nla_put_failure:
return -ENOBUFS;

View file

@ -3,6 +3,7 @@
*
* Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2016 Intel Deutschland GmbH
*/
#include <linux/kernel.h>
#include <linux/slab.h>
@ -194,7 +195,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
if (wdev->netdev)
cfg80211_sme_scan_done(wdev->netdev);
if (!request->aborted &&
if (!request->info.aborted &&
request->flags & NL80211_SCAN_FLAG_FLUSH) {
/* flush entries from previous scans */
spin_lock_bh(&rdev->bss_lock);
@ -202,10 +203,10 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
spin_unlock_bh(&rdev->bss_lock);
}
msg = nl80211_build_scan_msg(rdev, wdev, request->aborted);
msg = nl80211_build_scan_msg(rdev, wdev, request->info.aborted);
#ifdef CONFIG_CFG80211_WEXT
if (wdev->netdev && !request->aborted) {
if (wdev->netdev && !request->info.aborted) {
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL);
@ -236,12 +237,13 @@ void __cfg80211_scan_done(struct work_struct *wk)
rtnl_unlock();
}
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
void cfg80211_scan_done(struct cfg80211_scan_request *request,
struct cfg80211_scan_info *info)
{
trace_cfg80211_scan_done(request, aborted);
trace_cfg80211_scan_done(request, info);
WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req);
request->aborted = aborted;
request->info = *info;
request->notified = true;
queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);
}
@ -843,6 +845,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
found->pub.capability = tmp->pub.capability;
found->ts = tmp->ts;
found->ts_boottime = tmp->ts_boottime;
found->parent_tsf = tmp->parent_tsf;
ether_addr_copy(found->parent_bssid, tmp->parent_bssid);
} else {
struct cfg80211_internal_bss *new;
struct cfg80211_internal_bss *hidden;
@ -1086,6 +1090,8 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
tmp.ts_boottime = data->boottime_ns;
tmp.parent_tsf = data->parent_tsf;
ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
wiphy->max_adj_channel_rssi_comp;

View file

@ -2642,8 +2642,9 @@ TRACE_EVENT(cfg80211_tdls_oper_request,
);
TRACE_EVENT(cfg80211_scan_done,
TP_PROTO(struct cfg80211_scan_request *request, bool aborted),
TP_ARGS(request, aborted),
TP_PROTO(struct cfg80211_scan_request *request,
struct cfg80211_scan_info *info),
TP_ARGS(request, info),
TP_STRUCT__entry(
__field(u32, n_channels)
__dynamic_array(u8, ie, request ? request->ie_len : 0)
@ -2652,6 +2653,8 @@ TRACE_EVENT(cfg80211_scan_done,
MAC_ENTRY(wiphy_mac)
__field(bool, no_cck)
__field(bool, aborted)
__field(u64, scan_start_tsf)
MAC_ENTRY(tsf_bssid)
),
TP_fast_assign(
if (request) {
@ -2666,9 +2669,16 @@ TRACE_EVENT(cfg80211_scan_done,
request->wiphy->perm_addr);
__entry->no_cck = request->no_cck;
}
__entry->aborted = aborted;
if (info) {
__entry->aborted = info->aborted;
__entry->scan_start_tsf = info->scan_start_tsf;
MAC_ASSIGN(tsf_bssid, info->tsf_bssid);
}
),
TP_printk("aborted: %s", BOOL_TO_STR(__entry->aborted))
TP_printk("aborted: %s, scan start (TSF): %llu, tsf_bssid: " MAC_PR_FMT,
BOOL_TO_STR(__entry->aborted),
(unsigned long long)__entry->scan_start_tsf,
MAC_PR_ARG(tsf_bssid))
);
DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_results,
@ -2721,6 +2731,8 @@ TRACE_EVENT(cfg80211_inform_bss_frame,
__dynamic_array(u8, mgmt, len)
__field(s32, signal)
__field(u64, ts_boottime)
__field(u64, parent_tsf)
MAC_ENTRY(parent_bssid)
),
TP_fast_assign(
WIPHY_ASSIGN;
@ -2730,10 +2742,15 @@ TRACE_EVENT(cfg80211_inform_bss_frame,
memcpy(__get_dynamic_array(mgmt), mgmt, len);
__entry->signal = data->signal;
__entry->ts_boottime = data->boottime_ns;
__entry->parent_tsf = data->parent_tsf;
MAC_ASSIGN(parent_bssid, data->parent_bssid);
),
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "(scan_width: %d) signal: %d, tsb:%llu",
WIPHY_PR_ARG, CHAN_PR_ARG, __entry->scan_width,
__entry->signal, (unsigned long long)__entry->ts_boottime)
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT
"(scan_width: %d) signal: %d, tsb:%llu, detect_tsf:%llu, tsf_bssid: "
MAC_PR_FMT, WIPHY_PR_ARG, CHAN_PR_ARG, __entry->scan_width,
__entry->signal, (unsigned long long)__entry->ts_boottime,
(unsigned long long)__entry->parent_tsf,
MAC_PR_ARG(parent_bssid))
);
DECLARE_EVENT_CLASS(cfg80211_bss_evt,