diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/ip6_output.c | 4 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 84 |
2 files changed, 54 insertions, 34 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 4d124d558..b1e7e7dc5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_output.c,v 1.26 2000/03/01 02:58:12 davem Exp $ + * $Id: ip6_output.c,v 1.27 2000/06/21 17:18:40 davem Exp $ * * Based on linux/net/ipv4/ip_output.c * @@ -200,7 +200,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, if (skb_headroom(skb) < head_room) { struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); - kfree(skb); + kfree_skb(skb); skb = skb2; if (skb == NULL) return -ENOBUFS; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 053db0c72..dd4b55b0f 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: mcast.c,v 1.30 2000/02/08 21:27:23 davem Exp $ + * $Id: mcast.c,v 1.31 2000/06/21 17:23:54 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -196,16 +196,26 @@ int inet6_mc_check(struct sock *sk, struct in6_addr *addr) return 0; } +static void ma_put(struct ifmcaddr6 *mc) +{ + if (atomic_dec_and_test(&mc->mca_refcnt)) { + in6_dev_put(mc->idev); + kfree_s(mc, sizeof(*mc)); + } +} + static int igmp6_group_added(struct ifmcaddr6 *mc) { struct net_device *dev = mc->idev->dev; char buf[MAX_ADDR_LEN]; + spin_lock_bh(&mc->mca_lock); if (!(mc->mca_flags&MAF_LOADED)) { mc->mca_flags |= MAF_LOADED; if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) dev_mc_add(dev, buf, dev->addr_len, 0); } + spin_unlock_bh(&mc->mca_lock); if (dev->flags&IFF_UP) igmp6_join_group(mc); @@ -217,11 +227,13 @@ static int igmp6_group_dropped(struct ifmcaddr6 *mc) struct net_device *dev = mc->idev->dev; char buf[MAX_ADDR_LEN]; + spin_lock_bh(&mc->mca_lock); if (mc->mca_flags&MAF_LOADED) { mc->mca_flags &= ~MAF_LOADED; if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) dev_mc_delete(dev, buf, dev->addr_len, 0); } + spin_unlock_bh(&mc->mca_lock); if (dev->flags&IFF_UP) igmp6_leave_group(mc); @@ -251,7 +263,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) for (mc = idev->mc_list; mc; mc = mc->next) { if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) { - atomic_inc(&mc->mca_users); + mc->mca_users++; write_unlock_bh(&idev->lock); in6_dev_put(idev); return 0; @@ -276,15 +288,16 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr)); mc->idev = idev; - atomic_set(&mc->mca_users, 1); + mc->mca_users = 1; + atomic_set(&mc->mca_refcnt, 2); + mc->mca_lock = SPIN_LOCK_UNLOCKED; mc->next = idev->mc_list; idev->mc_list = mc; - - igmp6_group_added(mc); - write_unlock_bh(&idev->lock); + igmp6_group_added(mc); + ma_put(mc); return 0; } @@ -303,16 +316,13 @@ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr) write_lock_bh(&idev->lock); for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) { if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) { - if (atomic_dec_and_test(&ma->mca_users)) { + if (--ma->mca_users == 0) { *map = ma->next; write_unlock_bh(&idev->lock); igmp6_group_dropped(ma); - if (ma->idev) - __in6_dev_put(ma->idev); - - kfree(ma); + ma_put(ma); in6_dev_put(idev); return 0; } @@ -363,8 +373,11 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) if (ipv6_addr_type(&ma->mca_addr)&(IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK)) return; - if (del_timer(&ma->mca_timer)) + spin_lock(&ma->mca_lock); + if (del_timer(&ma->mca_timer)) { + atomic_dec(&ma->mca_refcnt); delay = ma->mca_timer.expires - jiffies; + } if (delay >= resptime) { if (resptime) @@ -373,9 +386,10 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) delay = 1; } - ma->mca_flags |= MAF_TIMER_RUNNING; ma->mca_timer.expires = jiffies + delay; - add_timer(&ma->mca_timer); + if (!mod_timer(&ma->mca_timer, jiffies + delay)) + atomic_inc(&ma->mca_refcnt); + spin_unlock(&ma->mca_lock); } int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, int len) @@ -453,12 +467,11 @@ int igmp6_event_report(struct sk_buff *skb, struct icmp6hdr *hdr, int len) read_lock(&idev->lock); for (ma = idev->mc_list; ma; ma=ma->next) { if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) { - if (ma->mca_flags & MAF_TIMER_RUNNING) { - del_timer(&ma->mca_timer); - ma->mca_flags &= ~MAF_TIMER_RUNNING; - } - - ma->mca_flags &= ~MAF_LAST_REPORTER; + spin_lock(&ma->mca_lock); + if (del_timer(&ma->mca_timer)) + atomic_dec(&ma->mca_refcnt); + ma->mca_flags &= ~(MAF_LAST_REPORTER|MAF_TIMER_RUNNING); + spin_unlock(&ma->mca_lock); break; } } @@ -552,13 +565,17 @@ static void igmp6_join_group(struct ifmcaddr6 *ma) igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); delay = net_random() % IGMP6_UNSOLICITED_IVAL; - if (del_timer(&ma->mca_timer)) - delay = ma->mca_timer.expires - jiffies; - ma->mca_timer.expires = jiffies + delay; + spin_lock_bh(&ma->mca_lock); + if (del_timer(&ma->mca_timer)) { + atomic_dec(&ma->mca_refcnt); + delay = ma->mca_timer.expires - jiffies; + } - add_timer(&ma->mca_timer); + if (!mod_timer(&ma->mca_timer, jiffies + delay)) + atomic_inc(&ma->mca_refcnt); ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER; + spin_unlock_bh(&ma->mca_lock); } static void igmp6_leave_group(struct ifmcaddr6 *ma) @@ -573,17 +590,23 @@ static void igmp6_leave_group(struct ifmcaddr6 *ma) if (ma->mca_flags & MAF_LAST_REPORTER) igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION); - if (ma->mca_flags & MAF_TIMER_RUNNING) - del_timer(&ma->mca_timer); + spin_lock_bh(&ma->mca_lock); + if (del_timer(&ma->mca_timer)) + atomic_dec(&ma->mca_refcnt); + spin_unlock_bh(&ma->mca_lock); } void igmp6_timer_handler(unsigned long data) { struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data; - ma->mca_flags |= MAF_LAST_REPORTER; igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); + + spin_lock(&ma->mca_lock); + ma->mca_flags |= MAF_LAST_REPORTER; ma->mca_flags &= ~MAF_TIMER_RUNNING; + spin_unlock(&ma->mca_lock); + ma_put(ma); } /* Device going down */ @@ -640,10 +663,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) write_unlock_bh(&idev->lock); igmp6_group_dropped(i); - - if (i->idev) - in6_dev_put(i->idev); - kfree(i); + ma_put(i); write_lock_bh(&idev->lock); } @@ -677,7 +697,7 @@ static int igmp6_read_proc(char *buffer, char **start, off_t offset, len+=sprintf(buffer+len, " %5d %08X %ld\n", - atomic_read(&im->mca_users), + im->mca_users, im->mca_flags, (im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0); |