Commit 65a5124a authored by Xin Long's avatar Xin Long Committed by David S. Miller

sctp: support to lookup with ep+paddr in transport rhashtable

Now, when we sendmsg, we translate the ep to laddr by selecting the
first element of the list, and then do a lookup for a transport.

But sctp_hash_cmp() will compare it against asoc addr_list, which may
be a subset of ep addr_list, meaning that this chosen laddr may not be
there, and thus making it impossible to find the transport.

So we fix it by using ep + paddr to lookup transports in hashtable. In
sctp_hash_cmp, if .ep is set, we will check if this ep == asoc->ep,
or we will do the laddr check.

Fixes: d6c0256a ("sctp: add the rhashtable apis for sctp global transport hashtable")
Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Acked-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Reported-by: default avatarVlad Yasevich <vyasevich@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 628a96e7
...@@ -784,6 +784,7 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(struct net *net, ...@@ -784,6 +784,7 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(struct net *net,
/* rhashtable for transport */ /* rhashtable for transport */
struct sctp_hash_cmp_arg { struct sctp_hash_cmp_arg {
const struct sctp_endpoint *ep;
const union sctp_addr *laddr; const union sctp_addr *laddr;
const union sctp_addr *paddr; const union sctp_addr *paddr;
const struct net *net; const struct net *net;
...@@ -797,15 +798,20 @@ static inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg, ...@@ -797,15 +798,20 @@ static inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg,
struct sctp_association *asoc = t->asoc; struct sctp_association *asoc = t->asoc;
const struct net *net = x->net; const struct net *net = x->net;
if (x->laddr->v4.sin_port != htons(asoc->base.bind_addr.port))
return 1;
if (!sctp_cmp_addr_exact(&t->ipaddr, x->paddr)) if (!sctp_cmp_addr_exact(&t->ipaddr, x->paddr))
return 1; return 1;
if (!net_eq(sock_net(asoc->base.sk), net)) if (!net_eq(sock_net(asoc->base.sk), net))
return 1; return 1;
if (!sctp_bind_addr_match(&asoc->base.bind_addr, if (x->ep) {
x->laddr, sctp_sk(asoc->base.sk))) if (x->ep != asoc->ep)
return 1; return 1;
} else {
if (x->laddr->v4.sin_port != htons(asoc->base.bind_addr.port))
return 1;
if (!sctp_bind_addr_match(&asoc->base.bind_addr,
x->laddr, sctp_sk(asoc->base.sk)))
return 1;
}
return 0; return 0;
} }
...@@ -832,9 +838,11 @@ static inline u32 sctp_hash_key(const void *data, u32 len, u32 seed) ...@@ -832,9 +838,11 @@ static inline u32 sctp_hash_key(const void *data, u32 len, u32 seed)
const struct sctp_hash_cmp_arg *x = data; const struct sctp_hash_cmp_arg *x = data;
const union sctp_addr *paddr = x->paddr; const union sctp_addr *paddr = x->paddr;
const struct net *net = x->net; const struct net *net = x->net;
u16 lport = x->laddr->v4.sin_port; u16 lport;
u32 addr; u32 addr;
lport = x->ep ? htons(x->ep->base.bind_addr.port) :
x->laddr->v4.sin_port;
if (paddr->sa.sa_family == AF_INET6) if (paddr->sa.sa_family == AF_INET6)
addr = jhash(&paddr->v6.sin6_addr, 16, seed); addr = jhash(&paddr->v6.sin6_addr, 16, seed);
else else
...@@ -864,12 +872,9 @@ void sctp_transport_hashtable_destroy(void) ...@@ -864,12 +872,9 @@ void sctp_transport_hashtable_destroy(void)
void sctp_hash_transport(struct sctp_transport *t) void sctp_hash_transport(struct sctp_transport *t)
{ {
struct sctp_sockaddr_entry *addr;
struct sctp_hash_cmp_arg arg; struct sctp_hash_cmp_arg arg;
addr = list_entry(t->asoc->base.bind_addr.address_list.next, arg.ep = t->asoc->ep;
struct sctp_sockaddr_entry, list);
arg.laddr = &addr->a;
arg.paddr = &t->ipaddr; arg.paddr = &t->ipaddr;
arg.net = sock_net(t->asoc->base.sk); arg.net = sock_net(t->asoc->base.sk);
...@@ -891,6 +896,7 @@ struct sctp_transport *sctp_addrs_lookup_transport( ...@@ -891,6 +896,7 @@ struct sctp_transport *sctp_addrs_lookup_transport(
const union sctp_addr *paddr) const union sctp_addr *paddr)
{ {
struct sctp_hash_cmp_arg arg = { struct sctp_hash_cmp_arg arg = {
.ep = NULL,
.laddr = laddr, .laddr = laddr,
.paddr = paddr, .paddr = paddr,
.net = net, .net = net,
...@@ -904,13 +910,15 @@ struct sctp_transport *sctp_epaddr_lookup_transport( ...@@ -904,13 +910,15 @@ struct sctp_transport *sctp_epaddr_lookup_transport(
const struct sctp_endpoint *ep, const struct sctp_endpoint *ep,
const union sctp_addr *paddr) const union sctp_addr *paddr)
{ {
struct sctp_sockaddr_entry *addr;
struct net *net = sock_net(ep->base.sk); struct net *net = sock_net(ep->base.sk);
struct sctp_hash_cmp_arg arg = {
.ep = ep,
.paddr = paddr,
.net = net,
};
addr = list_entry(ep->base.bind_addr.address_list.next, return rhashtable_lookup_fast(&sctp_transport_hashtable, &arg,
struct sctp_sockaddr_entry, list); sctp_hash_params);
return sctp_addrs_lookup_transport(net, &addr->a, paddr);
} }
/* Look up an association. */ /* Look up an association. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment