diff options
-rw-r--r-- | net/sctp/associola.c | 5 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 35 | ||||
-rw-r--r-- | net/sctp/input.c | 39 | ||||
-rw-r--r-- | net/sctp/protocol.c | 6 |
4 files changed, 29 insertions, 56 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 559afd0ee7de..2bf8ec92dde4 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -383,6 +383,7 @@ void sctp_association_free(struct sctp_association *asoc) | |||
383 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { | 383 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { |
384 | transport = list_entry(pos, struct sctp_transport, transports); | 384 | transport = list_entry(pos, struct sctp_transport, transports); |
385 | list_del_rcu(pos); | 385 | list_del_rcu(pos); |
386 | sctp_unhash_transport(transport); | ||
386 | sctp_transport_free(transport); | 387 | sctp_transport_free(transport); |
387 | } | 388 | } |
388 | 389 | ||
@@ -500,6 +501,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, | |||
500 | 501 | ||
501 | /* Remove this peer from the list. */ | 502 | /* Remove this peer from the list. */ |
502 | list_del_rcu(&peer->transports); | 503 | list_del_rcu(&peer->transports); |
504 | /* Remove this peer from the transport hashtable */ | ||
505 | sctp_unhash_transport(peer); | ||
503 | 506 | ||
504 | /* Get the first transport of asoc. */ | 507 | /* Get the first transport of asoc. */ |
505 | pos = asoc->peer.transport_addr_list.next; | 508 | pos = asoc->peer.transport_addr_list.next; |
@@ -699,6 +702,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
699 | /* Attach the remote transport to our asoc. */ | 702 | /* Attach the remote transport to our asoc. */ |
700 | list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list); | 703 | list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list); |
701 | asoc->peer.transport_count++; | 704 | asoc->peer.transport_count++; |
705 | /* Add this peer into the transport hashtable */ | ||
706 | sctp_hash_transport(peer); | ||
702 | 707 | ||
703 | /* If we do not yet have a primary path, set one. */ | 708 | /* If we do not yet have a primary path, set one. */ |
704 | if (!asoc->peer.primary_path) { | 709 | if (!asoc->peer.primary_path) { |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 9da76ba4d10f..8838bf492a12 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
@@ -314,8 +314,8 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep, | |||
314 | } | 314 | } |
315 | 315 | ||
316 | /* Find the association that goes with this chunk. | 316 | /* Find the association that goes with this chunk. |
317 | * We do a linear search of the associations for this endpoint. | 317 | * We lookup the transport from hashtable at first, then get association |
318 | * We return the matching transport address too. | 318 | * through t->assoc. |
319 | */ | 319 | */ |
320 | static struct sctp_association *__sctp_endpoint_lookup_assoc( | 320 | static struct sctp_association *__sctp_endpoint_lookup_assoc( |
321 | const struct sctp_endpoint *ep, | 321 | const struct sctp_endpoint *ep, |
@@ -323,12 +323,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc( | |||
323 | struct sctp_transport **transport) | 323 | struct sctp_transport **transport) |
324 | { | 324 | { |
325 | struct sctp_association *asoc = NULL; | 325 | struct sctp_association *asoc = NULL; |
326 | struct sctp_association *tmp; | 326 | struct sctp_transport *t; |
327 | struct sctp_transport *t = NULL; | ||
328 | struct sctp_hashbucket *head; | ||
329 | struct sctp_ep_common *epb; | ||
330 | int hash; | ||
331 | int rport; | ||
332 | 327 | ||
333 | *transport = NULL; | 328 | *transport = NULL; |
334 | 329 | ||
@@ -337,26 +332,12 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc( | |||
337 | */ | 332 | */ |
338 | if (!ep->base.bind_addr.port) | 333 | if (!ep->base.bind_addr.port) |
339 | goto out; | 334 | goto out; |
335 | t = sctp_epaddr_lookup_transport(ep, paddr); | ||
336 | if (!t || t->asoc->temp) | ||
337 | goto out; | ||
340 | 338 | ||
341 | rport = ntohs(paddr->v4.sin_port); | 339 | *transport = t; |
342 | 340 | asoc = t->asoc; | |
343 | hash = sctp_assoc_hashfn(sock_net(ep->base.sk), ep->base.bind_addr.port, | ||
344 | rport); | ||
345 | head = &sctp_assoc_hashtable[hash]; | ||
346 | read_lock(&head->lock); | ||
347 | sctp_for_each_hentry(epb, &head->chain) { | ||
348 | tmp = sctp_assoc(epb); | ||
349 | if (tmp->ep != ep || rport != tmp->peer.port) | ||
350 | continue; | ||
351 | |||
352 | t = sctp_assoc_lookup_paddr(tmp, paddr); | ||
353 | if (t) { | ||
354 | asoc = tmp; | ||
355 | *transport = t; | ||
356 | break; | ||
357 | } | ||
358 | } | ||
359 | read_unlock(&head->lock); | ||
360 | out: | 341 | out: |
361 | return asoc; | 342 | return asoc; |
362 | } | 343 | } |
diff --git a/net/sctp/input.c b/net/sctp/input.c index bac8278b176b..6f075d835764 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -981,38 +981,19 @@ static struct sctp_association *__sctp_lookup_association( | |||
981 | const union sctp_addr *peer, | 981 | const union sctp_addr *peer, |
982 | struct sctp_transport **pt) | 982 | struct sctp_transport **pt) |
983 | { | 983 | { |
984 | struct sctp_hashbucket *head; | 984 | struct sctp_transport *t; |
985 | struct sctp_ep_common *epb; | ||
986 | struct sctp_association *asoc; | ||
987 | struct sctp_transport *transport; | ||
988 | int hash; | ||
989 | 985 | ||
990 | /* Optimize here for direct hit, only listening connections can | 986 | t = sctp_addrs_lookup_transport(net, local, peer); |
991 | * have wildcards anyways. | 987 | if (!t || t->dead || t->asoc->temp) |
992 | */ | 988 | return NULL; |
993 | hash = sctp_assoc_hashfn(net, ntohs(local->v4.sin_port), | ||
994 | ntohs(peer->v4.sin_port)); | ||
995 | head = &sctp_assoc_hashtable[hash]; | ||
996 | read_lock(&head->lock); | ||
997 | sctp_for_each_hentry(epb, &head->chain) { | ||
998 | asoc = sctp_assoc(epb); | ||
999 | transport = sctp_assoc_is_match(asoc, net, local, peer); | ||
1000 | if (transport) | ||
1001 | goto hit; | ||
1002 | } | ||
1003 | 989 | ||
1004 | read_unlock(&head->lock); | 990 | sctp_association_hold(t->asoc); |
991 | *pt = t; | ||
1005 | 992 | ||
1006 | return NULL; | 993 | return t->asoc; |
1007 | |||
1008 | hit: | ||
1009 | *pt = transport; | ||
1010 | sctp_association_hold(asoc); | ||
1011 | read_unlock(&head->lock); | ||
1012 | return asoc; | ||
1013 | } | 994 | } |
1014 | 995 | ||
1015 | /* Look up an association. BH-safe. */ | 996 | /* Look up an association. protected by RCU read lock */ |
1016 | static | 997 | static |
1017 | struct sctp_association *sctp_lookup_association(struct net *net, | 998 | struct sctp_association *sctp_lookup_association(struct net *net, |
1018 | const union sctp_addr *laddr, | 999 | const union sctp_addr *laddr, |
@@ -1021,9 +1002,9 @@ struct sctp_association *sctp_lookup_association(struct net *net, | |||
1021 | { | 1002 | { |
1022 | struct sctp_association *asoc; | 1003 | struct sctp_association *asoc; |
1023 | 1004 | ||
1024 | local_bh_disable(); | 1005 | rcu_read_lock(); |
1025 | asoc = __sctp_lookup_association(net, laddr, paddr, transportp); | 1006 | asoc = __sctp_lookup_association(net, laddr, paddr, transportp); |
1026 | local_bh_enable(); | 1007 | rcu_read_unlock(); |
1027 | 1008 | ||
1028 | return asoc; | 1009 | return asoc; |
1029 | } | 1010 | } |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 010aced44b6b..631cfb380535 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -1467,6 +1467,9 @@ static __init int sctp_init(void) | |||
1467 | INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain); | 1467 | INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain); |
1468 | } | 1468 | } |
1469 | 1469 | ||
1470 | if (sctp_transport_hashtable_init()) | ||
1471 | goto err_thash_alloc; | ||
1472 | |||
1470 | pr_info("Hash tables configured (established %d bind %d)\n", | 1473 | pr_info("Hash tables configured (established %d bind %d)\n", |
1471 | sctp_assoc_hashsize, sctp_port_hashsize); | 1474 | sctp_assoc_hashsize, sctp_port_hashsize); |
1472 | 1475 | ||
@@ -1521,6 +1524,8 @@ err_register_defaults: | |||
1521 | get_order(sctp_port_hashsize * | 1524 | get_order(sctp_port_hashsize * |
1522 | sizeof(struct sctp_bind_hashbucket))); | 1525 | sizeof(struct sctp_bind_hashbucket))); |
1523 | err_bhash_alloc: | 1526 | err_bhash_alloc: |
1527 | sctp_transport_hashtable_destroy(); | ||
1528 | err_thash_alloc: | ||
1524 | kfree(sctp_ep_hashtable); | 1529 | kfree(sctp_ep_hashtable); |
1525 | err_ehash_alloc: | 1530 | err_ehash_alloc: |
1526 | free_pages((unsigned long)sctp_assoc_hashtable, | 1531 | free_pages((unsigned long)sctp_assoc_hashtable, |
@@ -1567,6 +1572,7 @@ static __exit void sctp_exit(void) | |||
1567 | free_pages((unsigned long)sctp_port_hashtable, | 1572 | free_pages((unsigned long)sctp_port_hashtable, |
1568 | get_order(sctp_port_hashsize * | 1573 | get_order(sctp_port_hashsize * |
1569 | sizeof(struct sctp_bind_hashbucket))); | 1574 | sizeof(struct sctp_bind_hashbucket))); |
1575 | sctp_transport_hashtable_destroy(); | ||
1570 | 1576 | ||
1571 | percpu_counter_destroy(&sctp_sockets_allocated); | 1577 | percpu_counter_destroy(&sctp_sockets_allocated); |
1572 | 1578 | ||