diff options
author | Sridhar Samudrala <sri@us.ibm.com> | 2006-12-13 19:26:26 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-13 19:48:27 -0500 |
commit | 29c7cf96186ac14ce7380633f690fc39732ff03a (patch) | |
tree | ccc95adc0e1185469e77a1adcae1d300d0b534d1 /net/sctp/ipv6.c | |
parent | 6931ba7cef3991fbb970997d33e24139ccdc3c2c (diff) |
[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 <sri@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r-- | net/sctp/ipv6.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 3c3e560087ca..d8d36dee5ab6 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -78,8 +78,44 @@ | |||
78 | 78 | ||
79 | #include <asm/uaccess.h> | 79 | #include <asm/uaccess.h> |
80 | 80 | ||
81 | /* Event handler for inet6 address addition/deletion events. */ | ||
82 | int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, | ||
83 | void *ptr) | ||
84 | { | ||
85 | struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; | ||
86 | struct sctp_sockaddr_entry *addr; | ||
87 | struct list_head *pos, *temp; | ||
88 | |||
89 | switch (ev) { | ||
90 | case NETDEV_UP: | ||
91 | addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); | ||
92 | if (addr) { | ||
93 | addr->a.v6.sin6_family = AF_INET6; | ||
94 | addr->a.v6.sin6_port = 0; | ||
95 | memcpy(&addr->a.v6.sin6_addr, &ifa->addr, | ||
96 | sizeof(struct in6_addr)); | ||
97 | addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex; | ||
98 | list_add_tail(&addr->list, &sctp_local_addr_list); | ||
99 | } | ||
100 | break; | ||
101 | case NETDEV_DOWN: | ||
102 | list_for_each_safe(pos, temp, &sctp_local_addr_list) { | ||
103 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | ||
104 | if (ipv6_addr_equal(&addr->a.v6.sin6_addr, &ifa->addr)) { | ||
105 | list_del(pos); | ||
106 | kfree(addr); | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | break; | ||
112 | } | ||
113 | |||
114 | return NOTIFY_DONE; | ||
115 | } | ||
116 | |||
81 | static struct notifier_block sctp_inet6addr_notifier = { | 117 | static struct notifier_block sctp_inet6addr_notifier = { |
82 | .notifier_call = sctp_inetaddr_event, | 118 | .notifier_call = sctp_inet6addr_event, |
83 | }; | 119 | }; |
84 | 120 | ||
85 | /* ICMP error handler. */ | 121 | /* ICMP error handler. */ |