From 3ba08b00e0d8413d79be9cab8ec085ceb6ae6fd6 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Sat, 3 May 2008 20:46:29 -0700 Subject: sch_htb: remove from event queue in htb_parent_to_leaf() There is lack of removing a class from the event queue while changing from parent to leaf which can cause corruption of this rb tree. This patch fixes a bug introduced by my patch: "sch_htb: turn intermediate classes into leaves" commit: 160d5e10f87b1dc88fd9b84b31b1718e0fd76398. Many thanks to Jan 'yanek' Bortl for finding a way to reproduce this rare bug and narrowing the test case, which made possible proper diagnosing. This patch is recommended for all kernels starting from 2.6.20. Reported-and-tested-by: Jan 'yanek' Bortl Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 66148cc4759e..5bc1ed490180 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1197,12 +1197,16 @@ static inline int htb_parent_last_child(struct htb_class *cl) return 1; } -static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q) +static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl, + struct Qdisc *new_q) { struct htb_class *parent = cl->parent; BUG_TRAP(!cl->level && cl->un.leaf.q && !cl->prio_activity); + if (parent->cmode != HTB_CAN_SEND) + htb_safe_rb_erase(&parent->pq_node, q->wait_pq + parent->level); + parent->level = 0; memset(&parent->un.inner, 0, sizeof(parent->un.inner)); INIT_LIST_HEAD(&parent->un.leaf.drop_list); @@ -1300,7 +1304,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) htb_deactivate(q, cl); if (last_child) - htb_parent_to_leaf(cl, new_q); + htb_parent_to_leaf(q, cl, new_q); if (--cl->refcnt == 0) htb_destroy_class(sch, cl); -- cgit v1.2.3 From c8005785102e5b67ecf213f06a3d6c001f6f8cb4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 3 May 2008 20:56:42 -0700 Subject: net: Fix useless comment reference loop. include/linux/skbuff.h says: /* These elements must be at the end, see alloc_skb() for details. */ net/core/skbuff.c says: * See comment in sk_buff definition, just before the 'tail' member This patch contains my guess as to the actual reason rather than a dead comment reference loop. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- net/core/skbuff.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4fe605fa6f8a..5c459f2b7985 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -200,7 +200,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, goto nodata; /* - * See comment in sk_buff definition, just before the 'tail' member + * Only clear those fields we need to clear, not those that we will + * actually initialise below. Hence, don't put any more fields after + * the tail pointer in struct sk_buff! */ memset(skb, 0, offsetof(struct sk_buff, tail)); skb->truesize = size + sizeof(struct sk_buff); -- cgit v1.2.3 From c37aa90b0458d87342e0bb083f6bf7d113220d09 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 4 May 2008 17:57:29 -0700 Subject: bridge: Net device leak in br_add_bridge(). In case the register_netdevice() call fails the device is leaked, since the out: label is just rtnl_unlock()+return. Free the device. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/bridge/br_if.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 77a981a1ee52..bff0f5bb12be 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -280,8 +280,10 @@ int br_add_bridge(const char *name) } ret = register_netdevice(dev); - if (ret) + if (ret) { + free_netdev(dev); goto out; + } ret = br_sysfs_addbr(dev); if (ret) -- cgit v1.2.3 From e340a90e6e07bba6e6b3fc39dd5fa76f95579d7c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 4 May 2008 17:58:07 -0700 Subject: bridge: Consolidate error paths in br_add_bridge(). This actually had to be merged with the patch #1, but I decided not to mix two changes in one patch. There are already two calls to free_netdev() in there, so merge them into one. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/bridge/br_if.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index bff0f5bb12be..c2397f503b0f 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -273,17 +273,13 @@ int br_add_bridge(const char *name) rtnl_lock(); if (strchr(dev->name, '%')) { ret = dev_alloc_name(dev, dev->name); - if (ret < 0) { - free_netdev(dev); - goto out; - } + if (ret < 0) + goto out_free; } ret = register_netdevice(dev); - if (ret) { - free_netdev(dev); - goto out; - } + if (ret) + goto out_free; ret = br_sysfs_addbr(dev); if (ret) @@ -291,6 +287,10 @@ int br_add_bridge(const char *name) out: rtnl_unlock(); return ret; + +out_free: + free_netdev(dev); + goto out; } int br_del_bridge(const char *name) -- cgit v1.2.3 From 339a7c41c913035bf58579f6e47b4ba29da83795 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 4 May 2008 17:59:30 -0700 Subject: mac80211: Do not free net device after it is unregistered. The error path in ieee80211_register_hw() may call the unregister_netdev() and right after it - the free_netdev(), which is wrong, since the unregister releases the device itself. So the proposed fix is to NULL the local->mdev after unregister is done and check this before calling free_netdev(). I checked - no code uses the local->mdev after unregister in this error path (but even if some did this would be a BUG). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/mac80211/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9ad4e3631b6b..915afadb0602 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1766,6 +1766,7 @@ fail_wep: fail_rate: ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); unregister_netdevice(local->mdev); + local->mdev = NULL; fail_dev: rtnl_unlock(); sta_info_stop(local); @@ -1773,8 +1774,10 @@ fail_sta_info: debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue); fail_workqueue: - ieee80211_if_free(local->mdev); - local->mdev = NULL; + if (local->mdev != NULL) { + ieee80211_if_free(local->mdev); + local->mdev = NULL; + } fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); return result; -- cgit v1.2.3 From 65e4113684e50cee75357ce10dc9026b0929e4e9 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 4 May 2008 18:00:05 -0700 Subject: atm: Do not free already unregistered net device. Both br2684_push and br2684_exit do so, but unregister_netdev() releases the device itself. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/atm/br2684.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 1b228065e745..3a74ff8ca45d 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -350,7 +350,6 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) list_del(&brdev->br2684_devs); read_unlock(&devs_lock); unregister_netdev(net_dev); - free_netdev(net_dev); } return; } @@ -771,7 +770,6 @@ static void __exit br2684_exit(void) list_del(&brdev->br2684_devs); unregister_netdev(net_dev); - free_netdev(net_dev); } } -- cgit v1.2.3 From 1e0ba0060ffcee2e766ec3159196235b1a2a0ff3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 4 May 2008 18:00:36 -0700 Subject: atm: Bad locking on br2684_devs modifications. The list_del happens under read-locked devs_lock. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/atm/br2684.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 3a74ff8ca45d..13858e2675c5 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -346,9 +346,9 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) /* skb==NULL means VCC is being destroyed */ br2684_close_vcc(brvcc); if (list_empty(&brdev->brvccs)) { - read_lock(&devs_lock); + write_lock_irq(&devs_lock); list_del(&brdev->br2684_devs); - read_unlock(&devs_lock); + write_unlock_irq(&devs_lock); unregister_netdev(net_dev); } return; -- cgit v1.2.3 From 0bbeafd0118fc3ae54990064760c889d41dc21d6 Mon Sep 17 00:00:00 2001 From: Satoru SATOH Date: Sun, 4 May 2008 22:12:43 -0700 Subject: ip: Make use of the inline function dst_metric_locked() Signed-off-by: Satoru SATOH Signed-off-by: David S. Miller --- include/net/ip.h | 2 +- net/ipv4/route.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/ip.h b/include/net/ip.h index 6d7bcd5e62d4..3b40bc2234be 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -210,7 +210,7 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst) { return (inet_sk(sk)->pmtudisc == IP_PMTUDISC_DO || (inet_sk(sk)->pmtudisc == IP_PMTUDISC_WANT && - !(dst_metric(dst, RTAX_LOCK)&(1<u.dst.metrics)); if (fi->fib_mtu == 0) { rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu; - if (rt->u.dst.metrics[RTAX_LOCK-1] & (1 << RTAX_MTU) && + if (dst_metric_locked(&rt->u.dst, RTAX_MTU) && rt->rt_gateway != rt->rt_dst && rt->u.dst.dev->mtu > 576) rt->u.dst.metrics[RTAX_MTU-1] = 576; -- cgit v1.2.3 From 5ffc02a158997b1eb91ade8d02bcf521ff79a218 Mon Sep 17 00:00:00 2001 From: Satoru SATOH Date: Sun, 4 May 2008 22:14:42 -0700 Subject: ip: Use inline function dst_metric() instead of direct access to dst->metric[] There are functions to refer to the value of dst->metric[THE_METRIC-1] directly without use of a inline function "dst_metric" defined in net/dst.h. The following patch changes them to use the inline function consistently. Signed-off-by: Satoru SATOH Signed-off-by: David S. Miller --- net/decnet/dn_route.c | 12 ++++++------ net/ipv4/route.c | 16 ++++++++-------- net/ipv4/tcp_input.c | 15 ++++++++------- net/ipv6/route.c | 6 +++--- 4 files changed, 25 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 2f665a516476..f50e88bf2661 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -235,14 +235,14 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu) else min_mtu -= 21; - if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) { + if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= min_mtu) { if (!(dst_metric_locked(dst, RTAX_MTU))) { dst->metrics[RTAX_MTU-1] = mtu; dst_set_expires(dst, dn_rt_mtu_expires); } if (!(dst_metric_locked(dst, RTAX_ADVMSS))) { u32 mss = mtu - DN_MAX_NSP_DATA_HEADER; - if (dst->metrics[RTAX_ADVMSS-1] > mss) + if (dst_metric(dst, RTAX_ADVMSS) > mss) dst->metrics[RTAX_ADVMSS-1] = mss; } } @@ -805,12 +805,12 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) rt->u.dst.neighbour = n; } - if (rt->u.dst.metrics[RTAX_MTU-1] == 0 || - rt->u.dst.metrics[RTAX_MTU-1] > rt->u.dst.dev->mtu) + if (dst_metric(&rt->u.dst, RTAX_MTU) == 0 || + dst_metric(&rt->u.dst, RTAX_MTU) > rt->u.dst.dev->mtu) rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu; mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst)); - if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0 || - rt->u.dst.metrics[RTAX_ADVMSS-1] > mss) + if (dst_metric(&rt->u.dst, RTAX_ADVMSS) == 0 || + dst_metric(&rt->u.dst, RTAX_ADVMSS) > mss) rt->u.dst.metrics[RTAX_ADVMSS-1] = mss; return 0; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 9084055a81a4..92f90ae46f4a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1468,14 +1468,14 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, /* BSD 4.2 compatibility hack :-( */ if (mtu == 0 && - old_mtu >= rth->u.dst.metrics[RTAX_MTU-1] && + old_mtu >= dst_metric(&rth->u.dst, RTAX_MTU) && old_mtu >= 68 + (iph->ihl << 2)) old_mtu -= iph->ihl << 2; mtu = guess_mtu(old_mtu); } - if (mtu <= rth->u.dst.metrics[RTAX_MTU-1]) { - if (mtu < rth->u.dst.metrics[RTAX_MTU-1]) { + if (mtu <= dst_metric(&rth->u.dst, RTAX_MTU)) { + if (mtu < dst_metric(&rth->u.dst, RTAX_MTU)) { dst_confirm(&rth->u.dst); if (mtu < ip_rt_min_pmtu) { mtu = ip_rt_min_pmtu; @@ -1497,7 +1497,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) { - if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= 68 && + if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= 68 && !(dst_metric_locked(dst, RTAX_MTU))) { if (mtu < ip_rt_min_pmtu) { mtu = ip_rt_min_pmtu; @@ -1624,14 +1624,14 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) } else rt->u.dst.metrics[RTAX_MTU-1]= rt->u.dst.dev->mtu; - if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0) + if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0) rt->u.dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl; - if (rt->u.dst.metrics[RTAX_MTU-1] > IP_MAX_MTU) + if (dst_metric(&rt->u.dst, RTAX_MTU) > IP_MAX_MTU) rt->u.dst.metrics[RTAX_MTU-1] = IP_MAX_MTU; - if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0) + if (dst_metric(&rt->u.dst, RTAX_ADVMSS) == 0) rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->u.dst.dev->mtu - 40, ip_rt_min_advmss); - if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535 - 40) + if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535 - 40) rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535 - 40; #ifdef CONFIG_NET_CLS_ROUTE diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index eda4f4a233f3..8ac15a604e08 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -605,7 +606,7 @@ static u32 tcp_rto_min(struct sock *sk) u32 rto_min = TCP_RTO_MIN; if (dst && dst_metric_locked(dst, RTAX_RTO_MIN)) - rto_min = dst->metrics[RTAX_RTO_MIN - 1]; + rto_min = dst_metric(dst, RTAX_RTO_MIN); return rto_min; } @@ -769,7 +770,7 @@ void tcp_update_metrics(struct sock *sk) dst->metrics[RTAX_RTTVAR - 1] = m; else dst->metrics[RTAX_RTTVAR-1] -= - (dst->metrics[RTAX_RTTVAR-1] - m)>>2; + (dst_metric(dst, RTAX_RTTVAR) - m)>>2; } if (tp->snd_ssthresh >= 0xFFFF) { @@ -788,21 +789,21 @@ void tcp_update_metrics(struct sock *sk) dst->metrics[RTAX_SSTHRESH-1] = max(tp->snd_cwnd >> 1, tp->snd_ssthresh); if (!dst_metric_locked(dst, RTAX_CWND)) - dst->metrics[RTAX_CWND-1] = (dst->metrics[RTAX_CWND-1] + tp->snd_cwnd) >> 1; + dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_cwnd) >> 1; } else { /* Else slow start did not finish, cwnd is non-sense, ssthresh may be also invalid. */ if (!dst_metric_locked(dst, RTAX_CWND)) - dst->metrics[RTAX_CWND-1] = (dst->metrics[RTAX_CWND-1] + tp->snd_ssthresh) >> 1; - if (dst->metrics[RTAX_SSTHRESH-1] && + dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_ssthresh) >> 1; + if (dst_metric(dst, RTAX_SSTHRESH) && !dst_metric_locked(dst, RTAX_SSTHRESH) && - tp->snd_ssthresh > dst->metrics[RTAX_SSTHRESH-1]) + tp->snd_ssthresh > dst_metric(dst, RTAX_SSTHRESH)) dst->metrics[RTAX_SSTHRESH-1] = tp->snd_ssthresh; } if (!dst_metric_locked(dst, RTAX_REORDERING)) { - if (dst->metrics[RTAX_REORDERING-1] < tp->reordering && + if (dst_metric(dst, RTAX_REORDERING) < tp->reordering && tp->reordering != sysctl_tcp_reordering) dst->metrics[RTAX_REORDERING-1] = tp->reordering; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a493ad9b8914..12bba0880345 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1243,11 +1243,11 @@ install_route: } } - if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0) + if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0) rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1; - if (!rt->u.dst.metrics[RTAX_MTU-1]) + if (!dst_metric(&rt->u.dst, RTAX_MTU)) rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); - if (!rt->u.dst.metrics[RTAX_ADVMSS-1]) + if (!dst_metric(&rt->u.dst, RTAX_ADVMSS)) rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst)); rt->u.dst.dev = dev; rt->rt6i_idev = idev; -- cgit v1.2.3 From fa1b1cff3d06550d23ef540c4f97ca83c021b473 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Mon, 5 May 2008 00:22:35 -0700 Subject: net_cls_act: Make act_simple use of netlink policy. Convert to netlink helpers by using netlink policy validation. As a side effect fixes a leak. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/act_simple.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 64b2d136c78e..269ab51cd9b2 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -6,7 +6,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Authors: Jamal Hadi Salim (2005) + * Authors: Jamal Hadi Salim (2005-8) * */ @@ -34,6 +34,7 @@ static struct tcf_hashinfo simp_hash_info = { .lock = &simp_lock, }; +#define SIMP_MAX_DATA 32 static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) { struct tcf_defact *d = a->priv; @@ -69,23 +70,24 @@ static int tcf_simp_release(struct tcf_defact *d, int bind) return ret; } -static int alloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata) +static int alloc_defdata(struct tcf_defact *d, char *defdata) { - d->tcfd_defdata = kmemdup(defdata, datalen, GFP_KERNEL); + d->tcfd_defdata = kstrndup(defdata, SIMP_MAX_DATA, GFP_KERNEL); if (unlikely(!d->tcfd_defdata)) return -ENOMEM; - d->tcfd_datalen = datalen; + return 0; } -static int realloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata) +static int realloc_defdata(struct tcf_defact *d, char *defdata) { kfree(d->tcfd_defdata); - return alloc_defdata(d, datalen, defdata); + return alloc_defdata(d, defdata); } static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = { [TCA_DEF_PARMS] = { .len = sizeof(struct tc_defact) }, + [TCA_DEF_DATA] = { .type = NLA_STRING, .len = SIMP_MAX_DATA }, }; static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, @@ -95,28 +97,24 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, struct tc_defact *parm; struct tcf_defact *d; struct tcf_common *pc; - void *defdata; - u32 datalen = 0; + char *defdata; int ret = 0, err; if (nla == NULL) return -EINVAL; - err = nla_parse_nested(tb, TCA_DEF_MAX, nla, NULL); + err = nla_parse_nested(tb, TCA_DEF_MAX, nla, simple_policy); if (err < 0) return err; if (tb[TCA_DEF_PARMS] == NULL) return -EINVAL; - parm = nla_data(tb[TCA_DEF_PARMS]); - defdata = nla_data(tb[TCA_DEF_DATA]); - if (defdata == NULL) + if (tb[TCA_DEF_DATA] == NULL) return -EINVAL; - datalen = nla_len(tb[TCA_DEF_DATA]); - if (datalen == 0) - return -EINVAL; + parm = nla_data(tb[TCA_DEF_PARMS]); + defdata = nla_data(tb[TCA_DEF_DATA]); pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info); if (!pc) { @@ -126,7 +124,7 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, return -ENOMEM; d = to_defact(pc); - ret = alloc_defdata(d, datalen, defdata); + ret = alloc_defdata(d, defdata); if (ret < 0) { kfree(pc); return ret; @@ -138,7 +136,7 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, tcf_simp_release(d, bind); return -EEXIST; } - realloc_defdata(d, datalen, defdata); + realloc_defdata(d, defdata); } spin_lock_bh(&d->tcf_lock); @@ -172,7 +170,7 @@ static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, opt.bindcnt = d->tcf_bindcnt - bind; opt.action = d->tcf_action; NLA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); - NLA_PUT(skb, TCA_DEF_DATA, d->tcfd_datalen, d->tcfd_defdata); + NLA_PUT_STRING(skb, TCA_DEF_DATA, d->tcfd_defdata); t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse); t.expires = jiffies_to_clock_t(d->tcf_tm.expires); -- cgit v1.2.3 From 19443178fbfbf40db15c86012fc37df1a44ab857 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Mon, 5 May 2008 13:50:24 -0700 Subject: dccp: return -EINVAL on invalid feature length dccp_feat_change() validates length and on error is returning 1. This happens to work since call chain is checking for 0 == success, but this is returned to userspace, so make it a real error value. Signed-off-by: Chris Wright Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/feat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 4a4f6ce4498d..933a0ecf8d46 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -32,7 +32,7 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, if (len > 3) { DCCP_WARN("invalid length %d\n", len); - return 1; + return -EINVAL; } /* XXX add further sanity checks */ -- cgit v1.2.3 From 5f6b1ea41b46bc63f667f9b30d939b49734c20b0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 6 May 2008 00:00:16 -0700 Subject: Revert "atm: Do not free already unregistered net device." This reverts commit 65e4113684e50cee75357ce10dc9026b0929e4e9. Unlike the other cases Pavel fixed, this case did not setup a netdev->destructor of free_netdev, therefore this change was not correct. Signed-off-by: David S. Miller --- net/atm/br2684.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 13858e2675c5..9d52ebfc1962 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -350,6 +350,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) list_del(&brdev->br2684_devs); write_unlock_irq(&devs_lock); unregister_netdev(net_dev); + free_netdev(net_dev); } return; } @@ -770,6 +771,7 @@ static void __exit br2684_exit(void) list_del(&brdev->br2684_devs); unregister_netdev(net_dev); + free_netdev(net_dev); } } -- cgit v1.2.3 From 9d1045ad68fcccfaf1393cc463ab6357693e8d1d Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 6 May 2008 00:10:24 -0700 Subject: net_cls_act: act_simple dont ignore realloc code reallocation of the policy data was being ignored. It could fail. Simplify so that there is no need for reallocating. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/act_simple.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 269ab51cd9b2..1d421d059caf 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -79,10 +79,14 @@ static int alloc_defdata(struct tcf_defact *d, char *defdata) return 0; } -static int realloc_defdata(struct tcf_defact *d, char *defdata) +static void reset_policy(struct tcf_defact *d, char *defdata, + struct tc_defact *p) { - kfree(d->tcfd_defdata); - return alloc_defdata(d, defdata); + spin_lock_bh(&d->tcf_lock); + d->tcf_action = p->action; + memset(d->tcfd_defdata, 0, SIMP_MAX_DATA); + strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); + spin_unlock_bh(&d->tcf_lock); } static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = { @@ -129,6 +133,7 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, kfree(pc); return ret; } + d->tcf_action = parm->action; ret = ACT_P_CREATED; } else { d = to_defact(pc); @@ -136,13 +141,9 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, tcf_simp_release(d, bind); return -EEXIST; } - realloc_defdata(d, defdata); + reset_policy(d, defdata, parm); } - spin_lock_bh(&d->tcf_lock); - d->tcf_action = parm->action; - spin_unlock_bh(&d->tcf_lock); - if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &simp_hash_info); return ret; -- cgit v1.2.3