Commit 42bd20d9 authored by Aviya Erenfeld's avatar Aviya Erenfeld Committed by Johannes Berg

mac80211: add support for MU-MIMO air sniffer

add support to MU-MIMO air sniffer according groupID:
in monitor mode, use a given MU-MIMO groupID to monitor stations
that belongs to that group using MU-MIMO.

add support for following a station according to its MAC address
using VHT MU-MIMO sniffer:
the monitors wait until they get an action MU-MIMO notification
frame, then parses it in order to find the groupID that corresponds
to the given MAC address and monitors packets destined to that
groupID using VHT MU-MIMO.
Signed-off-by: default avatarAviya Erenfeld <aviya.erenfeld@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 480dd46b
...@@ -73,8 +73,29 @@ static int ieee80211_change_iface(struct wiphy *wiphy, ...@@ -73,8 +73,29 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
sdata->u.mgd.use_4addr = params->use_4addr; sdata->u.mgd.use_4addr = params->use_4addr;
} }
if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) { if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *monitor_sdata;
u32 mu_mntr_cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
monitor_sdata = rtnl_dereference(local->monitor_sdata);
if (monitor_sdata &&
wiphy_ext_feature_isset(wiphy, mu_mntr_cap_flag)) {
memcpy(monitor_sdata->vif.bss_conf.mu_group.membership,
params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN);
memcpy(monitor_sdata->vif.bss_conf.mu_group.position,
params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
WLAN_USER_POSITION_LEN);
monitor_sdata->vif.mu_mimo_owner = true;
ieee80211_bss_info_change_notify(monitor_sdata,
BSS_CHANGED_MU_GROUPS);
ether_addr_copy(monitor_sdata->u.mntr.mu_follow_addr,
params->macaddr);
}
if (!flags)
return 0;
if (ieee80211_sdata_running(sdata)) { if (ieee80211_sdata_running(sdata)) {
u32 mask = MONITOR_FLAG_COOK_FRAMES | u32 mask = MONITOR_FLAG_COOK_FRAMES |
......
...@@ -162,7 +162,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, ...@@ -162,7 +162,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
return; return;
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
sdata->vif.type == NL80211_IFTYPE_MONITOR)) (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!sdata->vif.mu_mimo_owner)))
return; return;
if (!check_sdata_in_driver(sdata)) if (!check_sdata_in_driver(sdata))
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* Copyright 2005, Devicescape Software, Inc. * Copyright 2005, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2015 Intel Mobile Communications GmbH
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -826,6 +826,7 @@ struct txq_info { ...@@ -826,6 +826,7 @@ struct txq_info {
struct ieee80211_if_mntr { struct ieee80211_if_mntr {
u32 flags; u32 flags;
u8 mu_follow_addr[ETH_ALEN] __aligned(2);
}; };
struct ieee80211_sub_if_data { struct ieee80211_sub_if_data {
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
* by either the RTNL, the iflist_mtx or RCU. * by either the RTNL, the iflist_mtx or RCU.
*/ */
static void ieee80211_iface_work(struct work_struct *work);
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
...@@ -448,6 +450,9 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) ...@@ -448,6 +450,9 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
return ret; return ret;
} }
skb_queue_head_init(&sdata->skb_queue);
INIT_WORK(&sdata->work, ieee80211_iface_work);
return 0; return 0;
} }
......
...@@ -485,6 +485,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, ...@@ -485,6 +485,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
struct net_device *prev_dev = NULL; struct net_device *prev_dev = NULL;
int present_fcs_len = 0; int present_fcs_len = 0;
unsigned int rtap_vendor_space = 0; unsigned int rtap_vendor_space = 0;
struct ieee80211_mgmt *mgmt;
struct ieee80211_sub_if_data *monitor_sdata =
rcu_dereference(local->monitor_sdata);
if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) {
struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data;
...@@ -585,6 +588,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, ...@@ -585,6 +588,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
ieee80211_rx_stats(sdata->dev, skb->len); ieee80211_rx_stats(sdata->dev, skb->len);
} }
mgmt = (void *)skb->data;
if (monitor_sdata &&
skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + VHT_MUMIMO_GROUPS_DATA_LEN &&
ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_VHT &&
mgmt->u.action.u.vht_group_notif.action_code == WLAN_VHT_ACTION_GROUPID_MGMT &&
is_valid_ether_addr(monitor_sdata->u.mntr.mu_follow_addr) &&
ether_addr_equal(mgmt->da, monitor_sdata->u.mntr.mu_follow_addr)) {
struct sk_buff *mu_skb = skb_copy(skb, GFP_ATOMIC);
if (mu_skb) {
mu_skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
skb_queue_tail(&monitor_sdata->skb_queue, mu_skb);
ieee80211_queue_work(&local->hw, &monitor_sdata->work);
}
}
if (prev_dev) { if (prev_dev) {
skb->dev = prev_dev; skb->dev = prev_dev;
netif_receive_skb(skb); netif_receive_skb(skb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment