From 29c7cf96186ac14ce7380633f690fc39732ff03a Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Wed, 13 Dec 2006 16:26:26 -0800 Subject: [SCTP]: Handle address add/delete events in a more efficient way. Currently in SCTP, we maintain a local address list by rebuilding the whole list from the device list whenever we get a address add/delete event. This patch fixes it by only adding/deleting the address for which we receive the event. Also removed the sctp_local_addr_lock() which is no longer needed as we now use list_for_each_safe() to traverse this list. This fixes the bugs in sctp_copy_laddrs_xxx() routines where we do copy_to_user() while holding this lock. Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'net/sctp/ipv6.c') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 3c3e560087c..d8d36dee5ab 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -78,8 +78,44 @@ #include +/* Event handler for inet6 address addition/deletion events. */ +int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, + void *ptr) +{ + struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; + struct sctp_sockaddr_entry *addr; + struct list_head *pos, *temp; + + switch (ev) { + case NETDEV_UP: + addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); + if (addr) { + addr->a.v6.sin6_family = AF_INET6; + addr->a.v6.sin6_port = 0; + memcpy(&addr->a.v6.sin6_addr, &ifa->addr, + sizeof(struct in6_addr)); + addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex; + list_add_tail(&addr->list, &sctp_local_addr_list); + } + break; + case NETDEV_DOWN: + list_for_each_safe(pos, temp, &sctp_local_addr_list) { + addr = list_entry(pos, struct sctp_sockaddr_entry, list); + if (ipv6_addr_equal(&addr->a.v6.sin6_addr, &ifa->addr)) { + list_del(pos); + kfree(addr); + break; + } + } + + break; + } + + return NOTIFY_DONE; +} + static struct notifier_block sctp_inet6addr_notifier = { - .notifier_call = sctp_inetaddr_event, + .notifier_call = sctp_inet6addr_event, }; /* ICMP error handler. */ -- cgit v1.2.3