@ -790,10 +790,9 @@ hit:
/* rhashtable for transport */
struct sctp_hash_cmp_arg {
const struct sctp_endpoint * ep ;
const union sctp_addr * laddr ;
const union sctp_addr * paddr ;
const struct net * net ;
const union sctp_addr * paddr ;
const struct net * net ;
u16 lport ;
} ;
static inline int sctp_hash_cmp ( struct rhashtable_compare_arg * arg ,
@ -801,7 +800,6 @@ static inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg,
{
struct sctp_transport * t = ( struct sctp_transport * ) ptr ;
const struct sctp_hash_cmp_arg * x = arg - > key ;
struct sctp_association * asoc ;
int err = 1 ;
if ( ! sctp_cmp_addr_exact ( & t - > ipaddr , x - > paddr ) )
@ -809,19 +807,10 @@ static inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg,
if ( ! sctp_transport_hold ( t ) )
return err ;
asoc = t - > asoc ;
if ( ! net_eq ( sock_net ( asoc - > base . sk ) , x - > net ) )
if ( ! net_eq ( sock_net ( t - > asoc - > base . sk ) , x - > net ) )
goto out ;
if ( x - > lport ! = htons ( t - > asoc - > base . bind_addr . port ) )
goto out ;
if ( x - > ep ) {
if ( x - > ep ! = asoc - > ep )
goto out ;
} else {
if ( x - > laddr - > v4 . sin_port ! = htons ( asoc - > base . bind_addr . port ) )
goto out ;
if ( ! sctp_bind_addr_match ( & asoc - > base . bind_addr ,
x - > laddr , sctp_sk ( asoc - > base . sk ) ) )
goto out ;
}
err = 0 ;
out :
@ -851,11 +840,9 @@ static inline u32 sctp_hash_key(const void *data, u32 len, u32 seed)
const struct sctp_hash_cmp_arg * x = data ;
const union sctp_addr * paddr = x - > paddr ;
const struct net * net = x - > net ;
u16 lport ;
u16 lport = x - > lport ;
u32 addr ;
lport = x - > ep ? htons ( x - > ep - > base . bind_addr . port ) :
x - > laddr - > v4 . sin_port ;
if ( paddr - > sa . sa_family = = AF_INET6 )
addr = jhash ( & paddr - > v6 . sin6_addr , 16 , seed ) ;
else
@ -875,29 +862,32 @@ static const struct rhashtable_params sctp_hash_params = {
int sctp_transport_hashtable_init ( void )
{
return rhash table_init ( & sctp_transport_hashtable , & sctp_hash_params ) ;
return rhl table_init ( & sctp_transport_hashtable , & sctp_hash_params ) ;
}
void sctp_transport_hashtable_destroy ( void )
{
rhash table_destroy ( & sctp_transport_hashtable ) ;
rhl table_destroy ( & sctp_transport_hashtable ) ;
}
void sctp_hash_transport ( struct sctp_transport * t )
int sctp_hash_transport ( struct sctp_transport * t )
{
struct sctp_hash_cmp_arg arg ;
int err ;
if ( t - > asoc - > temp )
return ;
return 0 ;
arg . ep = t - > asoc - > ep ;
arg . paddr = & t - > ipaddr ;
arg . net = sock_net ( t - > asoc - > base . sk ) ;
arg . paddr = & t - > ipaddr ;
arg . lport = htons ( t - > asoc - > base . bind_addr . port ) ;
reinsert :
if ( rhashtable_lookup_insert_key ( & sctp_transport_hashtable , & arg ,
& t - > node , sctp_hash_params ) = = - EBUSY )
goto reinsert ;
err = rhltable_insert_key ( & sctp_transport_hashtable , & arg ,
& t - > node , sctp_hash_params ) ;
if ( err )
pr_err_once ( " insert transport fail, errno %d \n " , err ) ;
return err ;
}
void sctp_unhash_transport ( struct sctp_transport * t )
@ -905,39 +895,62 @@ void sctp_unhash_transport(struct sctp_transport *t)
if ( t - > asoc - > temp )
return ;
rhashtable_remove_fast ( & sctp_transport_hashtable , & t - > node ,
sctp_hash_params ) ;
rhltable_remove ( & sctp_transport_hashtable , & t - > node ,
sctp_hash_params ) ;
}
/* return a transport with holding it */
struct sctp_transport * sctp_addrs_lookup_transport (
struct net * net ,
const union sctp_addr * laddr ,
const union sctp_addr * paddr )
{
struct rhlist_head * tmp , * list ;
struct sctp_transport * t ;
struct sctp_hash_cmp_arg arg = {
. ep = NULL ,
. laddr = laddr ,
. paddr = paddr ,
. net = net ,
. lport = laddr - > v4 . sin_port ,
} ;
return rhashtable_lookup_fast ( & sctp_transport_hashtable , & arg ,
sctp_hash_params ) ;
list = rhltable_lookup ( & sctp_transport_hashtable , & arg ,
sctp_hash_params ) ;
rhl_for_each_entry_rcu ( t , tmp , list , node ) {
if ( ! sctp_transport_hold ( t ) )
continue ;
if ( sctp_bind_addr_match ( & t - > asoc - > base . bind_addr ,
laddr , sctp_sk ( t - > asoc - > base . sk ) ) )
return t ;
sctp_transport_put ( t ) ;
}
return NULL ;
}
/* return a transport without holding it, as it's only used under sock lock */
struct sctp_transport * sctp_epaddr_lookup_transport (
const struct sctp_endpoint * ep ,
const union sctp_addr * paddr )
{
struct net * net = sock_net ( ep - > base . sk ) ;
struct rhlist_head * tmp , * list ;
struct sctp_transport * t ;
struct sctp_hash_cmp_arg arg = {
. ep = ep ,
. paddr = paddr ,
. net = net ,
. lport = htons ( ep - > base . bind_addr . port ) ,
} ;
return rhashtable_lookup_fast ( & sctp_transport_hashtable , & arg ,
sctp_hash_params ) ;
list = rhltable_lookup ( & sctp_transport_hashtable , & arg ,
sctp_hash_params ) ;
rhl_for_each_entry_rcu ( t , tmp , list , node )
if ( ep = = t - > asoc - > ep )
return t ;
return NULL ;
}
/* Look up an association. */
@ -951,7 +964,7 @@ static struct sctp_association *__sctp_lookup_association(
struct sctp_association * asoc = NULL ;
t = sctp_addrs_lookup_transport ( net , local , peer ) ;
if ( ! t | | ! sctp_transport_hold ( t ) )
if ( ! t )
goto out ;
asoc = t - > asoc ;