From 59615b5f9d1323898ca94e88e595b5b04115076a Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Thu, 25 Jun 2009 16:07:42 -0700 Subject: mac80211: fix allocation in mesh_queue_preq We allocate a PREQ queue node in mesh_queue_preq, however the allocation may cause us to sleep. Use GFP_ATOMIC to prevent this. [ 1869.126498] BUG: scheduling while atomic: ping/1859/0x10000100 [ 1869.127164] Modules linked in: ath5k mac80211 ath [ 1869.128310] Pid: 1859, comm: ping Not tainted 2.6.30-wl #1 [ 1869.128754] Call Trace: [ 1869.129293] [] __schedule_bug+0x48/0x4d [ 1869.129866] [] __schedule+0x77/0x67a [ 1869.130544] [] ? release_console_sem+0x17d/0x185 [ 1869.131568] [] ? mesh_queue_preq+0x2b/0x165 [mac80211] [ 1869.132318] [] schedule+0x8/0x1f [ 1869.132807] [] __cond_resched+0x16/0x2f [ 1869.133478] [] _cond_resched+0x27/0x32 [ 1869.134191] [] kmem_cache_alloc+0x1c/0xcf [ 1869.134714] [] ? printk+0x15/0x17 [ 1869.135670] [] mesh_queue_preq+0x2b/0x165 [mac80211] [ 1869.136731] [] mesh_nexthop_lookup+0xee/0x12d [mac80211] [ 1869.138130] [] ieee80211_xmit+0xe6/0x2b2 [mac80211] [ 1869.138935] [] ? ath5k_hw_setup_rx_desc+0x0/0x66 [ath5k] [ 1869.139831] [] ? ath5k_tasklet_rx+0xba/0x506 [ath5k] [ 1869.140863] [] ieee80211_subif_start_xmit+0x6c9/0x6e4 [mac80211] [ 1869.141665] [] ? handle_level_irq+0x78/0x9d [ 1869.142390] [] dev_hard_start_xmit+0x168/0x1c7 [ 1869.143092] [] __qdisc_run+0xe1/0x1b7 [ 1869.143612] [] qdisc_run+0x18/0x1a [ 1869.144248] [] dev_queue_xmit+0x16a/0x25a [ 1869.144785] [] ? _read_unlock_bh+0xe/0x10 [ 1869.145465] [] neigh_resolve_output+0x19c/0x1c7 [ 1869.146182] [] ? ip_finish_output+0x0/0x51 [ 1869.146697] [] ip_finish_output2+0x182/0x1bc [ 1869.147358] [] ip_finish_output+0x4d/0x51 [ 1869.147863] [] ip_output+0x80/0x85 [ 1869.148515] [] dst_output+0x9/0xb [ 1869.149141] [] ip_local_out+0x17/0x1a [ 1869.149632] [] ip_push_pending_frames+0x1f3/0x255 [ 1869.150343] [] raw_sendmsg+0x5e6/0x667 [ 1869.150883] [] ? insert_work+0x6a/0x73 [ 1869.151834] [] ? ieee80211_invoke_rx_handlers+0x17da/0x1ae8 [mac80211] [ 1869.152630] [] inet_sendmsg+0x3b/0x48 [ 1869.153232] [] __sock_sendmsg+0x45/0x4e [ 1869.153740] [] sock_sendmsg+0xb8/0xce [ 1869.154519] [] ? ath5k_hw_setup_rx_desc+0x0/0x66 [ath5k] [ 1869.155289] [] ? autoremove_wake_function+0x0/0x30 [ 1869.155859] [] ? __copy_from_user_ll+0x11/0xce [ 1869.156573] [] ? copy_from_user+0x31/0x54 [ 1869.157235] [] ? verify_iovec+0x40/0x6e [ 1869.157778] [] sys_sendmsg+0x14d/0x1a5 [ 1869.158714] [] ? __ieee80211_rx+0x49e/0x4ee [mac80211] [ 1869.159641] [] ? ath5k_rxbuf_setup+0x6d/0x8d [ath5k] [ 1869.160543] [] ? ath5k_hw_setup_rx_desc+0x0/0x66 [ath5k] [ 1869.161434] [] ? ath5k_hw_get_rxdp+0xe/0x10 [ath5k] [ 1869.162319] [] ? ath5k_tasklet_rx+0xba/0x506 [ath5k] [ 1869.163063] [] ? enable_8259A_irq+0x40/0x43 [ 1869.163594] [] ? __dequeue_entity+0x23/0x27 [ 1869.164793] [] ? __switch_to+0x2b/0x105 [ 1869.165442] [] ? finish_task_switch+0x5b/0x74 [ 1869.166129] [] sys_socketcall+0x14b/0x17b [ 1869.166612] [] syscall_call+0x7/0xb Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 003cb470ac8..f49ef288e2e 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -637,7 +637,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_preq_queue *preq_node; - preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL); + preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); if (!preq_node) { printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); return; -- cgit From 3938b45c1c75e53d45eb65ac253f12e86239c9ba Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 3 Jul 2009 08:25:08 +0300 Subject: mac80211: minstrel: avoid accessing negative indices in rix_to_ndx() If rix is not found in mi->r[], i will become -1 after the loop. This value is eventually used to access arrays, so we were accessing arrays with a negative index, which is obviously not what we want to do. This patch fixes this potential problem. Signed-off-by: Luciano Coelho Acked-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index b218b98fba7..37771abd8f5 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix) for (i = rix; i >= 0; i--) if (mi->r[i].rix == rix) break; - WARN_ON(mi->r[i].rix != rix); + WARN_ON(i < 0); return i; } @@ -181,6 +181,9 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, break; ndx = rix_to_ndx(mi, ar[i].idx); + if (ndx < 0) + continue; + mi->r[ndx].attempts += ar[i].count; if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) -- cgit From e2e414d92397c366396d13f627a98a20be92e509 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 11:38:14 +0200 Subject: mac80211: disable mesh My kvm instance was complaining a lot about sleeping in atomic contexts in the mesh code, and it turns out that both mesh_path_add() and mpp_path_add() need to be able to sleep (they even use synchronize_rcu()!). I put in a might_sleep() to annotate that, but I see no way, at least right now, of actually making sure those functions are only called from process context since they are both called during TX and RX and the mesh code itself even calls them with rcu_read_lock() "held". Therefore, let's disable it completely for now. It's possible that I'm only seeing this because the hwsim's beaconing is broken and thus the peers aren't discovered right away, but it is possible that this happens even if beaconing is working, for a peer that doesn't exist or so. It should be possible to solve this by deferring the freeing of the tables to call_rcu() instead of using synchronize_rcu(), and also using atomic allocations, but maybe it makes more sense to rework the code to not call these from atomic contexts and defer more of the work to the workqueue. Right now, I can't work on either of those solutions though. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 1 + net/mac80211/mesh_pathtbl.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index ba2643a43c7..7836ee92898 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -83,6 +83,7 @@ endmenu config MAC80211_MESH bool "Enable mac80211 mesh networking (pre-802.11s) support" depends on MAC80211 && EXPERIMENTAL + depends on BROKEN ---help--- This options enables support of Draft 802.11s mesh networking. The implementation is based on Draft 1.08 of the Mesh Networking diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 3c72557df45..02f8709a181 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -175,6 +175,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; + might_sleep(); + if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -265,6 +267,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; + might_sleep(); if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ -- cgit From 8ef86c7bfac5b44529b73b84bc50d3cf574bfb4b Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 10 Jul 2009 16:42:29 -0400 Subject: mac80211: fix injection in monitor mode The location of the 802.11 header is calculated incorrectly due to a wrong placement of parentheses. Found by kmemcheck. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- net/mac80211/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d238a8939a0..3a8922cd103 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1455,7 +1455,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) monitor_iface = UNKNOWN_ADDRESS; len_rthdr = ieee80211_get_radiotap_len(skb->data); - hdr = (struct ieee80211_hdr *)skb->data + len_rthdr; + hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); hdrlen = ieee80211_hdrlen(hdr->frame_control); /* check the header is complete in the frame */ -- cgit From 35946a571099a50d2595c8866f07617d29558f53 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 13 Jul 2009 17:00:10 -0700 Subject: mac80211: use correct address for mesh Path Error For forwarded frames, we save the precursor address in addr1 in case it needs to be used to send a Path Error. mesh_path_discard_frame, however, was using addr2 instead of addr1 to send Path Error frames, so correct that and also make the comment regarding this more clear. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 02f8709a181..479597e8858 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -494,8 +494,10 @@ void mesh_path_tx_pending(struct mesh_path *mpath) * @skb: frame to discard * @sdata: network subif the frame was to be sent through * - * If the frame was beign forwarded from another MP, a PERR frame will be sent - * to the precursor. + * If the frame was being forwarded from another MP, a PERR frame will be sent + * to the precursor. The precursor's address (i.e. the previous hop) was saved + * in addr1 of the frame-to-be-forwarded, and would only be overwritten once + * the destination is successfully resolved. * * Locking: the function must me called within a rcu_read_lock region */ @@ -510,7 +512,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, u8 *ra, *da; da = hdr->addr3; - ra = hdr->addr2; + ra = hdr->addr1; mpath = mesh_path_lookup(da, sdata); if (mpath) dsn = ++mpath->dsn; -- cgit From 78f1a8b758d57c2d2c9f3db7199cd30803854c82 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 08:38:25 -0700 Subject: mac80211: do not queue work after suspend in the dynamic ps timer Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aca22b00b6a..07e7e41816b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -721,7 +721,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) { struct ieee80211_local *local = (void *) data; - if (local->quiescing) + if (local->quiescing || local->suspended) return; queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); -- cgit From 89c3a8aca28e6d57f2ae945d97858a372d624b81 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Jul 2009 18:10:17 +0200 Subject: mac80211: fix suspend Jan reported that his b43-based laptop hangs during suspend. The problem turned out to be mac80211 asking the driver to stop the hardware before removing interfaces, and interface removal caused b43 to touch the hardware (while down, which causes the hang). This patch fixes mac80211 to do reorder these operations to have them in the correct order -- first remove interfaces and then stop the hardware. Some more code is necessary to be able to do so in a race-free manner, in particular it is necessary to not process frames received during quiescing. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=13337. Reported-by: Jan Scholz Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/pm.c | 24 +++++++++++++++--------- net/mac80211/rx.c | 12 ++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 7a549f9deb9..5e3d476972f 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -55,15 +55,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) rcu_read_unlock(); - /* flush again, in case driver queued work */ - flush_workqueue(local->hw.workqueue); - - /* stop hardware - this must stop RX */ - if (local->open_count) { - ieee80211_led_radio(local, false); - drv_stop(local); - } - /* remove STAs */ spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry(sta, &local->sta_list, list) { @@ -111,7 +102,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) drv_remove_interface(local, &conf); } + /* stop hardware - this must stop RX */ + if (local->open_count) { + ieee80211_led_radio(local, false); + drv_stop(local); + } + + /* + * flush again, in case driver queued work -- it + * shouldn't be doing (or cancel everything in the + * stop callback) that but better safe than sorry. + */ + flush_workqueue(local->hw.workqueue); + local->suspended = true; + /* need suspended to be visible before quiescing is false */ + barrier(); local->quiescing = false; return 0; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index de5bba7f910..0936fc24942 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2453,6 +2453,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, return; } + /* + * If we're suspending, it is possible although not too likely + * that we'd be receiving frames after having already partially + * quiesced the stack. We can't process such frames then since + * that might, for example, cause stations to be added or other + * driver callbacks be invoked. + */ + if (unlikely(local->quiescing || local->suspended)) { + kfree_skb(skb); + return; + } + if (status->flag & RX_FLAG_HT) { /* rate_idx is MCS index */ if (WARN_ON(status->rate_idx < 0 || -- cgit From 416fbdff2137e8d8cc8f23f517bee3a26b11526f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 11 Aug 2009 13:10:33 -0700 Subject: mac80211: fix panic when splicing unprepared TIDs We splice skbs from the pending queue for a TID onto the local pending queue when tearing down a block ack request. This is not necessary unless we actually have received a request to start a block ack request (rate control, for example). If we never received that request we should not be splicing the tid pending queue as it would be null, causing a panic. Not sure yet how exactly we allowed through a call when the tid state does not have at least HT_ADDBA_REQUESTED_MSK set, that will require some further review as it is not quite obvious. For more information see the bug report: http://bugzilla.kernel.org/show_bug.cgi?id=13922 This fixes this oops: BUG: unable to handle kernel NULL pointer dereference at 00000030 IP: [] ieee80211_agg_splice_packets+0x40/0xc0 [mac80211] *pdpt = 0000000002d1e001 *pde = 0000000000000000 Thread overran stack, or stack corrupted Oops: 0000 [#1] SMP last sysfs file: /sys/module/aes_generic/initstate Modules linked in: Pid: 0, comm: swapper Not tainted (2.6.31-rc5-wl #2) Dell DV051 EIP: 0060:[] EFLAGS: 00010292 CPU: 0 EIP is at ieee80211_agg_splice_packets+0x40/0xc0 [mac80211] EAX: 00000030 EBX: 0000004c ECX: 00000003 EDX: 00000000 ESI: c1c98000 EDI: f745a1c0 EBP: c076be58 ESP: c076be38 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 Process swapper (pid: 0, ti=c076a000 task=c0709160 task.ti=c076a000) Stack: Call Trace: [] ? ieee80211_stop_tx_ba_cb+0xab/0x150 [mac80211] [] ? ieee80211_tasklet_handler+0xce/0x110 [mac80211] [] ? net_rx_action+0xef/0x1d0 [] ? tasklet_action+0x58/0xc0 [] ? __do_softirq+0xc2/0x190 [] ? handle_IRQ_event+0x58/0x140 [] ? ack_apic_level+0x7e/0x270 [] ? do_softirq+0x3d/0x40 [] ? irq_exit+0x65/0x90 [] ? do_IRQ+0x4f/0xc0 [] ? irq_exit+0x7d/0x90 [] ? smp_apic_timer_interrupt+0x57/0x90 [] ? common_interrupt+0x29/0x30 [] ? mwait_idle+0xbe/0x100 [] ? cpu_idle+0x52/0x90 [] ? rest_init+0x55/0x60 [] ? start_kernel+0x315/0x37d [] ? unknown_bootoption+0x0/0x1f9 [] ? i386_start_kernel+0x79/0x81 Code: EIP: [] ieee80211_agg_splice_packets+0x40/0xc0 [mac80211] SS:ESP 0068:c076be38 CR2: 0000000000000030 Cc: stable@kernel.org Testedy-by: Jack Lau Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 9e5762ad307..a24e59816b9 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -381,6 +381,14 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local, &local->hw, queue, IEEE80211_QUEUE_STOP_REASON_AGGREGATION); + if (!(sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK)) + return; + + if (WARN(!sta->ampdu_mlme.tid_tx[tid], + "TID %d gone but expected when splicing aggregates from" + "the pending queue\n", tid)) + return; + if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) { spin_lock_irqsave(&local->queue_stop_reason_lock, flags); /* mark queue as pending, it is stopped already */ -- cgit