From 066a3b5b2346febf9a655b444567b7138e3bb939 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Mon, 14 Apr 2008 15:10:42 -0700 Subject: [NET_SCHED] sch_api: fix qdisc_tree_decrease_qlen() loop TC_H_MAJ(parentid) for root classes is the same as for ingress, and if ingress qdisc is created qdisc_lookup() returns its pointer (without ingress NULL is returned). After this all qdisc_lookups give the same, and we get endless loop. (I don't know how this could hide for so long - it should trigger with every leaf class deleted if it's qdisc isn't empty.) After this fix qdisc_lookup() is omitted both for ingress and root parents, but looking for root is only wasting a little time here... Many thanks to Enrico Demarin for finding a test for catching this bug, which probably bothered quite a lot of admins. Reported-by: Enrico Demarin , Signed-off-by: Jarek Poplawski Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_api.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 7e3c048ba9b..fc8708a0a25 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -386,6 +386,9 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) if (n == 0) return; while ((parentid = sch->parent)) { + if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS)) + return; + sch = qdisc_lookup(sch->dev, TC_H_MAJ(parentid)); if (sch == NULL) { WARN_ON(parentid != TC_H_ROOT); -- cgit v1.2.3-70-g09d2 From b000cd3707e7b25d76745f9c0e261c23d21fa578 Mon Sep 17 00:00:00 2001 From: Vitaliy Gusev Date: Tue, 15 Apr 2008 00:33:38 -0700 Subject: [TCP]: Fix never pruned tcp out-of-order queue. tcp_prune_queue() doesn't prune an out-of-order queue at all. Therefore sk_rmem_schedule() can fail but the out-of-order queue isn't pruned . This can lead to tcp deadlock state if the next two conditions are held: 1. There are a sequence hole between last received in order segment and segments enqueued to the out-of-order queue. 2. Size of all segments in the out-of-order queue is more than tcp_mem[2]. Signed-off-by: Vitaliy Gusev Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 72 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 5119856017a..61db7b1eb99 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3841,8 +3841,26 @@ static void tcp_ofo_queue(struct sock *sk) } } +static void tcp_prune_ofo_queue(struct sock *sk); static int tcp_prune_queue(struct sock *sk); +static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size) +{ + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || + !sk_rmem_schedule(sk, size)) { + + if (tcp_prune_queue(sk) < 0) + return -1; + + if (!sk_rmem_schedule(sk, size)) { + tcp_prune_ofo_queue(sk); + if (!sk_rmem_schedule(sk, size)) + return -1; + } + } + return 0; +} + static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) { struct tcphdr *th = tcp_hdr(skb); @@ -3892,12 +3910,9 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) if (eaten <= 0) { queue_and_out: if (eaten < 0 && - (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || - !sk_rmem_schedule(sk, skb->truesize))) { - if (tcp_prune_queue(sk) < 0 || - !sk_rmem_schedule(sk, skb->truesize)) - goto drop; - } + tcp_try_rmem_schedule(sk, skb->truesize)) + goto drop; + skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); } @@ -3966,12 +3981,8 @@ drop: TCP_ECN_check_ce(tp, skb); - if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || - !sk_rmem_schedule(sk, skb->truesize)) { - if (tcp_prune_queue(sk) < 0 || - !sk_rmem_schedule(sk, skb->truesize)) - goto drop; - } + if (tcp_try_rmem_schedule(sk, skb->truesize)) + goto drop; /* Disable header prediction. */ tp->pred_flags = 0; @@ -4198,6 +4209,28 @@ static void tcp_collapse_ofo_queue(struct sock *sk) } } +/* + * Purge the out-of-order queue. + */ +static void tcp_prune_ofo_queue(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (!skb_queue_empty(&tp->out_of_order_queue)) { + NET_INC_STATS_BH(LINUX_MIB_OFOPRUNED); + __skb_queue_purge(&tp->out_of_order_queue); + + /* Reset SACK state. A conforming SACK implementation will + * do the same at a timeout based retransmit. When a connection + * is in a sad state like this, we care only about integrity + * of the connection not performance. + */ + if (tp->rx_opt.sack_ok) + tcp_sack_reset(&tp->rx_opt); + sk_mem_reclaim(sk); + } +} + /* Reduce allocated memory if we can, trying to get * the socket within its memory limits again. * @@ -4231,20 +4264,7 @@ static int tcp_prune_queue(struct sock *sk) /* Collapsing did not help, destructive actions follow. * This must not ever occur. */ - /* First, purge the out_of_order queue. */ - if (!skb_queue_empty(&tp->out_of_order_queue)) { - NET_INC_STATS_BH(LINUX_MIB_OFOPRUNED); - __skb_queue_purge(&tp->out_of_order_queue); - - /* Reset SACK state. A conforming SACK implementation will - * do the same at a timeout based retransmit. When a connection - * is in a sad state like this, we care only about integrity - * of the connection not performance. - */ - if (tcp_is_sack(tp)) - tcp_sack_reset(&tp->rx_opt); - sk_mem_reclaim(sk); - } + tcp_prune_ofo_queue(sk); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) return 0; -- cgit v1.2.3-70-g09d2 From 89796f64a20d31e74ee0051df2e26812c852e734 Mon Sep 17 00:00:00 2001 From: Carlos Corbacho Date: Sat, 12 Apr 2008 16:39:47 +0100 Subject: rfkill: Fix device type check when toggling states rfkill_switch_all() is supposed to only switch all the interfaces of a given type, but does not actually do this; instead, it just switches everything currently in the same state. Add the necessary type check in. (This fixes a bug I've been seeing while developing an rfkill laptop driver, with both bluetooth and wireless simultaneously changing state after only pressing either KEY_WLAN or KEY_BLUETOOTH). Signed-off-by: Carlos Corbacho Signed-off-by: John W. Linville --- net/rfkill/rfkill.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 140a0a8c6b0..4e10a95de83 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -92,7 +92,7 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) rfkill_states[type] = state; list_for_each_entry(rfkill, &rfkill_list, node) { - if (!rfkill->user_claim) + if ((!rfkill->user_claim) && (rfkill->type == type)) rfkill_toggle_radio(rfkill, state); } -- cgit v1.2.3-70-g09d2 From b3fc9c6c58c986f7a24fd8b0794d1e0794935a28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 13 Apr 2008 10:12:47 +0200 Subject: mac80211: remove message on receiving unexpected unencrypted frames Some people are getting this message a lot, and we have traced it to broken access points that much too often send completely empty frames (all bytes zeroed, which they shouldn't do at all.) Since we cannot do anything about such frames in any case except the special case where we're debugging an AP, just remove the message. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 535407d07fa..a8a40aba846 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1050,12 +1050,9 @@ ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx) if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && - (rx->key || rx->sdata->drop_unencrypted))) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " - "encryption\n", rx->dev->name); + (rx->key || rx->sdata->drop_unencrypted))) return -EACCES; - } + return 0; } -- cgit v1.2.3-70-g09d2 From 56f367bbfd5a7439961499ca6a2f0822d2074d83 Mon Sep 17 00:00:00 2001 From: Vitaliy Gusev Date: Tue, 15 Apr 2008 20:26:34 -0700 Subject: [TCP]: Add return value indication to tcp_prune_ofo_queue(). Returns non-zero if tp->out_of_order_queue was seen non-empty. This allows tcp_try_rmem_schedule() to return early. Signed-off-by: Vitaliy Gusev Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 61db7b1eb99..bbb7d88a16b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3841,7 +3841,7 @@ static void tcp_ofo_queue(struct sock *sk) } } -static void tcp_prune_ofo_queue(struct sock *sk); +static int tcp_prune_ofo_queue(struct sock *sk); static int tcp_prune_queue(struct sock *sk); static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size) @@ -3853,7 +3853,9 @@ static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size) return -1; if (!sk_rmem_schedule(sk, size)) { - tcp_prune_ofo_queue(sk); + if (!tcp_prune_ofo_queue(sk)) + return -1; + if (!sk_rmem_schedule(sk, size)) return -1; } @@ -4211,10 +4213,12 @@ static void tcp_collapse_ofo_queue(struct sock *sk) /* * Purge the out-of-order queue. + * Return true if queue was pruned. */ -static void tcp_prune_ofo_queue(struct sock *sk) +static int tcp_prune_ofo_queue(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + int res = 0; if (!skb_queue_empty(&tp->out_of_order_queue)) { NET_INC_STATS_BH(LINUX_MIB_OFOPRUNED); @@ -4228,7 +4232,9 @@ static void tcp_prune_ofo_queue(struct sock *sk) if (tp->rx_opt.sack_ok) tcp_sack_reset(&tp->rx_opt); sk_mem_reclaim(sk); + res = 1; } + return res; } /* Reduce allocated memory if we can, trying to get -- cgit v1.2.3-70-g09d2