Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Aviya Erenfeld <aviya.erenfeld@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Aviya Erenfeld and committed by
Johannes Berg
42bd20d9 480dd46b

+51 -3
+22 -1
net/mac80211/cfg.c
··· 73 73 sdata->u.mgd.use_4addr = params->use_4addr; 74 74 } 75 75 76 - if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) { 76 + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { 77 77 struct ieee80211_local *local = sdata->local; 78 + struct ieee80211_sub_if_data *monitor_sdata; 79 + u32 mu_mntr_cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER; 80 + 81 + monitor_sdata = rtnl_dereference(local->monitor_sdata); 82 + if (monitor_sdata && 83 + wiphy_ext_feature_isset(wiphy, mu_mntr_cap_flag)) { 84 + memcpy(monitor_sdata->vif.bss_conf.mu_group.membership, 85 + params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); 86 + memcpy(monitor_sdata->vif.bss_conf.mu_group.position, 87 + params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, 88 + WLAN_USER_POSITION_LEN); 89 + monitor_sdata->vif.mu_mimo_owner = true; 90 + ieee80211_bss_info_change_notify(monitor_sdata, 91 + BSS_CHANGED_MU_GROUPS); 92 + 93 + ether_addr_copy(monitor_sdata->u.mntr.mu_follow_addr, 94 + params->macaddr); 95 + } 96 + 97 + if (!flags) 98 + return 0; 78 99 79 100 if (ieee80211_sdata_running(sdata)) { 80 101 u32 mask = MONITOR_FLAG_COOK_FRAMES |
+2 -1
net/mac80211/driver-ops.h
··· 162 162 return; 163 163 164 164 if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || 165 - sdata->vif.type == NL80211_IFTYPE_MONITOR)) 165 + (sdata->vif.type == NL80211_IFTYPE_MONITOR && 166 + !sdata->vif.mu_mimo_owner))) 166 167 return; 167 168 168 169 if (!check_sdata_in_driver(sdata))
+2 -1
net/mac80211/ieee80211_i.h
··· 3 3 * Copyright 2005, Devicescape Software, Inc. 4 4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 5 5 * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> 6 - * Copyright 2013-2014 Intel Mobile Communications GmbH 6 + * Copyright 2013-2015 Intel Mobile Communications GmbH 7 7 * 8 8 * This program is free software; you can redistribute it and/or modify 9 9 * it under the terms of the GNU General Public License version 2 as ··· 826 826 827 827 struct ieee80211_if_mntr { 828 828 u32 flags; 829 + u8 mu_follow_addr[ETH_ALEN] __aligned(2); 829 830 }; 830 831 831 832 struct ieee80211_sub_if_data {
+5
net/mac80211/iface.c
··· 43 43 * by either the RTNL, the iflist_mtx or RCU. 44 44 */ 45 45 46 + static void ieee80211_iface_work(struct work_struct *work); 47 + 46 48 bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) 47 49 { 48 50 struct ieee80211_chanctx_conf *chanctx_conf; ··· 449 447 kfree(sdata); 450 448 return ret; 451 449 } 450 + 451 + skb_queue_head_init(&sdata->skb_queue); 452 + INIT_WORK(&sdata->work, ieee80211_iface_work); 452 453 453 454 return 0; 454 455 }
+20
net/mac80211/rx.c
··· 485 485 struct net_device *prev_dev = NULL; 486 486 int present_fcs_len = 0; 487 487 unsigned int rtap_vendor_space = 0; 488 + struct ieee80211_mgmt *mgmt; 489 + struct ieee80211_sub_if_data *monitor_sdata = 490 + rcu_dereference(local->monitor_sdata); 488 491 489 492 if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { 490 493 struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; ··· 586 583 587 584 prev_dev = sdata->dev; 588 585 ieee80211_rx_stats(sdata->dev, skb->len); 586 + } 587 + 588 + mgmt = (void *)skb->data; 589 + if (monitor_sdata && 590 + skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + VHT_MUMIMO_GROUPS_DATA_LEN && 591 + ieee80211_is_action(mgmt->frame_control) && 592 + mgmt->u.action.category == WLAN_CATEGORY_VHT && 593 + mgmt->u.action.u.vht_group_notif.action_code == WLAN_VHT_ACTION_GROUPID_MGMT && 594 + is_valid_ether_addr(monitor_sdata->u.mntr.mu_follow_addr) && 595 + ether_addr_equal(mgmt->da, monitor_sdata->u.mntr.mu_follow_addr)) { 596 + struct sk_buff *mu_skb = skb_copy(skb, GFP_ATOMIC); 597 + 598 + if (mu_skb) { 599 + mu_skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; 600 + skb_queue_tail(&monitor_sdata->skb_queue, mu_skb); 601 + ieee80211_queue_work(&local->hw, &monitor_sdata->work); 602 + } 589 603 } 590 604 591 605 if (prev_dev) {