summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/sctp/associola.c5
-rw-r--r--net/sctp/endpointola.c35
-rw-r--r--net/sctp/input.c39
-rw-r--r--net/sctp/protocol.c6
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 */
320static struct sctp_association *__sctp_endpoint_lookup_assoc( 320static 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);
360out: 341out:
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
1008hit:
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 */
1016static 997static
1017struct sctp_association *sctp_lookup_association(struct net *net, 998struct 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)));
1523err_bhash_alloc: 1526err_bhash_alloc:
1527 sctp_transport_hashtable_destroy();
1528err_thash_alloc:
1524 kfree(sctp_ep_hashtable); 1529 kfree(sctp_ep_hashtable);
1525err_ehash_alloc: 1530err_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