From e057d3c31bdf87616b415c4b2cbf7310f54b9219 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 28 May 2013 13:01:52 +0200 Subject: [PATCH 1/7] cfg80211: support an active monitor interface flag An active monitor interface is one that is used for communication (via injection). It is expected to ACK incoming unicast packets. This is useful for running various 802.11 testing utilities that associate to an AP via injection and manage the state in user space. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ include/uapi/linux/nl80211.h | 4 ++++ net/wireless/nl80211.c | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b3b076a46d50..13b247d26544 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -961,6 +961,7 @@ struct station_info { * @MONITOR_FLAG_CONTROL: pass control frames * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering * @MONITOR_FLAG_COOK_FRAMES: report frames after processing + * @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address */ enum monitor_flags { MONITOR_FLAG_FCSFAIL = 1<wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR)) + return -EOPNOTSUPP; + if (change) err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); else @@ -2395,6 +2400,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); + + if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) && + !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR)) + return -EOPNOTSUPP; + wdev = rdev_add_virtual_intf(rdev, nla_data(info->attrs[NL80211_ATTR_IFNAME]), type, err ? NULL : &flags, ¶ms); From 31eba5bc56a9324f056d28569a4f89f39c1c3f70 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 28 May 2013 13:01:53 +0200 Subject: [PATCH 2/7] mac80211: support active monitor interfaces Support them only if the driver advertises support for them via IEEE80211_HW_SUPPORTS_ACTIVE_MONITOR. Unlike normal monitor interfaces, they are added to the driver, along with their MAC address. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 11 +++++++---- net/mac80211/driver-ops.h | 3 ++- net/mac80211/iface.c | 29 +++++++++++++++++++++++------ net/mac80211/util.c | 6 ++++++ 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 232edf78d5a9..9034da16cf1b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy, struct ieee80211_local *local = sdata->local; if (ieee80211_sdata_running(sdata)) { + u32 mask = MONITOR_FLAG_COOK_FRAMES | + MONITOR_FLAG_ACTIVE; + /* - * Prohibit MONITOR_FLAG_COOK_FRAMES to be - * changed while the interface is up. + * Prohibit MONITOR_FLAG_COOK_FRAMES and + * MONITOR_FLAG_ACTIVE to be changed while the + * interface is up. * Else we would need to add a lot of cruft * to update everything: * cooked_mntrs, monitor and all fif_* counters * reconfigure hardware */ - if ((*flags & MONITOR_FLAG_COOK_FRAMES) != - (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) + if ((*flags & mask) != (sdata->u.mntr_flags & mask)) return -EBUSY; ieee80211_adjust_monitor_flags(sdata, -1); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 169664c122e2..b931c96a596f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local, if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || (sdata->vif.type == NL80211_IFTYPE_MONITOR && - !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)))) + !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF) && + !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)))) return -EINVAL; trace_drv_add_interface(local, sdata); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ceef64426a8d..7cabaf261fed 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) +static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr, + bool check_dup) { struct ieee80211_sub_if_data *sdata; u64 new, mask, tmp; @@ -179,10 +180,13 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); + if (!check_dup) + return ret; mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) + if (sdata->vif.type == NL80211_IFTYPE_MONITOR && + !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) continue; m = sdata->vif.addr; @@ -204,12 +208,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sockaddr *sa = addr; + bool check_dup = true; int ret; if (ieee80211_sdata_running(sdata)) return -EBUSY; - ret = ieee80211_verify_mac(sdata->local, sa->sa_data); + if (sdata->vif.type == NL80211_IFTYPE_MONITOR && + !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) + check_dup = false; + + ret = ieee80211_verify_mac(sdata->local, sa->sa_data, check_dup); if (ret) return ret; @@ -541,7 +550,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) break; } - if (local->monitors == 0 && local->open_count == 0) { + if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) { + res = drv_add_interface(local, sdata); + if (res) + goto err_stop; + } else if (local->monitors == 0 && local->open_count == 0) { res = ieee80211_add_virtual_monitor(local); if (res) goto err_stop; @@ -919,7 +932,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->mtx); ieee80211_recalc_idle(local); mutex_unlock(&local->mtx); - break; + + if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) + break; + + /* fall through */ default: if (going_down) drv_remove_interface(local, sdata); @@ -1068,7 +1085,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = { .ndo_start_xmit = ieee80211_monitor_start_xmit, .ndo_set_rx_mode = ieee80211_set_multicast_list, .ndo_change_mtu = ieee80211_change_mtu, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = ieee80211_change_mac, .ndo_select_queue = ieee80211_monitor_select_queue, }; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 2a8d759324c2..89a83770d152 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces( list_for_each_entry(sdata, &local->interfaces, list) { switch (sdata->vif.type) { case NL80211_IFTYPE_MONITOR: + if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) + continue; + break; case NL80211_IFTYPE_AP_VLAN: continue; default: @@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic( list_for_each_entry_rcu(sdata, &local->interfaces, list) { switch (sdata->vif.type) { case NL80211_IFTYPE_MONITOR: + if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) + continue; + break; case NL80211_IFTYPE_AP_VLAN: continue; default: From bd5e14fb77d9d1dd15f9102759e8c8b31c667488 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 May 2013 09:08:05 +0200 Subject: [PATCH 3/7] cfg80211: remove cleanup_work kernel-doc I evidently forgot this when removing the work itself. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 13b247d26544..6dd19593e333 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2869,7 +2869,6 @@ struct cfg80211_cached_keys; * @mgmt_registrations_lock: lock for the list * @mtx: mutex used to lock data in this struct, may be used by drivers * and some API functions require it held - * @cleanup_work: work struct used for cleanup that can't be done directly * @beacon_interval: beacon interval used on this device for transmitting * beacons, 0 when not valid * @address: The address for this device, valid only if @netdev is %NULL From f4d57941bf89997bad3294f94987caebf2771a33 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 May 2013 17:24:15 +0200 Subject: [PATCH 4/7] mac80211: always send multicast on CAB queue If the driver advertised support for a CAB queue, then we should put all multicast frames there, otherwise sending them can be racy with clients going to sleep while we TX a frame. To avoid this, always TX multicast frames on the multicast queue. It seems like even drivers not using the queue framework might want to do this which would mean also moving the IEEE80211_TX_CTL_SEND_AFTER_DTIM flag assignment, but it also seems that drivers behave differently here so that just moving it wouldn't be a good idea. It'd be better to modify those drivers to use the queue framework. Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9972e07a2f96..34be9336b5d1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) if (ieee80211_has_order(hdr->frame_control)) return TX_CONTINUE; + if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) + info->hw_queue = tx->sdata->vif.cab_queue; + /* no stations in PS mode */ if (!atomic_read(&ps->num_sta_ps)) return TX_CONTINUE; info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; - if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) - info->hw_queue = tx->sdata->vif.cab_queue; /* device releases frame after DTIM beacon */ if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) From 3c15a0fb61e743bc72e2d7e01e968f0247a8be8b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 May 2013 10:17:19 +0200 Subject: [PATCH 5/7] Revert "iwlwifi: mvm: remove P2P_DEVICE support" This reverts commit eebfc9394ee31b3ef162692c0cd483c1318a4395. This wasn't intended to be included here, my mistake. I accidentally merged a mac80211 fixes tree here that had this change, when it wasn't even intended to be there. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 11dc7df8bdf9..dd158ec571fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -84,6 +84,15 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = { .types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP), }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, }; static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { @@ -152,7 +161,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->chanctx_data_size = sizeof(struct iwl_mvm_phy_ctxt); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP); + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_DEVICE); hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS | From a8cd57b3042446250f19daf98d120802dffc768d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 May 2013 10:17:49 +0200 Subject: [PATCH 6/7] Revert "mac80211_hwsim: remove P2P_DEVICE support" This reverts commit e3ee68b7b049c5bbfcb78a179c00c373a38ed58c. This wasn't intended to be included here, my mistake. I accidentally merged a mac80211 fixes tree here that had this change, when it wasn't even intended to be there. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 69bbf6fdd2d3..cb34c7895f2a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2169,6 +2169,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { #endif BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, }; static struct ieee80211_iface_combination hwsim_if_comb = { @@ -2294,7 +2295,8 @@ static int __init init_mac80211_hwsim(void) BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_P2P_DEVICE); hw->flags = IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_SIGNAL_DBM | From ed405be5cb5e8e494e8dcd83b6eb1add34dc752a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 3 Jun 2013 13:51:59 +0200 Subject: [PATCH 7/7] mac80211: fix sdata locking around __ieee80211_request_smps My cfg80211/mac80211 locking unification broke the sdata locking in ieee80211_set_power_mgmt, it needs to acquire the lock for __ieee80211_request_smps(). Add the locking. Reported-by: Jakub Kicinski Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9034da16cf1b..30622101d3b5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2378,7 +2378,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, local->dynamic_ps_forced_timeout = timeout; /* no change, but if automatic follow powersave */ + sdata_lock(sdata); __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); + sdata_unlock(sdata); if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);