From f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481b Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Fri, 22 Aug 2008 03:24:05 -0700 Subject: pkt_sched: Fix qdisc list locking Since some qdiscs call qdisc_tree_decrease_qlen() (so qdisc_lookup()) without rtnl_lock(), adding and deleting from a qdisc list needs additional locking. This patch adds global spinlock qdisc_list_lock and wrapper functions for modifying the list. It is considered as a temporary solution until hfsc_dequeue(), netem_dequeue() and tbf_dequeue() (or qdisc_tree_decrease_qlen()) are redone. With feedback from Herbert Xu and David S. Miller. Signed-off-by: Jarek Poplawski Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/sched/sch_api.c | 44 +++++++++++++++++++++++++++++++++++++++----- net/sched/sch_generic.c | 5 ++--- 2 files changed, 41 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 45f442d..e7fb9e0 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -199,19 +199,53 @@ struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) return NULL; } +/* + * This lock is needed until some qdiscs stop calling qdisc_tree_decrease_qlen() + * without rtnl_lock(); currently hfsc_dequeue(), netem_dequeue(), tbf_dequeue() + */ +static DEFINE_SPINLOCK(qdisc_list_lock); + +static void qdisc_list_add(struct Qdisc *q) +{ + if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { + spin_lock_bh(&qdisc_list_lock); + list_add_tail(&q->list, &qdisc_root_sleeping(q)->list); + spin_unlock_bh(&qdisc_list_lock); + } +} + +void qdisc_list_del(struct Qdisc *q) +{ + if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { + spin_lock_bh(&qdisc_list_lock); + list_del(&q->list); + spin_unlock_bh(&qdisc_list_lock); + } +} +EXPORT_SYMBOL(qdisc_list_del); + struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) { unsigned int i; + struct Qdisc *q; + + spin_lock_bh(&qdisc_list_lock); for (i = 0; i < dev->num_tx_queues; i++) { struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - struct Qdisc *q, *txq_root = txq->qdisc_sleeping; + struct Qdisc *txq_root = txq->qdisc_sleeping; q = qdisc_match_from_root(txq_root, handle); if (q) - return q; + goto unlock; } - return qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); + + q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); + +unlock: + spin_unlock_bh(&qdisc_list_lock); + + return q; } static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) @@ -810,8 +844,8 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, goto err_out3; } } - if ((parent != TC_H_ROOT) && !(sch->flags & TCQ_F_INGRESS)) - list_add_tail(&sch->list, &dev_queue->qdisc_sleeping->list); + + qdisc_list_add(sch); return sch; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index c3ed4d4..5f0ade7 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -526,10 +526,9 @@ void qdisc_destroy(struct Qdisc *qdisc) !atomic_dec_and_test(&qdisc->refcnt)) return; - if (qdisc->parent) - list_del(&qdisc->list); - #ifdef CONFIG_NET_SCHED + qdisc_list_del(qdisc); + qdisc_put_stab(qdisc->stab); #endif gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); -- cgit v1.1 From fdc0bde90a689b9145f2b6f271c03f4c99d09667 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sat, 23 Aug 2008 04:43:33 -0700 Subject: icmp: icmp_sk() should not use smp_processor_id() in preemptible code Pass namespace into icmp_xmit_lock, obtain socket inside and return it as a result for caller. Thanks Alexey Dobryan for this report: Steps to reproduce: CONFIG_PREEMPT=y CONFIG_DEBUG_PREEMPT=y tracepath BUG: using smp_processor_id() in preemptible [00000000] code: tracepath/3205 caller is icmp_sk+0x15/0x30 Pid: 3205, comm: tracepath Not tainted 2.6.27-rc4 #1 Call Trace: [] debug_smp_processor_id+0xe4/0xf0 [] icmp_sk+0x15/0x30 [] icmp_send+0x4b/0x3f0 [] ? trace_hardirqs_on_caller+0xd5/0x160 [] ? trace_hardirqs_on+0xd/0x10 [] ? local_bh_enable_ip+0x95/0x110 [] ? _spin_unlock_bh+0x39/0x40 [] ? mark_held_locks+0x4c/0x90 [] ? trace_hardirqs_on+0xd/0x10 [] ? trace_hardirqs_on_caller+0xd5/0x160 [] ip_fragment+0x8d4/0x900 [] ? ip_finish_output2+0x0/0x290 [] ? ip_finish_output+0x0/0x60 [] ? dst_output+0x0/0x10 [] ip_finish_output+0x4c/0x60 [] ip_output+0xa3/0xf0 [] ip_local_out+0x20/0x30 [] ip_push_pending_frames+0x27f/0x400 [] udp_push_pending_frames+0x233/0x3d0 [] udp_sendmsg+0x321/0x6f0 [] inet_sendmsg+0x45/0x80 [] sock_sendmsg+0xdf/0x110 [] ? autoremove_wake_function+0x0/0x40 [] ? validate_chain+0x415/0x1010 [] ? __do_fault+0x140/0x450 [] ? __lock_acquire+0x260/0x590 [] ? sockfd_lookup_light+0x45/0x80 [] sys_sendto+0xea/0x120 [] ? _spin_unlock_irqrestore+0x42/0x80 [] ? __up_read+0x4c/0xb0 [] ? up_read+0x26/0x30 [] system_call_fastpath+0x16/0x1b icmp6_sk() is similar. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 22 ++++++++++++++-------- net/ipv6/icmp.c | 23 ++++++++++++----------- 2 files changed, 26 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 8605586..55c355e 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -204,18 +204,22 @@ static struct sock *icmp_sk(struct net *net) return net->ipv4.icmp_sk[smp_processor_id()]; } -static inline int icmp_xmit_lock(struct sock *sk) +static inline struct sock *icmp_xmit_lock(struct net *net) { + struct sock *sk; + local_bh_disable(); + sk = icmp_sk(net); + if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { /* This can happen if the output path signals a * dst_link_failure() for an outgoing ICMP packet. */ local_bh_enable(); - return 1; + return NULL; } - return 0; + return sk; } static inline void icmp_xmit_unlock(struct sock *sk) @@ -354,15 +358,17 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) struct ipcm_cookie ipc; struct rtable *rt = skb->rtable; struct net *net = dev_net(rt->u.dst.dev); - struct sock *sk = icmp_sk(net); - struct inet_sock *inet = inet_sk(sk); + struct sock *sk; + struct inet_sock *inet; __be32 daddr; if (ip_options_echo(&icmp_param->replyopts, skb)) return; - if (icmp_xmit_lock(sk)) + sk = icmp_xmit_lock(net); + if (sk == NULL) return; + inet = inet_sk(sk); icmp_param->data.icmph.checksum = 0; @@ -419,7 +425,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) if (!rt) goto out; net = dev_net(rt->u.dst.dev); - sk = icmp_sk(net); /* * Find the original header. It is expected to be valid, of course. @@ -483,7 +488,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) } } - if (icmp_xmit_lock(sk)) + sk = icmp_xmit_lock(net); + if (sk == NULL) return; /* diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index abedf95..b3157a0 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -91,19 +91,22 @@ static struct inet6_protocol icmpv6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -static __inline__ int icmpv6_xmit_lock(struct sock *sk) +static __inline__ struct sock *icmpv6_xmit_lock(struct net *net) { + struct sock *sk; + local_bh_disable(); + sk = icmpv6_sk(net); if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { /* This can happen if the output path (f.e. SIT or * ip6ip6 tunnel) signals dst_link_failure() for an * outgoing ICMP6 packet. */ local_bh_enable(); - return 1; + return NULL; } - return 0; + return sk; } static __inline__ void icmpv6_xmit_unlock(struct sock *sk) @@ -392,11 +395,10 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, fl.fl_icmp_code = code; security_skb_classify_flow(skb, &fl); - sk = icmpv6_sk(net); - np = inet6_sk(sk); - - if (icmpv6_xmit_lock(sk)) + sk = icmpv6_xmit_lock(net); + if (sk == NULL) return; + np = inet6_sk(sk); if (!icmpv6_xrlim_allow(sk, type, &fl)) goto out; @@ -539,11 +541,10 @@ static void icmpv6_echo_reply(struct sk_buff *skb) fl.fl_icmp_type = ICMPV6_ECHO_REPLY; security_skb_classify_flow(skb, &fl); - sk = icmpv6_sk(net); - np = inet6_sk(sk); - - if (icmpv6_xmit_lock(sk)) + sk = icmpv6_xmit_lock(net); + if (sk == NULL) return; + np = inet6_sk(sk); if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) fl.oif = np->mcast_oif; -- cgit v1.1 From f410a1fba7afa79d2992620e874a343fdba28332 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 23 Aug 2008 05:16:46 -0700 Subject: ipv6: protocol for address routes This fixes a problem spotted with zebra, but not sure if it is necessary a kernel problem. With IPV6 when an address is added to an interface, Zebra creates a duplicate RIB entry, one as a connected route, and other as a kernel route. When an address is added to an interface the RTN_NEWADDR message causes Zebra to create a connected route. In IPV4 when an address is added to an interface a RTN_NEWROUTE message is set to user space with the protocol RTPROT_KERNEL. Zebra ignores these messages, because it already has the connected route. The problem is that route created in IPV6 has route protocol == RTPROT_BOOT. Was this a design decision or a bug? This fixes it. Same patch applies to both net-2.6 and stable. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e2d3b758..7b6a584 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1688,6 +1688,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, .fc_dst_len = plen, .fc_flags = RTF_UP | flags, .fc_nlinfo.nl_net = dev_net(dev), + .fc_protocol = RTPROT_KERNEL, }; ipv6_addr_copy(&cfg.fc_dst, pfx); -- cgit v1.1 From 30c2235cbc477d4629983d440cdc4f496fec9246 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 25 Aug 2008 15:16:19 -0700 Subject: sctp: add verification checks to SCTP_AUTH_KEY option The structure used for SCTP_AUTH_KEY option contains a length that needs to be verfied to prevent buffer overflow conditions. Spoted by Eugene Teo . Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/auth.c | 4 ++++ net/sctp/socket.c | 5 +++++ 2 files changed, 9 insertions(+) (limited to 'net') diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 675a5c3..1fcb4cf 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -80,6 +80,10 @@ static struct sctp_auth_bytes *sctp_auth_create_key(__u32 key_len, gfp_t gfp) { struct sctp_auth_bytes *key; + /* Verify that we are not going to overflow INT_MAX */ + if ((INT_MAX - key_len) < sizeof(struct sctp_auth_bytes)) + return NULL; + /* Allocate the shared key */ key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); if (!key) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index bb5c9ef..afa952e 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3144,6 +3144,11 @@ static int sctp_setsockopt_auth_key(struct sock *sk, goto out; } + if (authkey->sca_keylength > optlen) { + ret = -EINVAL; + goto out; + } + asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { ret = -EINVAL; -- cgit v1.1 From 2f4520d35d89ca6c5cd129c38e3b11f0283b7d1b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Aug 2008 15:17:44 -0700 Subject: ipv4: sysctl fixes net.ipv4.neigh should be a part of skeleton to avoid ordering problems Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/route.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cca921e..e91bafe 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3116,14 +3116,23 @@ static ctl_table ipv4_route_table[] = { { .ctl_name = 0 } }; -static __net_initdata struct ctl_path ipv4_route_path[] = { +static struct ctl_table empty[1]; + +static struct ctl_table ipv4_skeleton[] = +{ + { .procname = "route", .ctl_name = NET_IPV4_ROUTE, + .child = ipv4_route_table}, + { .procname = "neigh", .ctl_name = NET_IPV4_NEIGH, + .child = empty}, + { } +}; + +static __net_initdata struct ctl_path ipv4_path[] = { { .procname = "net", .ctl_name = CTL_NET, }, { .procname = "ipv4", .ctl_name = NET_IPV4, }, - { .procname = "route", .ctl_name = NET_IPV4_ROUTE, }, { }, }; - static struct ctl_table ipv4_route_flush_table[] = { { .ctl_name = NET_IPV4_ROUTE_FLUSH, @@ -3136,6 +3145,13 @@ static struct ctl_table ipv4_route_flush_table[] = { { .ctl_name = 0 }, }; +static __net_initdata struct ctl_path ipv4_route_path[] = { + { .procname = "net", .ctl_name = CTL_NET, }, + { .procname = "ipv4", .ctl_name = NET_IPV4, }, + { .procname = "route", .ctl_name = NET_IPV4_ROUTE, }, + { }, +}; + static __net_init int sysctl_route_net_init(struct net *net) { struct ctl_table *tbl; @@ -3287,7 +3303,7 @@ int __init ip_rt_init(void) */ void __init ip_static_sysctl_init(void) { - register_sysctl_paths(ipv4_route_path, ipv4_route_table); + register_sysctl_paths(ipv4_path, ipv4_skeleton); } #endif -- cgit v1.1 From ce3113ec57abcd41cc5a2fed02474aee3f63d12c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Aug 2008 15:18:15 -0700 Subject: ipv6: sysctl fixes Braino: net.ipv6 in ipv6 skeleton has no business in rotable class Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv6/sysctl_net_ipv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index e6dfaea..587f8f6 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -156,7 +156,7 @@ static struct ctl_table_header *ip6_base; int ipv6_static_sysctl_register(void) { static struct ctl_table empty[1]; - ip6_base = register_net_sysctl_rotable(net_ipv6_ctl_path, empty); + ip6_base = register_sysctl_paths(net_ipv6_ctl_path, empty); if (ip6_base == NULL) return -ENOMEM; return 0; -- cgit v1.1 From 988b02f1bf5b608ef91a9d98c7170d037d0f12e3 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 18 Aug 2008 22:56:53 +0300 Subject: net: rfkill: add missing line break Trivial patch adding a missing line break on rfkill_claim_show(). Signed-off-by: Felipe Balbi Acked-by: Ivo van Doorn 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 35a9994..74aecc0 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -377,7 +377,7 @@ static ssize_t rfkill_claim_show(struct device *dev, { struct rfkill *rfkill = to_rfkill(dev); - return sprintf(buf, "%d", rfkill->user_claim); + return sprintf(buf, "%d\n", rfkill->user_claim); } static ssize_t rfkill_claim_store(struct device *dev, -- cgit v1.1 From 087d833e5a9f67ba933cb32eaf5a2279c1a5b47c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 Aug 2008 10:54:32 +0300 Subject: mac80211: Use IWEVASSOCREQIE instead of IWEVCUSTOM The previous code was using IWEVCUSTOM to report IEs from AssocReq and AssocResp frames into user space. This can easily hit the 256 byte limit (IW_CUSTOM_MAX) with APs that include number of vendor IEs in AssocResp. This results in the event message not being sent and dmesg showing "wlan0 (WE) : Wireless Event too big (366)" type of errors. Convert mac80211 to use IWEVASSOCREQIE/IWEVASSOCRESPIE to avoid the issue of being unable to send association IEs as wireless events. These newer event types use binary encoding and larger maximum size (IW_GENERIC_IE_MAX = 1024), so the likelyhood of not being able to send the IEs is much smaller than with IWEVCUSTOM. As an extra benefit, the code is also quite a bit simpler since there is no need to allocate an extra buffer for hex encoding. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 48 +++++++++--------------------------------------- 1 file changed, 9 insertions(+), 39 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1e97fb9..09a56e2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -478,51 +478,21 @@ int ieee80211_ht_addt_info_ie_to_ht_bss_info( static void ieee80211_sta_send_associnfo(struct net_device *dev, struct ieee80211_if_sta *ifsta) { - char *buf; - size_t len; - int i; union iwreq_data wrqu; - if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) - return; - - buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + - ifsta->assocresp_ies_len), GFP_KERNEL); - if (!buf) - return; - - len = sprintf(buf, "ASSOCINFO("); if (ifsta->assocreq_ies) { - len += sprintf(buf + len, "ReqIEs="); - for (i = 0; i < ifsta->assocreq_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifsta->assocreq_ies[i]); - } - } - if (ifsta->assocresp_ies) { - if (ifsta->assocreq_ies) - len += sprintf(buf + len, " "); - len += sprintf(buf + len, "RespIEs="); - for (i = 0; i < ifsta->assocresp_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifsta->assocresp_ies[i]); - } + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = ifsta->assocreq_ies_len; + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, + ifsta->assocreq_ies); } - len += sprintf(buf + len, ")"); - if (len > IW_CUSTOM_MAX) { - len = sprintf(buf, "ASSOCRESPIE="); - for (i = 0; i < ifsta->assocresp_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifsta->assocresp_ies[i]); - } + if (ifsta->assocresp_ies) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = ifsta->assocresp_ies_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, + ifsta->assocresp_ies); } - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = len; - wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); - - kfree(buf); } -- cgit v1.1 From 667d8af9af775a5fea203890978037ea750816cc Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2008 18:27:38 +0200 Subject: net/mac80211/mesh.c: correct the argument to __mesh_table_free In the function mesh_table_grow, it is the new table not the argument table that should be freed if the function fails (cf commit bd9b448f4c0a514559bdae4ca18ca3e8cd999c6d) The semantic match that detects this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E,f; position p1,p2,p3; identifier l; statement S; @@ x = mesh_table_alloc@p1(...) ... if (x == NULL) S ... when != E = x when != mesh_table_free(x) goto@p2 l; ... when != E = x when != f(...,x,...) when any ( return \(0\|x\); | return@p3 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; p3 << r.p3; @@ print "%s: call on line %s not freed or saved before return on line %s via line %s" % (p1[0].file,p1[0].line,p3[0].line,p2[0].line) // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b5933b2..35f2f95 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -383,7 +383,7 @@ errcopy: hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) tbl->free_node(p, 0); } - __mesh_table_free(tbl); + __mesh_table_free(newtbl); endgrow: return NULL; } -- cgit v1.1 From 93015f0f34e81a47c4126329746ce5f364bafd11 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 25 Aug 2008 11:57:06 +0300 Subject: mac80211: Fix debugfs file add/del for netdev Previous version was using incorrect union structures for non-AP interfaces when adding and removing max_ratectrl_rateidx and force_unicast_rateidx entries. Depending on the vif type, this ended up in corrupting debugfs entries since the dentries inside different union structures ended up going being on top of eachother.. As the end result, debugfs files were being left behind with references to freed data (instant kernel oops on access) and directories were not removed properly when unloading mac80211 drivers. This patch fixes those issues by using only a single union structure based on the vif type. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 24 ++++++++++++------------ net/mac80211/ieee80211_i.h | 6 ++++++ 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 475f89a..8165df5 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -248,8 +248,8 @@ IEEE80211_IF_WFILE(min_discovery_timeout, static void add_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted, sta); - DEBUGFS_ADD(force_unicast_rateidx, ap); - DEBUGFS_ADD(max_ratectrl_rateidx, ap); + DEBUGFS_ADD(force_unicast_rateidx, sta); + DEBUGFS_ADD(max_ratectrl_rateidx, sta); DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); @@ -283,8 +283,8 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) static void add_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted, wds); - DEBUGFS_ADD(force_unicast_rateidx, ap); - DEBUGFS_ADD(max_ratectrl_rateidx, ap); + DEBUGFS_ADD(force_unicast_rateidx, wds); + DEBUGFS_ADD(max_ratectrl_rateidx, wds); DEBUGFS_ADD(peer, wds); } @@ -292,8 +292,8 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata) static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted, vlan); - DEBUGFS_ADD(force_unicast_rateidx, ap); - DEBUGFS_ADD(max_ratectrl_rateidx, ap); + DEBUGFS_ADD(force_unicast_rateidx, vlan); + DEBUGFS_ADD(max_ratectrl_rateidx, vlan); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -381,8 +381,8 @@ static void add_files(struct ieee80211_sub_if_data *sdata) static void del_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(drop_unencrypted, sta); - DEBUGFS_DEL(force_unicast_rateidx, ap); - DEBUGFS_DEL(max_ratectrl_rateidx, ap); + DEBUGFS_DEL(force_unicast_rateidx, sta); + DEBUGFS_DEL(max_ratectrl_rateidx, sta); DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); @@ -416,8 +416,8 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata) static void del_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(drop_unencrypted, wds); - DEBUGFS_DEL(force_unicast_rateidx, ap); - DEBUGFS_DEL(max_ratectrl_rateidx, ap); + DEBUGFS_DEL(force_unicast_rateidx, wds); + DEBUGFS_DEL(max_ratectrl_rateidx, wds); DEBUGFS_DEL(peer, wds); } @@ -425,8 +425,8 @@ static void del_wds_files(struct ieee80211_sub_if_data *sdata) static void del_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(drop_unencrypted, vlan); - DEBUGFS_DEL(force_unicast_rateidx, ap); - DEBUGFS_DEL(max_ratectrl_rateidx, ap); + DEBUGFS_DEL(force_unicast_rateidx, vlan); + DEBUGFS_DEL(max_ratectrl_rateidx, vlan); } static void del_monitor_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ec59345..586a9b4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -470,6 +470,8 @@ struct ieee80211_sub_if_data { struct dentry *auth_transaction; struct dentry *flags; struct dentry *num_beacons_sta; + struct dentry *force_unicast_rateidx; + struct dentry *max_ratectrl_rateidx; } sta; struct { struct dentry *drop_unencrypted; @@ -483,9 +485,13 @@ struct ieee80211_sub_if_data { struct { struct dentry *drop_unencrypted; struct dentry *peer; + struct dentry *force_unicast_rateidx; + struct dentry *max_ratectrl_rateidx; } wds; struct { struct dentry *drop_unencrypted; + struct dentry *force_unicast_rateidx; + struct dentry *max_ratectrl_rateidx; } vlan; struct { struct dentry *mode; -- cgit v1.1 From 8ab65b03b7893da4a49009e7e356e36e27b0c407 Mon Sep 17 00:00:00 2001 From: Jan-Espen Pettersen Date: Mon, 25 Aug 2008 20:29:22 +0200 Subject: mac80211: don't send empty extended rates IE The association request includes a list of supported data rates. 802.11b: 4 supported rates. 802.11g: 12 (8 + 4) supported rates. 802.11a: 8 supported rates. The rates tag of the assoc request has room for only 8 rates. In case of 802.11g an extended rate tag is appended. However in net/wireless/mlme.c an extended (empty) rate tag is also appended if the number of rates is exact 8. This empty (length=0) extended rates tag causes some APs to deny association with code 18 (unsupported rates). These APs include my ZyXEL G-570U, and according to Tomas Winkler som Cisco APs. 'If count == 8' has been used to check for the need for an extended rates tag. But count would also be equal to 8 if the for loop exited because of no more supported rates. Therefore a check for count being less than rates_len would seem more correct. Thanks to: * Dan Williams for newbie guidance * Tomas Winkler for confirming the problem Signed-off-by: Jan-Espen Pettersen Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 09a56e2..74777ad 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -783,7 +783,7 @@ static void ieee80211_send_assoc(struct net_device *dev, } } - if (count == 8) { + if (rates_len > count) { pos = skb_put(skb, rates_len - count + 2); *pos++ = WLAN_EID_EXT_SUPP_RATES; *pos++ = rates_len - count; -- cgit v1.1 From 576fdeaef631976c3afcb1d78ef196051282611d Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 26 Aug 2008 20:33:34 -0400 Subject: mac80211: quiet chatty IBSS merge message It seems obvious that this #ifndef should be the opposite polarity... Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 74777ad..9bb68c6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2838,7 +2838,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, jiffies); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (beacon_timestamp > rx_timestamp) { -#ifndef CONFIG_MAC80211_IBSS_DEBUG +#ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: beacon TSF higher than " "local TSF - IBSS merge with BSSID %s\n", dev->name, print_mac(mac, mgmt->bssid)); -- cgit v1.1 From 666d9bbedfff7c2c37eab92e715641922dee6864 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Wed, 27 Aug 2008 02:12:52 -0700 Subject: pkt_sched: Fix dev_graft_qdisc() locking During dev_graft_qdisc() dev is deactivated, so qdisc_root_lock() returns wrong lock of noop_qdisc instead of qdisc_sleeping. Signed-off-by: Jarek Poplawski Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/sched/sch_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index e7fb9e0..341d558 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -624,7 +624,7 @@ static struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, struct Qdisc *oqdisc = dev_queue->qdisc_sleeping; spinlock_t *root_lock; - root_lock = qdisc_root_lock(oqdisc); + root_lock = qdisc_lock(oqdisc); spin_lock_bh(root_lock); /* Prune old scheduler */ -- cgit v1.1 From f7a54c13c7b072d9426bd5cec1cdb8306df5ef55 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Wed, 27 Aug 2008 02:22:07 -0700 Subject: pkt_sched: Use rcu_assign_pointer() to change dev_queue->qdisc These pointers are RCU protected, so proper primitives should be used. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/sched/sch_api.c | 2 +- net/sched/sch_generic.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 341d558..ad9cda1 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -635,7 +635,7 @@ static struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, if (qdisc == NULL) qdisc = &noop_qdisc; dev_queue->qdisc_sleeping = qdisc; - dev_queue->qdisc = &noop_qdisc; + rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc); spin_unlock_bh(root_lock); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 5f0ade7..9634091 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -634,7 +634,7 @@ static void dev_deactivate_queue(struct net_device *dev, if (!(qdisc->flags & TCQ_F_BUILTIN)) set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state); - dev_queue->qdisc = qdisc_default; + rcu_assign_pointer(dev_queue->qdisc, qdisc_default); qdisc_reset(qdisc); spin_unlock_bh(qdisc_lock(qdisc)); @@ -709,7 +709,7 @@ static void shutdown_scheduler_queue(struct net_device *dev, struct Qdisc *qdisc_default = _qdisc_default; if (qdisc) { - dev_queue->qdisc = qdisc_default; + rcu_assign_pointer(dev_queue->qdisc, qdisc_default); dev_queue->qdisc_sleeping = qdisc_default; qdisc_destroy(qdisc); -- cgit v1.1 From f6f9b93f1624206c802ac9162c9302edaf59bfd9 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Wed, 27 Aug 2008 02:25:17 -0700 Subject: pkt_sched: Fix gen_estimator locks While passing a qdisc root lock to gen_new_estimator() and gen_replace_estimator() dev could be deactivated or even before grafting proper root qdisc as qdisc_sleeping (e.g. qdisc_create), so using qdisc_root_lock() is not enough. This patch adds qdisc_root_sleeping_lock() for this, plus additional checks, where necessary. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/sched/sch_api.c | 14 +++++++++++--- net/sched/sch_cbq.c | 4 ++-- net/sched/sch_hfsc.c | 4 ++-- net/sched/sch_htb.c | 4 ++-- 4 files changed, 17 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index ad9cda1..506b709 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -830,9 +830,16 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, sch->stab = stab; } if (tca[TCA_RATE]) { + spinlock_t *root_lock; + + if ((sch->parent != TC_H_ROOT) && + !(sch->flags & TCQ_F_INGRESS)) + root_lock = qdisc_root_sleeping_lock(sch); + else + root_lock = qdisc_lock(sch); + err = gen_new_estimator(&sch->bstats, &sch->rate_est, - qdisc_root_lock(sch), - tca[TCA_RATE]); + root_lock, tca[TCA_RATE]); if (err) { /* * Any broken qdiscs that would require @@ -884,7 +891,8 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) if (tca[TCA_RATE]) gen_replace_estimator(&sch->bstats, &sch->rate_est, - qdisc_root_lock(sch), tca[TCA_RATE]); + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); return 0; } diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 8fa90d6..9b720ad 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1839,7 +1839,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_lock(sch), + qdisc_root_sleeping_lock(sch), tca[TCA_RATE]); return 0; } @@ -1930,7 +1930,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (tca[TCA_RATE]) gen_new_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_lock(sch), tca[TCA_RATE]); + qdisc_root_sleeping_lock(sch), tca[TCA_RATE]); *arg = (unsigned long)cl; return 0; diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index c2b8d9c..c1e77da 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1045,7 +1045,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_lock(sch), + qdisc_root_sleeping_lock(sch), tca[TCA_RATE]); return 0; } @@ -1104,7 +1104,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (tca[TCA_RATE]) gen_new_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_lock(sch), tca[TCA_RATE]); + qdisc_root_sleeping_lock(sch), tca[TCA_RATE]); *arg = (unsigned long)cl; return 0; } diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 0df0df2..97d4761 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1372,7 +1372,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, goto failure; gen_new_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_lock(sch), + qdisc_root_sleeping_lock(sch), tca[TCA_RATE] ? : &est.nla); cl->refcnt = 1; cl->children = 0; @@ -1427,7 +1427,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, } else { if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_lock(sch), + qdisc_root_sleeping_lock(sch), tca[TCA_RATE]); sch_tree_lock(sch); } -- cgit v1.1 From 7982d5e1b350acb96aa156916c44c25ef87bb809 Mon Sep 17 00:00:00 2001 From: Philip Love Date: Wed, 27 Aug 2008 02:33:50 -0700 Subject: tcp: fix tcp header size miscalculation when window scale is unused The size of the TCP header is miscalculated when the window scale ends up being 0. Additionally, this can be induced by sending a SYN to a passive open port with a window scale option with value 0. Signed-off-by: Philip Love Signed-off-by: Adam Langley Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a00532d..8165f5a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -468,7 +468,8 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, } if (likely(sysctl_tcp_window_scaling)) { opts->ws = tp->rx_opt.rcv_wscale; - size += TCPOLEN_WSCALE_ALIGNED; + if(likely(opts->ws)) + size += TCPOLEN_WSCALE_ALIGNED; } if (likely(sysctl_tcp_sack)) { opts->options |= OPTION_SACK_ADVERTISE; @@ -509,7 +510,8 @@ static unsigned tcp_synack_options(struct sock *sk, if (likely(ireq->wscale_ok)) { opts->ws = ireq->rcv_wscale; - size += TCPOLEN_WSCALE_ALIGNED; + if(likely(opts->ws)) + size += TCPOLEN_WSCALE_ALIGNED; } if (likely(doing_ts)) { opts->options |= OPTION_TS; -- cgit v1.1 From d994af0d50efc96b2077978fe9f066992639d525 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 27 Aug 2008 02:35:18 -0700 Subject: ipv4: mode 0555 in ipv4_skeleton vpnc on today's kernel says Cannot open "/proc/sys/net/ipv4/route/flush": d--------- 0 root root 0 2008-08-26 11:32 /proc/sys/net/ipv4/route d--------- 0 root root 0 2008-08-26 19:16 /proc/sys/net/ipv4/neigh Signed-off-by: Hugh Dickins Acked-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index e91bafe..6ee5354 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3121,9 +3121,9 @@ static struct ctl_table empty[1]; static struct ctl_table ipv4_skeleton[] = { { .procname = "route", .ctl_name = NET_IPV4_ROUTE, - .child = ipv4_route_table}, + .mode = 0555, .child = ipv4_route_table}, { .procname = "neigh", .ctl_name = NET_IPV4_NEIGH, - .child = empty}, + .mode = 0555, .child = empty}, { } }; -- cgit v1.1 From 328fc47ea0bcc27d9afa69c3ad6e52431cadd76c Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 27 Aug 2008 16:08:54 -0700 Subject: sctp: correct bounds check in sctp_setsockopt_auth_key The bonds check to prevent buffer overlflow was not exactly right. It still allowed overflow of up to 8 bytes which is sizeof(struct sctp_authkey). Since optlen is already checked against the size of that struct, we are guaranteed not to cause interger overflow either. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index afa952e..9b9b2c3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3144,7 +3144,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk, goto out; } - if (authkey->sca_keylength > optlen) { + if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { ret = -EINVAL; goto out; } -- cgit v1.1 From d97240552cd98c4b07322f30f66fd9c3ba4171de Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 27 Aug 2008 16:09:49 -0700 Subject: sctp: fix random memory dereference with SCTP_HMAC_IDENT option. The number of identifiers needs to be checked against the option length. Also, the identifier index provided needs to be verified to make sure that it doesn't exceed the bounds of the array. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/auth.c | 3 +++ net/sctp/socket.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 1fcb4cf..52db5f6 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -786,6 +786,9 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, for (i = 0; i < hmacs->shmac_num_idents; i++) { id = hmacs->shmac_idents[i]; + if (id > SCTP_AUTH_HMAC_ID_MAX) + return -EOPNOTSUPP; + if (SCTP_AUTH_HMAC_ID_SHA1 == id) has_sha1 = 1; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9b9b2c3..5ffb9de 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3086,6 +3086,7 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, int optlen) { struct sctp_hmacalgo *hmacs; + u32 idents; int err; if (!sctp_auth_enable) @@ -3103,8 +3104,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, goto out; } - if (hmacs->shmac_num_idents == 0 || - hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) { + idents = hmacs->shmac_num_idents; + if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || + (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) { err = -EINVAL; goto out; } -- cgit v1.1 From 3cc76caa98b092a8fb3e7b4303c70f847db0651f Mon Sep 17 00:00:00 2001 From: Yang Hongyang Date: Fri, 29 Aug 2008 14:06:51 -0700 Subject: ipv6: When we droped a packet, we should return NET_RX_DROP instead of 0 Signed-off-by: Yang Hongyang Signed-off-by: David S. Miller --- net/ipv6/raw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 01d4767..e53e493 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -377,14 +377,14 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) skb_checksum_complete(skb)) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } /* Charge it to the socket. */ if (sock_queue_rcv_skb(sk,skb)<0) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } return 0; @@ -429,7 +429,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) if (skb_checksum_complete(skb)) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } } -- cgit v1.1 From 102396ae65108b026e4e1868e30fa013f45a169e Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Fri, 29 Aug 2008 14:21:52 -0700 Subject: pkt_sched: Fix locking of qdisc_root with qdisc_root_sleeping_lock() Use qdisc_root_sleeping_lock() instead of qdisc_root_lock() where appropriate. The only difference is while dev is deactivated, when currently we can use a sleeping qdisc with the lock of noop_qdisc. This shouldn't be dangerous since after deactivation root lock could be used only by gen_estimator code, but looks wrong anyway. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/sched/cls_api.c | 2 +- net/sched/cls_route.c | 2 +- net/sched/sch_api.c | 8 ++++---- net/sched/sch_cbq.c | 2 +- net/sched/sch_htb.c | 4 ++-- net/sched/sch_netem.c | 2 +- net/sched/sch_teql.c | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 5cafdd4..8eb79e9 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -205,7 +205,7 @@ replay: } } - root_lock = qdisc_root_lock(q); + root_lock = qdisc_root_sleeping_lock(q); if (tp == NULL) { /* Proto-tcf does not exist, create new one */ diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 481260a..e3d8455 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -75,7 +75,7 @@ static __inline__ int route4_fastmap_hash(u32 id, int iif) static inline void route4_reset_fastmap(struct Qdisc *q, struct route4_head *head, u32 id) { - spinlock_t *root_lock = qdisc_root_lock(q); + spinlock_t *root_lock = qdisc_root_sleeping_lock(q); spin_lock_bh(root_lock); memset(head->fastmap, 0, sizeof(head->fastmap)); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 506b709..1122c95 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1169,8 +1169,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) goto nla_put_failure; - if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, - TCA_XSTATS, qdisc_root_lock(q), &d) < 0) + if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, + qdisc_root_sleeping_lock(q), &d) < 0) goto nla_put_failure; if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) @@ -1461,8 +1461,8 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0) goto nla_put_failure; - if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, - TCA_XSTATS, qdisc_root_lock(q), &d) < 0) + if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, + qdisc_root_sleeping_lock(q), &d) < 0) goto nla_put_failure; if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 9b720ad..8b06fa9 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1754,7 +1754,7 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg) if (--cl->refcnt == 0) { #ifdef CONFIG_NET_CLS_ACT - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct cbq_sched_data *q = qdisc_priv(sch); spin_lock_bh(root_lock); diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 97d4761..d14f020 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1043,7 +1043,7 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct htb_sched *q = qdisc_priv(sch); struct nlattr *nest; struct tc_htb_glob gopt; @@ -1075,7 +1075,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct htb_class *cl = (struct htb_class *)arg; - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct nlattr *nest; struct tc_htb_opt opt; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index fb0294d..3781e55 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -341,7 +341,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) for (i = 0; i < n; i++) d->table[i] = data[i]; - root_lock = qdisc_root_lock(sch); + root_lock = qdisc_root_sleeping_lock(sch); spin_lock_bh(root_lock); d = xchg(&q->delay_dist, d); diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 2c35c67..d35ef05 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -161,7 +161,7 @@ teql_destroy(struct Qdisc* sch) txq = netdev_get_tx_queue(master->dev, 0); master->slaves = NULL; - root_lock = qdisc_root_lock(txq->qdisc); + root_lock = qdisc_root_sleeping_lock(txq->qdisc); spin_lock_bh(root_lock); qdisc_reset(txq->qdisc); spin_unlock_bh(root_lock); -- cgit v1.1