aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/protocol.c
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2006-12-13 19:26:26 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-13 19:48:27 -0500
commit29c7cf96186ac14ce7380633f690fc39732ff03a (patch)
treeccc95adc0e1185469e77a1adcae1d300d0b534d1 /net/sctp/protocol.c
parent6931ba7cef3991fbb970997d33e24139ccdc3c2c (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/protocol.c')
-rw-r--r--net/sctp/protocol.c69
1 files changed, 32 insertions, 37 deletions
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index f2ba8615895b..b61f3341e0a2 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -163,7 +163,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
163/* Extract our IP addresses from the system and stash them in the 163/* Extract our IP addresses from the system and stash them in the
164 * protocol structure. 164 * protocol structure.
165 */ 165 */
166static void __sctp_get_local_addr_list(void) 166static void sctp_get_local_addr_list(void)
167{ 167{
168 struct net_device *dev; 168 struct net_device *dev;
169 struct list_head *pos; 169 struct list_head *pos;
@@ -179,17 +179,8 @@ static void __sctp_get_local_addr_list(void)
179 read_unlock(&dev_base_lock); 179 read_unlock(&dev_base_lock);
180} 180}
181 181
182static void sctp_get_local_addr_list(void)
183{
184 unsigned long flags;
185
186 sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
187 __sctp_get_local_addr_list();
188 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
189}
190
191/* Free the existing local addresses. */ 182/* Free the existing local addresses. */
192static void __sctp_free_local_addr_list(void) 183static void sctp_free_local_addr_list(void)
193{ 184{
194 struct sctp_sockaddr_entry *addr; 185 struct sctp_sockaddr_entry *addr;
195 struct list_head *pos, *temp; 186 struct list_head *pos, *temp;
@@ -201,27 +192,15 @@ static void __sctp_free_local_addr_list(void)
201 } 192 }
202} 193}
203 194
204/* Free the existing local addresses. */
205static void sctp_free_local_addr_list(void)
206{
207 unsigned long flags;
208
209 sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
210 __sctp_free_local_addr_list();
211 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
212}
213
214/* Copy the local addresses which are valid for 'scope' into 'bp'. */ 195/* Copy the local addresses which are valid for 'scope' into 'bp'. */
215int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope, 196int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
216 gfp_t gfp, int copy_flags) 197 gfp_t gfp, int copy_flags)
217{ 198{
218 struct sctp_sockaddr_entry *addr; 199 struct sctp_sockaddr_entry *addr;
219 int error = 0; 200 int error = 0;
220 struct list_head *pos; 201 struct list_head *pos, *temp;
221 unsigned long flags;
222 202
223 sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); 203 list_for_each_safe(pos, temp, &sctp_local_addr_list) {
224 list_for_each(pos, &sctp_local_addr_list) {
225 addr = list_entry(pos, struct sctp_sockaddr_entry, list); 204 addr = list_entry(pos, struct sctp_sockaddr_entry, list);
226 if (sctp_in_scope(&addr->a, scope)) { 205 if (sctp_in_scope(&addr->a, scope)) {
227 /* Now that the address is in scope, check to see if 206 /* Now that the address is in scope, check to see if
@@ -242,7 +221,6 @@ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
242 } 221 }
243 222
244end_copy: 223end_copy:
245 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
246 return error; 224 return error;
247} 225}
248 226
@@ -622,18 +600,36 @@ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
622 seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr)); 600 seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
623} 601}
624 602
625/* Event handler for inet address addition/deletion events. 603/* Event handler for inet address addition/deletion events. */
626 * Basically, whenever there is an event, we re-build our local address list.
627 */
628int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, 604int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
629 void *ptr) 605 void *ptr)
630{ 606{
631 unsigned long flags; 607 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
608 struct sctp_sockaddr_entry *addr;
609 struct list_head *pos, *temp;
632 610
633 sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); 611 switch (ev) {
634 __sctp_free_local_addr_list(); 612 case NETDEV_UP:
635 __sctp_get_local_addr_list(); 613 addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
636 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); 614 if (addr) {
615 addr->a.v4.sin_family = AF_INET;
616 addr->a.v4.sin_port = 0;
617 addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
618 list_add_tail(&addr->list, &sctp_local_addr_list);
619 }
620 break;
621 case NETDEV_DOWN:
622 list_for_each_safe(pos, temp, &sctp_local_addr_list) {
623 addr = list_entry(pos, struct sctp_sockaddr_entry, list);
624 if (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) {
625 list_del(pos);
626 kfree(addr);
627 break;
628 }
629 }
630
631 break;
632 }
637 633
638 return NOTIFY_DONE; 634 return NOTIFY_DONE;
639} 635}
@@ -1172,13 +1168,12 @@ SCTP_STATIC __init int sctp_init(void)
1172 1168
1173 /* Initialize the local address list. */ 1169 /* Initialize the local address list. */
1174 INIT_LIST_HEAD(&sctp_local_addr_list); 1170 INIT_LIST_HEAD(&sctp_local_addr_list);
1175 spin_lock_init(&sctp_local_addr_lock); 1171
1172 sctp_get_local_addr_list();
1176 1173
1177 /* Register notifier for inet address additions/deletions. */ 1174 /* Register notifier for inet address additions/deletions. */
1178 register_inetaddr_notifier(&sctp_inetaddr_notifier); 1175 register_inetaddr_notifier(&sctp_inetaddr_notifier);
1179 1176
1180 sctp_get_local_addr_list();
1181
1182 __unsafe(THIS_MODULE); 1177 __unsafe(THIS_MODULE);
1183 status = 0; 1178 status = 0;
1184out: 1179out: