diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index 68eec067274395..0ab37f31eee9ff 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -341,6 +341,35 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) return err; } +static int userspace_pm_subflow_create(struct mptcp_sock *msk, + struct mptcp_pm_addr_entry *local, + struct mptcp_addr_info *remote) +{ + struct sock *sk = (struct sock *)msk; + int err; + + if (local->flags & MPTCP_PM_ADDR_FLAG_SIGNAL) + return -EINVAL; + local->flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW; + + if (!mptcp_pm_addr_families_match(sk, &local->addr, remote)) + return -EINVAL; + + err = mptcp_userspace_pm_append_new_local_addr(msk, local, false); + if (err < 0) + return err; + + err = __mptcp_subflow_connect(sk, local, remote); + spin_lock_bh(&msk->pm.lock); + if (err) + mptcp_userspace_pm_delete_local_addr(msk, local); + else + msk->pm.subflows++; + spin_unlock_bh(&msk->pm.lock); + + return err; +} + int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) { struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE]; @@ -368,41 +397,17 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) goto create_err; } - if (entry.flags & MPTCP_PM_ADDR_FLAG_SIGNAL) { - GENL_SET_ERR_MSG(info, "invalid addr flags"); - err = -EINVAL; - goto create_err; - } - entry.flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW; - err = mptcp_pm_parse_addr(raddr, info, &addr_r); if (err < 0) { NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr"); goto create_err; } - if (!mptcp_pm_addr_families_match(sk, &entry.addr, &addr_r)) { - GENL_SET_ERR_MSG(info, "families mismatch"); - err = -EINVAL; - goto create_err; - } - - err = mptcp_userspace_pm_append_new_local_addr(msk, &entry, false); - if (err < 0) { - GENL_SET_ERR_MSG(info, "did not match address and id"); - goto create_err; - } - lock_sock(sk); - err = __mptcp_subflow_connect(sk, &entry, &addr_r); + err = userspace_pm_subflow_create(msk, &entry, &addr_r); release_sock(sk); - - spin_lock_bh(&msk->pm.lock); if (err) - mptcp_userspace_pm_delete_local_addr(msk, &entry); - else - msk->pm.subflows++; - spin_unlock_bh(&msk->pm.lock); + GENL_SET_ERR_MSG(info, "subflow_create failed"); create_err: sock_put(sk); @@ -457,6 +462,46 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk, return NULL; } +static int userspace_pm_subflow_destroy(struct mptcp_sock *msk, + struct mptcp_pm_addr_entry *local, + struct mptcp_addr_info *remote) +{ + struct sock *sk = (struct sock *)msk; + struct sock *ssk; + int err = -ESRCH; + +#if IS_ENABLED(CONFIG_MPTCP_IPV6) + if (local->addr.family == AF_INET && ipv6_addr_v4mapped(&remote->addr6)) { + ipv6_addr_set_v4mapped(local->addr.addr.s_addr, &remote->addr6); + local->addr.family = AF_INET6; + } + if (remote->family == AF_INET && ipv6_addr_v4mapped(&local->addr.addr6)) { + ipv6_addr_set_v4mapped(remote->addr.s_addr, &local->addr.addr6); + remote->family = AF_INET6; + } +#endif + if (local->addr.family != remote->family) + return -EINVAL; + + if (!local->addr.port || !remote->port) + return -EINVAL; + + ssk = mptcp_nl_find_ssk(msk, &local->addr, remote); + if (ssk) { + struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); + + spin_lock_bh(&msk->pm.lock); + mptcp_userspace_pm_delete_local_addr(msk, local); + spin_unlock_bh(&msk->pm.lock); + mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN); + mptcp_close_ssk(sk, ssk, subflow); + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW); + err = 0; + } + + return err; +} + int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info) { struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE]; @@ -464,8 +509,8 @@ int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info struct mptcp_pm_addr_entry local; struct mptcp_addr_info addr_r; struct mptcp_sock *msk; - struct sock *sk, *ssk; int err = -EINVAL; + struct sock *sk; if (!laddr || !raddr) { GENL_SET_ERR_MSG(info, "missing required inputs"); @@ -490,44 +535,11 @@ int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info goto destroy_err; } -#if IS_ENABLED(CONFIG_MPTCP_IPV6) - if (local.addr.family == AF_INET && ipv6_addr_v4mapped(&addr_r.addr6)) { - ipv6_addr_set_v4mapped(local.addr.addr.s_addr, &local.addr.addr6); - local.addr.family = AF_INET6; - } - if (addr_r.family == AF_INET && ipv6_addr_v4mapped(&local.addr.addr6)) { - ipv6_addr_set_v4mapped(addr_r.addr.s_addr, &local.addr.addr6); - addr_r.family = AF_INET6; - } -#endif - if (local.addr.family != addr_r.family) { - GENL_SET_ERR_MSG(info, "address families do not match"); - err = -EINVAL; - goto destroy_err; - } - - if (!local.addr.port || !addr_r.port) { - GENL_SET_ERR_MSG(info, "missing local or remote port"); - err = -EINVAL; - goto destroy_err; - } - lock_sock(sk); - ssk = mptcp_nl_find_ssk(msk, &local.addr, &addr_r); - if (ssk) { - struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); - - spin_lock_bh(&msk->pm.lock); - mptcp_userspace_pm_delete_local_addr(msk, &local); - spin_unlock_bh(&msk->pm.lock); - mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN); - mptcp_close_ssk(sk, ssk, subflow); - MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW); - err = 0; - } else { - err = -ESRCH; - } + err = userspace_pm_subflow_destroy(msk, &local, &addr_r); release_sock(sk); + if (err) + GENL_SET_ERR_MSG(info, "subflow_destroy failed"); destroy_err: sock_put(sk);