Skip to content

Commit

Permalink
sctp: add dif and sdif check in asoc and ep lookup
Browse files Browse the repository at this point in the history
This patch at first adds a pernet global l3mdev_accept to decide if it
accepts the packets from a l3mdev when a SCTP socket doesn't bind to
any interface. It's set to 1 to avoid any possible incompatible issue,
and in next patch, a sysctl will be introduced to allow to change it.

Then similar to inet/udp_sk_bound_dev_eq(), sctp_sk_bound_dev_eq() is
added to check either dif or sdif is equal to sk_bound_dev_if, and to
check sid is 0 or l3mdev_accept is 1 if sk_bound_dev_if is not set.
This function is used to match a association or a endpoint, namely
called by sctp_addrs_lookup_transport() and sctp_endpoint_is_match().
All functions that needs updating are:

sctp_rcv():
  asoc:
  __sctp_rcv_lookup()
    __sctp_lookup_association() -> sctp_addrs_lookup_transport()
    __sctp_rcv_lookup_harder()
      __sctp_rcv_init_lookup()
         __sctp_lookup_association() -> sctp_addrs_lookup_transport()
      __sctp_rcv_walk_lookup()
         __sctp_rcv_asconf_lookup()
           __sctp_lookup_association() -> sctp_addrs_lookup_transport()

  ep:
  __sctp_rcv_lookup_endpoint() -> sctp_endpoint_is_match()

sctp_connect():
  sctp_endpoint_is_peeled_off()
    __sctp_lookup_association()
      sctp_has_association()
        sctp_lookup_association()
          __sctp_lookup_association() -> sctp_addrs_lookup_transport()

sctp_diag_dump_one():
  sctp_transport_lookup_process() -> sctp_addrs_lookup_transport()

Signed-off-by: Xin Long <lucien.xin@gmail.com>
  • Loading branch information
lxin authored and intel-lab-lkp committed Nov 13, 2022
1 parent 3d39b70 commit 6129dc2
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 61 deletions.
4 changes: 4 additions & 0 deletions include/net/netns/sctp.h
Expand Up @@ -175,6 +175,10 @@ struct netns_sctp {

/* Threshold for autoclose timeout, in seconds. */
unsigned long max_autoclose;

#ifdef CONFIG_NET_L3_MASTER_DEV
int l3mdev_accept;
#endif
};

#endif /* __NETNS_SCTP_H__ */
16 changes: 14 additions & 2 deletions include/net/sctp/sctp.h
Expand Up @@ -114,7 +114,7 @@ struct sctp_transport *sctp_transport_get_idx(struct net *net,
struct rhashtable_iter *iter, int pos);
int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net,
const union sctp_addr *laddr,
const union sctp_addr *paddr, void *p);
const union sctp_addr *paddr, void *p, int dif);
int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,
struct net *net, int *pos, void *p);
int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), void *p);
Expand Down Expand Up @@ -162,7 +162,8 @@ void sctp_unhash_transport(struct sctp_transport *t);
struct sctp_transport *sctp_addrs_lookup_transport(
struct net *net,
const union sctp_addr *laddr,
const union sctp_addr *paddr);
const union sctp_addr *paddr,
int dif, int sdif);
struct sctp_transport *sctp_epaddr_lookup_transport(
const struct sctp_endpoint *ep,
const union sctp_addr *paddr);
Expand Down Expand Up @@ -676,4 +677,15 @@ static inline void sctp_sock_set_nodelay(struct sock *sk)
release_sock(sk);
}

static inline bool sctp_sk_bound_dev_eq(struct net *net, int bound_dev_if,
int dif, int sdif)
{
bool l3mdev_accept = true;

#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
l3mdev_accept = !!READ_ONCE(net->sctp.l3mdev_accept);
#endif
return inet_bound_dev_eq(l3mdev_accept, bound_dev_if, dif, sdif);
}

#endif /* __net_sctp_h__ */
8 changes: 5 additions & 3 deletions include/net/sctp/structs.h
Expand Up @@ -1379,10 +1379,12 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
struct sctp_transport **);
bool sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
const union sctp_addr *paddr);
struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *,
struct net *, const union sctp_addr *);
struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
struct net *net,
const union sctp_addr *laddr,
int dif, int sdif);
bool sctp_has_association(struct net *net, const union sctp_addr *laddr,
const union sctp_addr *paddr);
const union sctp_addr *paddr, int dif, int sdif);

int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
Expand Down
3 changes: 2 additions & 1 deletion net/sctp/diag.c
Expand Up @@ -426,6 +426,7 @@ static int sctp_diag_dump_one(struct netlink_callback *cb,
struct net *net = sock_net(skb->sk);
const struct nlmsghdr *nlh = cb->nlh;
union sctp_addr laddr, paddr;
int dif = req->id.idiag_if;
struct sctp_comm_param commp = {
.skb = skb,
.r = req,
Expand Down Expand Up @@ -454,7 +455,7 @@ static int sctp_diag_dump_one(struct netlink_callback *cb,
}

return sctp_transport_lookup_process(sctp_sock_dump_one,
net, &laddr, &paddr, &commp);
net, &laddr, &paddr, &commp, dif);
}

static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
Expand Down
13 changes: 9 additions & 4 deletions net/sctp/endpointola.c
Expand Up @@ -246,12 +246,15 @@ void sctp_endpoint_put(struct sctp_endpoint *ep)
/* Is this the endpoint we are looking for? */
struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
struct net *net,
const union sctp_addr *laddr)
const union sctp_addr *laddr,
int dif, int sdif)
{
int bound_dev_if = READ_ONCE(ep->base.sk->sk_bound_dev_if);
struct sctp_endpoint *retval = NULL;

if ((htons(ep->base.bind_addr.port) == laddr->v4.sin_port) &&
net_eq(ep->base.net, net)) {
if (net_eq(ep->base.net, net) &&
sctp_sk_bound_dev_eq(net, bound_dev_if, dif, sdif) &&
(htons(ep->base.bind_addr.port) == laddr->v4.sin_port)) {
if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
sctp_sk(ep->base.sk)))
retval = ep;
Expand Down Expand Up @@ -298,6 +301,7 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
bool sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
const union sctp_addr *paddr)
{
int bound_dev_if = READ_ONCE(ep->base.sk->sk_bound_dev_if);
struct sctp_sockaddr_entry *addr;
struct net *net = ep->base.net;
struct sctp_bind_addr *bp;
Expand All @@ -307,7 +311,8 @@ bool sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
* so the address_list can not change.
*/
list_for_each_entry(addr, &bp->address_list, list) {
if (sctp_has_association(net, &addr->a, paddr))
if (sctp_has_association(net, &addr->a, paddr,
bound_dev_if, bound_dev_if))
return true;
}

Expand Down

0 comments on commit 6129dc2

Please sign in to comment.