From: Greg Kroah-Hartman Date: Mon, 2 Oct 2017 08:57:59 +0000 (+0200) Subject: 4.13-stable patches X-Git-Tag: v3.18.73~37 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=07da3bce8d789380945aba0a21541b6893da5b7f;p=thirdparty%2Fkernel%2Fstable-queue.git 4.13-stable patches added patches: genirq-fix-cpumask-check-in-__irq_startup_managed.patch genirq-make-sparse_irq_lock-protect-what-it-should-protect.patch genirq-msi-fix-populating-multiple-interrupts.patch mac80211-fix-deadlock-in-driver-managed-rx-ba-session-start.patch mac80211-fix-vlan-handling-with-txqs.patch mac80211-flush-hw_roc_start-work-before-cancelling-the-roc.patch mac80211_hwsim-use-proper-tx-power.patch --- diff --git a/queue-4.13/genirq-fix-cpumask-check-in-__irq_startup_managed.patch b/queue-4.13/genirq-fix-cpumask-check-in-__irq_startup_managed.patch new file mode 100644 index 00000000000..1a7948bfcef --- /dev/null +++ b/queue-4.13/genirq-fix-cpumask-check-in-__irq_startup_managed.patch @@ -0,0 +1,50 @@ +From 9cb067ef8a10bb13112e4d1c0ea996ec96527422 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Wed, 13 Sep 2017 23:29:03 +0200 +Subject: genirq: Fix cpumask check in __irq_startup_managed() + +From: Thomas Gleixner + +commit 9cb067ef8a10bb13112e4d1c0ea996ec96527422 upstream. + +The result of cpumask_any_and() is invalid when result greater or equal +nr_cpu_ids. The current check is checking for greater only. Fix it. + +Fixes: 761ea388e8c4 ("genirq: Handle managed irqs gracefully in irq_startup()") +Signed-off-by: Thomas Gleixner +Cc: Boris Ostrovsky +Cc: Juergen Gross +Cc: Tony Luck +Cc: Chen Yu +Cc: Marc Zyngier +Cc: Alok Kataria +Cc: Joerg Roedel +Cc: "Rafael J. Wysocki" +Cc: Steven Rostedt +Cc: Christoph Hellwig +Cc: Peter Zijlstra +Cc: Borislav Petkov +Cc: Paolo Bonzini +Cc: Rui Zhang +Cc: "K. Y. Srinivasan" +Cc: Arjan van de Ven +Cc: Dan Williams +Cc: Len Brown +Link: http://lkml.kernel.org/r/20170913213152.272283444@linutronix.de +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/irq/chip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/irq/chip.c ++++ b/kernel/irq/chip.c +@@ -202,7 +202,7 @@ __irq_startup_managed(struct irq_desc *d + + irqd_clr_managed_shutdown(d); + +- if (cpumask_any_and(aff, cpu_online_mask) > nr_cpu_ids) { ++ if (cpumask_any_and(aff, cpu_online_mask) >= nr_cpu_ids) { + /* + * Catch code which fiddles with enable_irq() on a managed + * and potentially shutdown IRQ. Chained interrupt diff --git a/queue-4.13/genirq-make-sparse_irq_lock-protect-what-it-should-protect.patch b/queue-4.13/genirq-make-sparse_irq_lock-protect-what-it-should-protect.patch new file mode 100644 index 00000000000..f26c047b7eb --- /dev/null +++ b/queue-4.13/genirq-make-sparse_irq_lock-protect-what-it-should-protect.patch @@ -0,0 +1,119 @@ +From 12ac1d0f6c3e95732d144ffa65c8b20fbd9aa462 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 5 Sep 2017 10:12:20 +0200 +Subject: genirq: Make sparse_irq_lock protect what it should protect + +From: Thomas Gleixner + +commit 12ac1d0f6c3e95732d144ffa65c8b20fbd9aa462 upstream. + +for_each_active_irq() iterates the sparse irq allocation bitmap. The caller +must hold sparse_irq_lock. Several code pathes expect that an active bit in +the sparse bitmap also has a valid interrupt descriptor. + +Unfortunately that's not true. The (de)allocation is a two step process, +which holds the sparse_irq_lock only across the queue/remove from the radix +tree and the set/clear in the allocation bitmap. + +If a iteration locks sparse_irq_lock between the two steps, then it might +see an active bit but the corresponding irq descriptor is NULL. If that is +dereferenced unconditionally, then the kernel oopses. Of course, all +iterator sites could be audited and fixed, but.... + +There is no reason why the sparse_irq_lock needs to be dropped between the +two steps, in fact the code becomes simpler when the mutex is held across +both and the semantics become more straight forward, so future problems of +missing NULL pointer checks in the iteration are avoided and all existing +sites are fixed in one go. + +Expand the lock held sections so both operations are covered and the bitmap +and the radixtree are in sync. + +Fixes: a05a900a51c7 ("genirq: Make sparse_lock a mutex") +Reported-and-tested-by: Huang Ying +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/irq/irqdesc.c | 24 +++++++----------------- + 1 file changed, 7 insertions(+), 17 deletions(-) + +--- a/kernel/irq/irqdesc.c ++++ b/kernel/irq/irqdesc.c +@@ -421,10 +421,8 @@ static void free_desc(unsigned int irq) + * The sysfs entry must be serialized against a concurrent + * irq_sysfs_init() as well. + */ +- mutex_lock(&sparse_irq_lock); + kobject_del(&desc->kobj); + delete_irq_desc(irq); +- mutex_unlock(&sparse_irq_lock); + + /* + * We free the descriptor, masks and stat fields via RCU. That +@@ -462,20 +460,15 @@ static int alloc_descs(unsigned int star + desc = alloc_desc(start + i, node, flags, mask, owner); + if (!desc) + goto err; +- mutex_lock(&sparse_irq_lock); + irq_insert_desc(start + i, desc); + irq_sysfs_add(start + i, desc); +- mutex_unlock(&sparse_irq_lock); + } ++ bitmap_set(allocated_irqs, start, cnt); + return start; + + err: + for (i--; i >= 0; i--) + free_desc(start + i); +- +- mutex_lock(&sparse_irq_lock); +- bitmap_clear(allocated_irqs, start, cnt); +- mutex_unlock(&sparse_irq_lock); + return -ENOMEM; + } + +@@ -575,6 +568,7 @@ static inline int alloc_descs(unsigned i + + desc->owner = owner; + } ++ bitmap_set(allocated_irqs, start, cnt); + return start; + } + +@@ -670,10 +664,10 @@ void irq_free_descs(unsigned int from, u + if (from >= nr_irqs || (from + cnt) > nr_irqs) + return; + ++ mutex_lock(&sparse_irq_lock); + for (i = 0; i < cnt; i++) + free_desc(from + i); + +- mutex_lock(&sparse_irq_lock); + bitmap_clear(allocated_irqs, from, cnt); + mutex_unlock(&sparse_irq_lock); + } +@@ -720,19 +714,15 @@ __irq_alloc_descs(int irq, unsigned int + from, cnt, 0); + ret = -EEXIST; + if (irq >=0 && start != irq) +- goto err; ++ goto unlock; + + if (start + cnt > nr_irqs) { + ret = irq_expand_nr_irqs(start + cnt); + if (ret) +- goto err; ++ goto unlock; + } +- +- bitmap_set(allocated_irqs, start, cnt); +- mutex_unlock(&sparse_irq_lock); +- return alloc_descs(start, cnt, node, affinity, owner); +- +-err: ++ ret = alloc_descs(start, cnt, node, affinity, owner); ++unlock: + mutex_unlock(&sparse_irq_lock); + return ret; + } diff --git a/queue-4.13/genirq-msi-fix-populating-multiple-interrupts.patch b/queue-4.13/genirq-msi-fix-populating-multiple-interrupts.patch new file mode 100644 index 00000000000..8ab5163a1c7 --- /dev/null +++ b/queue-4.13/genirq-msi-fix-populating-multiple-interrupts.patch @@ -0,0 +1,49 @@ +From 596a7a1d0989c621c3ae49be73a1d1f9de22eb5a Mon Sep 17 00:00:00 2001 +From: John Keeping +Date: Wed, 6 Sep 2017 10:35:40 +0100 +Subject: genirq/msi: Fix populating multiple interrupts + +From: John Keeping + +commit 596a7a1d0989c621c3ae49be73a1d1f9de22eb5a upstream. + +On allocating the interrupts routed via a wire-to-MSI bridge, the allocator +iterates over the MSI descriptors to build the hierarchy, but fails to use +the descriptor interrupt number, and instead uses the base number, +generating the wrong IRQ domain mappings. + +The fix is to use the MSI descriptor interrupt number when setting up +the interrupt instead of the base interrupt for the allocation range. + +The only saving grace is that although the MSI descriptors are allocated +in bulk, the wired interrupts are only allocated one by one (so +desc->irq == virq) and the bug went unnoticed so far. + +Fixes: 2145ac9310b60 ("genirq/msi: Add msi_domain_populate_irqs") +Signed-off-by: John Keeping +Signed-off-by: Thomas Gleixner +Reviewed-by: Marc Zyngier +Link: http://lkml.kernel.org/r/20170906103540.373864a2.john@metanate.com +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/irq/msi.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/kernel/irq/msi.c ++++ b/kernel/irq/msi.c +@@ -315,11 +315,12 @@ int msi_domain_populate_irqs(struct irq_ + + ops->set_desc(arg, desc); + /* Assumes the domain mutex is held! */ +- ret = irq_domain_alloc_irqs_hierarchy(domain, virq, 1, arg); ++ ret = irq_domain_alloc_irqs_hierarchy(domain, desc->irq, 1, ++ arg); + if (ret) + break; + +- irq_set_msi_desc_off(virq, 0, desc); ++ irq_set_msi_desc_off(desc->irq, 0, desc); + } + + if (ret) { diff --git a/queue-4.13/mac80211-fix-deadlock-in-driver-managed-rx-ba-session-start.patch b/queue-4.13/mac80211-fix-deadlock-in-driver-managed-rx-ba-session-start.patch new file mode 100644 index 00000000000..2e398e0f1d0 --- /dev/null +++ b/queue-4.13/mac80211-fix-deadlock-in-driver-managed-rx-ba-session-start.patch @@ -0,0 +1,146 @@ +From bde59c475e0883e4c4294bcd9b9c7e08ae18c828 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Wed, 6 Sep 2017 15:01:42 +0200 +Subject: mac80211: fix deadlock in driver-managed RX BA session start + +From: Johannes Berg + +commit bde59c475e0883e4c4294bcd9b9c7e08ae18c828 upstream. + +When an RX BA session is started by the driver, and it has to tell +mac80211 about it, the corresponding bit in tid_rx_manage_offl gets +set and the BA session work is scheduled. Upon testing this bit, it +will call __ieee80211_start_rx_ba_session(), thus deadlocking as it +already holds the ampdu_mlme.mtx, which that acquires again. + +Fix this by adding ___ieee80211_start_rx_ba_session(), a version of +the function that requires the mutex already held. + +Fixes: 699cb58c8a52 ("mac80211: manage RX BA session offload without SKB queue") +Reported-by: Matteo Croce +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/agg-rx.c | 32 +++++++++++++++++++++----------- + net/mac80211/ht.c | 6 +++--- + net/mac80211/ieee80211_i.h | 4 ++++ + 3 files changed, 28 insertions(+), 14 deletions(-) + +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -245,10 +245,10 @@ static void ieee80211_send_addba_resp(st + ieee80211_tx_skb(sdata, skb); + } + +-void __ieee80211_start_rx_ba_session(struct sta_info *sta, +- u8 dialog_token, u16 timeout, +- u16 start_seq_num, u16 ba_policy, u16 tid, +- u16 buf_size, bool tx, bool auto_seq) ++void ___ieee80211_start_rx_ba_session(struct sta_info *sta, ++ u8 dialog_token, u16 timeout, ++ u16 start_seq_num, u16 ba_policy, u16 tid, ++ u16 buf_size, bool tx, bool auto_seq) + { + struct ieee80211_local *local = sta->sdata->local; + struct tid_ampdu_rx *tid_agg_rx; +@@ -267,7 +267,7 @@ void __ieee80211_start_rx_ba_session(str + ht_dbg(sta->sdata, + "STA %pM requests BA session on unsupported tid %d\n", + sta->sta.addr, tid); +- goto end_no_lock; ++ goto end; + } + + if (!sta->sta.ht_cap.ht_supported) { +@@ -275,14 +275,14 @@ void __ieee80211_start_rx_ba_session(str + "STA %pM erroneously requests BA session on tid %d w/o QoS\n", + sta->sta.addr, tid); + /* send a response anyway, it's an error case if we get here */ +- goto end_no_lock; ++ goto end; + } + + if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { + ht_dbg(sta->sdata, + "Suspend in progress - Denying ADDBA request (%pM tid %d)\n", + sta->sta.addr, tid); +- goto end_no_lock; ++ goto end; + } + + /* sanity check for incoming parameters: +@@ -296,7 +296,7 @@ void __ieee80211_start_rx_ba_session(str + ht_dbg_ratelimited(sta->sdata, + "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", + sta->sta.addr, tid, ba_policy, buf_size); +- goto end_no_lock; ++ goto end; + } + /* determine default buffer size */ + if (buf_size == 0) +@@ -311,7 +311,7 @@ void __ieee80211_start_rx_ba_session(str + buf_size, sta->sta.addr); + + /* examine state machine */ +- mutex_lock(&sta->ampdu_mlme.mtx); ++ lockdep_assert_held(&sta->ampdu_mlme.mtx); + + if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) { + if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) { +@@ -415,15 +415,25 @@ end: + __clear_bit(tid, sta->ampdu_mlme.unexpected_agg); + sta->ampdu_mlme.tid_rx_token[tid] = dialog_token; + } +- mutex_unlock(&sta->ampdu_mlme.mtx); + +-end_no_lock: + if (tx) + ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, + dialog_token, status, 1, buf_size, + timeout); + } + ++void __ieee80211_start_rx_ba_session(struct sta_info *sta, ++ u8 dialog_token, u16 timeout, ++ u16 start_seq_num, u16 ba_policy, u16 tid, ++ u16 buf_size, bool tx, bool auto_seq) ++{ ++ mutex_lock(&sta->ampdu_mlme.mtx); ++ ___ieee80211_start_rx_ba_session(sta, dialog_token, timeout, ++ start_seq_num, ba_policy, tid, ++ buf_size, tx, auto_seq); ++ mutex_unlock(&sta->ampdu_mlme.mtx); ++} ++ + void ieee80211_process_addba_request(struct ieee80211_local *local, + struct sta_info *sta, + struct ieee80211_mgmt *mgmt, +--- a/net/mac80211/ht.c ++++ b/net/mac80211/ht.c +@@ -333,9 +333,9 @@ void ieee80211_ba_session_work(struct wo + + if (test_and_clear_bit(tid, + sta->ampdu_mlme.tid_rx_manage_offl)) +- __ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid, +- IEEE80211_MAX_AMPDU_BUF, +- false, true); ++ ___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid, ++ IEEE80211_MAX_AMPDU_BUF, ++ false, true); + + if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS, + sta->ampdu_mlme.tid_rx_manage_offl)) +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1760,6 +1760,10 @@ void __ieee80211_start_rx_ba_session(str + u8 dialog_token, u16 timeout, + u16 start_seq_num, u16 ba_policy, u16 tid, + u16 buf_size, bool tx, bool auto_seq); ++void ___ieee80211_start_rx_ba_session(struct sta_info *sta, ++ u8 dialog_token, u16 timeout, ++ u16 start_seq_num, u16 ba_policy, u16 tid, ++ u16 buf_size, bool tx, bool auto_seq); + void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, + enum ieee80211_agg_stop_reason reason); + void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, diff --git a/queue-4.13/mac80211-fix-vlan-handling-with-txqs.patch b/queue-4.13/mac80211-fix-vlan-handling-with-txqs.patch new file mode 100644 index 00000000000..0a32b5ed11c --- /dev/null +++ b/queue-4.13/mac80211-fix-vlan-handling-with-txqs.patch @@ -0,0 +1,167 @@ +From 53168215909281a09d3afc6fb51a9d4f81f74d39 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Thu, 22 Jun 2017 12:20:30 +0200 +Subject: mac80211: fix VLAN handling with TXQs + +From: Johannes Berg + +commit 53168215909281a09d3afc6fb51a9d4f81f74d39 upstream. + +With TXQs, the AP_VLAN interfaces are resolved to their owner AP +interface when enqueuing the frame, which makes sense since the +frame really goes out on that as far as the driver is concerned. + +However, this introduces a problem: frames to be encrypted with +a VLAN-specific GTK will now be encrypted with the AP GTK, since +the information about which virtual interface to use to select +the key is taken from the TXQ. + +Fix this by preserving info->control.vif and using that in the +dequeue function. This now requires doing the driver-mapping +in the dequeue as well. + +Since there's no way to filter the frames that are sitting on a +TXQ, drop all frames, which may affect other interfaces, when an +AP_VLAN is removed. + +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + include/net/mac80211.h | 15 ++------------- + net/mac80211/iface.c | 17 +++++++++++++++-- + net/mac80211/tx.c | 36 +++++++++++++++++++++++++++++------- + 3 files changed, 46 insertions(+), 22 deletions(-) + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -919,21 +919,10 @@ struct ieee80211_tx_info { + unsigned long jiffies; + }; + /* NB: vif can be NULL for injected frames */ +- union { +- /* NB: vif can be NULL for injected frames */ +- struct ieee80211_vif *vif; +- +- /* When packets are enqueued on txq it's easy +- * to re-construct the vif pointer. There's no +- * more space in tx_info so it can be used to +- * store the necessary enqueue time for packet +- * sojourn time computation. +- */ +- codel_time_t enqueue_time; +- }; ++ struct ieee80211_vif *vif; + struct ieee80211_key_conf *hw_key; + u32 flags; +- /* 4 bytes free */ ++ codel_time_t enqueue_time; + } control; + struct { + u64 cookie; +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -792,6 +792,7 @@ static int ieee80211_open(struct net_dev + static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, + bool going_down) + { ++ struct ieee80211_sub_if_data *txq_sdata = sdata; + struct ieee80211_local *local = sdata->local; + struct fq *fq = &local->fq; + unsigned long flags; +@@ -937,6 +938,9 @@ static void ieee80211_do_stop(struct iee + + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP_VLAN: ++ txq_sdata = container_of(sdata->bss, ++ struct ieee80211_sub_if_data, u.ap); ++ + mutex_lock(&local->mtx); + list_del(&sdata->u.vlan.list); + mutex_unlock(&local->mtx); +@@ -1007,8 +1011,17 @@ static void ieee80211_do_stop(struct iee + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + +- if (sdata->vif.txq) { +- struct txq_info *txqi = to_txq_info(sdata->vif.txq); ++ if (txq_sdata->vif.txq) { ++ struct txq_info *txqi = to_txq_info(txq_sdata->vif.txq); ++ ++ /* ++ * FIXME FIXME ++ * ++ * We really shouldn't purge the *entire* txqi since that ++ * contains frames for the other AP_VLANs (and possibly ++ * the AP itself) as well, but there's no API in FQ now ++ * to be able to filter. ++ */ + + spin_lock_bh(&fq->lock); + ieee80211_txq_purge(local, txqi); +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1276,11 +1276,6 @@ static void ieee80211_set_skb_enqueue_ti + IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time(); + } + +-static void ieee80211_set_skb_vif(struct sk_buff *skb, struct txq_info *txqi) +-{ +- IEEE80211_SKB_CB(skb)->control.vif = txqi->txq.vif; +-} +- + static u32 codel_skb_len_func(const struct sk_buff *skb) + { + return skb->len; +@@ -3414,6 +3409,7 @@ struct sk_buff *ieee80211_tx_dequeue(str + struct ieee80211_tx_info *info; + struct ieee80211_tx_data tx; + ieee80211_tx_result r; ++ struct ieee80211_vif *vif; + + spin_lock_bh(&fq->lock); + +@@ -3430,8 +3426,6 @@ begin: + if (!skb) + goto out; + +- ieee80211_set_skb_vif(skb, txqi); +- + hdr = (struct ieee80211_hdr *)skb->data; + info = IEEE80211_SKB_CB(skb); + +@@ -3488,6 +3482,34 @@ begin: + } + } + ++ switch (tx.sdata->vif.type) { ++ case NL80211_IFTYPE_MONITOR: ++ if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) { ++ vif = &tx.sdata->vif; ++ break; ++ } ++ tx.sdata = rcu_dereference(local->monitor_sdata); ++ if (tx.sdata) { ++ vif = &tx.sdata->vif; ++ info->hw_queue = ++ vif->hw_queue[skb_get_queue_mapping(skb)]; ++ } else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) { ++ ieee80211_free_txskb(&local->hw, skb); ++ goto begin; ++ } else { ++ vif = NULL; ++ } ++ break; ++ case NL80211_IFTYPE_AP_VLAN: ++ tx.sdata = container_of(tx.sdata->bss, ++ struct ieee80211_sub_if_data, u.ap); ++ /* fall through */ ++ default: ++ vif = &tx.sdata->vif; ++ break; ++ } ++ ++ IEEE80211_SKB_CB(skb)->control.vif = vif; + out: + spin_unlock_bh(&fq->lock); + diff --git a/queue-4.13/mac80211-flush-hw_roc_start-work-before-cancelling-the-roc.patch b/queue-4.13/mac80211-flush-hw_roc_start-work-before-cancelling-the-roc.patch new file mode 100644 index 00000000000..1f0ce3c2d40 --- /dev/null +++ b/queue-4.13/mac80211-flush-hw_roc_start-work-before-cancelling-the-roc.patch @@ -0,0 +1,46 @@ +From 6e46d8ce894374fc135c96a8d1057c6af1fef237 Mon Sep 17 00:00:00 2001 +From: Avraham Stern +Date: Fri, 18 Aug 2017 15:33:57 +0300 +Subject: mac80211: flush hw_roc_start work before cancelling the ROC + +From: Avraham Stern + +commit 6e46d8ce894374fc135c96a8d1057c6af1fef237 upstream. + +When HW ROC is supported it is possible that after the HW notified +that the ROC has started, the ROC was cancelled and another ROC was +added while the hw_roc_start worker is waiting on the mutex (since +cancelling the ROC and adding another one also holds the same mutex). +As a result, the hw_roc_start worker will continue to run after the +new ROC is added but before it is actually started by the HW. +This may result in notifying userspace that the ROC has started before +it actually does, or in case of management tx ROC, in an attempt to +tx while not on the right channel. + +In addition, when the driver will notify mac80211 that the second ROC +has started, mac80211 will warn that this ROC has already been +notified. + +Fix this by flushing the hw_roc_start work before cancelling an ROC. + +Cc: stable@vger.kernel.org +Signed-off-by: Avraham Stern +Signed-off-by: Luca Coelho +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/offchannel.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/mac80211/offchannel.c ++++ b/net/mac80211/offchannel.c +@@ -707,6 +707,8 @@ static int ieee80211_cancel_roc(struct i + if (!cookie) + return -ENOENT; + ++ flush_work(&local->hw_roc_start); ++ + mutex_lock(&local->mtx); + list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { + if (!mgmt_tx && roc->cookie != cookie) diff --git a/queue-4.13/mac80211_hwsim-use-proper-tx-power.patch b/queue-4.13/mac80211_hwsim-use-proper-tx-power.patch new file mode 100644 index 00000000000..c6df279fb88 --- /dev/null +++ b/queue-4.13/mac80211_hwsim-use-proper-tx-power.patch @@ -0,0 +1,39 @@ +From 9de981f507474f326e42117858dc9a9321331ae5 Mon Sep 17 00:00:00 2001 +From: Beni Lev +Date: Tue, 25 Jul 2017 11:25:25 +0300 +Subject: mac80211_hwsim: Use proper TX power + +From: Beni Lev + +commit 9de981f507474f326e42117858dc9a9321331ae5 upstream. + +In struct ieee80211_tx_info, control.vif pointer and rate_driver_data[0] +falls on the same place, depending on the union usage. +During the whole TX process, the union is referred to as a control struct, +which holds the vif that is later used in the tx flow, especially in order +to derive the used tx power. +Referring direcly to rate_driver_data[0] and assigning a value to it, +overwrites the vif pointer, hence making all later references irrelevant. +Moreover, rate_driver_data[0] isn't used later in the flow in order to +retrieve the channel that it is pointing to. + +Signed-off-by: Beni Lev +Signed-off-by: Luca Coelho +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mac80211_hwsim.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/net/wireless/mac80211_hwsim.c ++++ b/drivers/net/wireless/mac80211_hwsim.c +@@ -1362,8 +1362,6 @@ static void mac80211_hwsim_tx(struct iee + txi->control.rates, + ARRAY_SIZE(txi->control.rates)); + +- txi->rate_driver_data[0] = channel; +- + if (skb->len >= 24 + 8 && + ieee80211_is_probe_resp(hdr->frame_control)) { + /* fake header transmission time */