2020-03-27 14:48:51 -07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/* Multipath TCP
|
|
|
|
*
|
|
|
|
* Copyright (c) 2020, Red Hat, Inc.
|
|
|
|
*/
|
|
|
|
|
2020-04-03 17:14:08 +08:00
|
|
|
#define pr_fmt(fmt) "MPTCP: " fmt
|
|
|
|
|
2020-03-27 14:48:51 -07:00
|
|
|
#include "protocol.h"
|
2024-05-13 18:13:31 -07:00
|
|
|
#include "mptcp_pm_gen.h"
|
2020-03-27 14:48:51 -07:00
|
|
|
|
2021-02-12 16:00:01 -08:00
|
|
|
#define MPTCP_PM_CMD_GRP_OFFSET 0
|
|
|
|
#define MPTCP_PM_EV_GRP_OFFSET 1
|
2020-03-27 14:48:51 -07:00
|
|
|
|
|
|
|
static const struct genl_multicast_group mptcp_pm_mcgrps[] = {
|
|
|
|
[MPTCP_PM_CMD_GRP_OFFSET] = { .name = MPTCP_PM_CMD_GRP_NAME, },
|
2021-02-12 16:00:01 -08:00
|
|
|
[MPTCP_PM_EV_GRP_OFFSET] = { .name = MPTCP_PM_EV_GRP_NAME,
|
2023-12-20 17:43:58 +02:00
|
|
|
.flags = GENL_MCAST_CAP_NET_ADMIN,
|
2021-02-12 16:00:01 -08:00
|
|
|
},
|
2020-03-27 14:48:51 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static int mptcp_pm_family_to_addr(int family)
|
|
|
|
{
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
if (family == AF_INET6)
|
|
|
|
return MPTCP_PM_ADDR_ATTR_ADDR6;
|
|
|
|
#endif
|
|
|
|
return MPTCP_PM_ADDR_ATTR_ADDR4;
|
|
|
|
}
|
|
|
|
|
2022-05-03 19:38:51 -07:00
|
|
|
static int mptcp_pm_parse_pm_addr_attr(struct nlattr *tb[],
|
|
|
|
const struct nlattr *attr,
|
|
|
|
struct genl_info *info,
|
|
|
|
struct mptcp_addr_info *addr,
|
|
|
|
bool require_family)
|
2020-03-27 14:48:51 -07:00
|
|
|
{
|
|
|
|
int err, addr_addr;
|
|
|
|
|
|
|
|
if (!attr) {
|
|
|
|
GENL_SET_ERR_MSG(info, "missing address info");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no validation needed - was already done via nested policy */
|
|
|
|
err = nla_parse_nested_deprecated(tb, MPTCP_PM_ADDR_ATTR_MAX, attr,
|
2023-10-23 11:17:07 -07:00
|
|
|
mptcp_pm_address_nl_policy, info->extack);
|
2020-03-27 14:48:51 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-05-03 19:38:51 -07:00
|
|
|
if (tb[MPTCP_PM_ADDR_ATTR_ID])
|
|
|
|
addr->id = nla_get_u8(tb[MPTCP_PM_ADDR_ATTR_ID]);
|
|
|
|
|
2020-03-27 14:48:51 -07:00
|
|
|
if (!tb[MPTCP_PM_ADDR_ATTR_FAMILY]) {
|
|
|
|
if (!require_family)
|
2022-12-08 16:44:31 -08:00
|
|
|
return 0;
|
2020-03-27 14:48:51 -07:00
|
|
|
|
|
|
|
NL_SET_ERR_MSG_ATTR(info->extack, attr,
|
|
|
|
"missing family");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2022-05-03 19:38:51 -07:00
|
|
|
addr->family = nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_FAMILY]);
|
|
|
|
if (addr->family != AF_INET
|
2020-03-27 14:48:51 -07:00
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
2022-05-03 19:38:51 -07:00
|
|
|
&& addr->family != AF_INET6
|
2020-03-27 14:48:51 -07:00
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(info->extack, attr,
|
|
|
|
"unknown address family");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2022-05-03 19:38:51 -07:00
|
|
|
addr_addr = mptcp_pm_family_to_addr(addr->family);
|
2020-03-27 14:48:51 -07:00
|
|
|
if (!tb[addr_addr]) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(info->extack, attr,
|
|
|
|
"missing address data");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
2022-05-03 19:38:51 -07:00
|
|
|
if (addr->family == AF_INET6)
|
|
|
|
addr->addr6 = nla_get_in6_addr(tb[addr_addr]);
|
2020-03-27 14:48:51 -07:00
|
|
|
else
|
|
|
|
#endif
|
2022-05-03 19:38:51 -07:00
|
|
|
addr->addr.s_addr = nla_get_in_addr(tb[addr_addr]);
|
|
|
|
|
|
|
|
if (tb[MPTCP_PM_ADDR_ATTR_PORT])
|
|
|
|
addr->port = htons(nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]));
|
|
|
|
|
2022-12-08 16:44:31 -08:00
|
|
|
return 0;
|
2022-05-03 19:38:51 -07:00
|
|
|
}
|
|
|
|
|
mptcp: netlink: allow userspace-driven subflow establishment
This allows userspace to tell kernel to add a new subflow to an existing
mptcp connection.
Userspace provides the token to identify the mptcp-level connection
that needs a change in active subflows and the local and remote
addresses of the new or the to-be-removed subflow.
MPTCP_PM_CMD_SUBFLOW_CREATE requires the following parameters:
{ token, { loc_id, family, loc_addr4 | loc_addr6 }, { family, rem_addr4 |
rem_addr6, rem_port }
MPTCP_PM_CMD_SUBFLOW_DESTROY requires the following parameters:
{ token, { family, loc_addr4 | loc_addr6, loc_port }, { family, rem_addr4 |
rem_addr6, rem_port }
Acked-by: Paolo Abeni <pabeni@redhat.com>
Co-developed-by: Kishen Maloor <kishen.maloor@intel.com>
Signed-off-by: Kishen Maloor <kishen.maloor@intel.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2022-05-03 19:38:56 -07:00
|
|
|
int mptcp_pm_parse_addr(struct nlattr *attr, struct genl_info *info,
|
|
|
|
struct mptcp_addr_info *addr)
|
|
|
|
{
|
|
|
|
struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
|
|
|
|
return mptcp_pm_parse_pm_addr_attr(tb, attr, info, addr, true);
|
|
|
|
}
|
|
|
|
|
2022-05-03 19:38:52 -07:00
|
|
|
int mptcp_pm_parse_entry(struct nlattr *attr, struct genl_info *info,
|
|
|
|
bool require_family,
|
|
|
|
struct mptcp_pm_addr_entry *entry)
|
2022-05-03 19:38:51 -07:00
|
|
|
{
|
|
|
|
struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
memset(entry, 0, sizeof(*entry));
|
|
|
|
|
|
|
|
err = mptcp_pm_parse_pm_addr_attr(tb, attr, info, &entry->addr, require_family);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2020-03-27 14:48:51 -07:00
|
|
|
|
2020-09-14 10:01:15 +02:00
|
|
|
if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX]) {
|
|
|
|
u32 val = nla_get_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]);
|
|
|
|
|
2021-04-06 17:15:57 -07:00
|
|
|
entry->ifindex = val;
|
2020-09-14 10:01:15 +02:00
|
|
|
}
|
2020-03-27 14:48:51 -07:00
|
|
|
|
|
|
|
if (tb[MPTCP_PM_ADDR_ATTR_FLAGS])
|
2021-04-06 17:15:57 -07:00
|
|
|
entry->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
|
2020-03-27 14:48:51 -07:00
|
|
|
|
2022-02-04 16:03:29 -08:00
|
|
|
if (tb[MPTCP_PM_ADDR_ATTR_PORT])
|
2021-02-01 15:09:17 -08:00
|
|
|
entry->addr.port = htons(nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]));
|
|
|
|
|
2020-03-27 14:48:51 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
mptcp: pm: move Netlink PM helpers to pm_netlink.c
Before this patch, the PM code was dispersed in different places:
- pm.c had common code for all PMs, but also Netlink specific code that
will not be needed with the future BPF path-managers.
- pm_netlink.c had common Netlink code.
To clarify the code, a reorganisation is suggested here, only by moving
code around, and small helper renaming to avoid confusions:
- pm_netlink.c now only contains common PM Netlink code:
- PM events: this code was already there
- shared helpers around Netlink code that were already there as well
- shared Netlink commands code from pm.c
- pm.c now no longer contain Netlink specific code.
- protocol.h has been updated accordingly:
- mptcp_nl_fill_addr() no longer need to be exported.
The code around the PM is now less confusing, which should help for the
maintenance in the long term.
This will certainly impact future backports, but because other cleanups
have already done recently, and more are coming to ease the addition of
a new path-manager controlled with BPF (struct_ops), doing that now
seems to be a good time. Also, many issues around the PM have been fixed
a few months ago while increasing the code coverage in the selftests, so
such big reorganisation can be done with more confidence now.
No behavioural changes intended.
Reviewed-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20250307-net-next-mptcp-pm-reorg-v1-15-abef20ada03b@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-03-07 12:21:59 +01:00
|
|
|
static int mptcp_nl_fill_addr(struct sk_buff *skb,
|
|
|
|
struct mptcp_pm_addr_entry *entry)
|
2020-03-27 14:48:51 -07:00
|
|
|
{
|
|
|
|
struct mptcp_addr_info *addr = &entry->addr;
|
|
|
|
struct nlattr *attr;
|
|
|
|
|
|
|
|
attr = nla_nest_start(skb, MPTCP_PM_ATTR_ADDR);
|
|
|
|
if (!attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u16(skb, MPTCP_PM_ADDR_ATTR_FAMILY, addr->family))
|
|
|
|
goto nla_put_failure;
|
2021-02-01 15:09:17 -08:00
|
|
|
if (nla_put_u16(skb, MPTCP_PM_ADDR_ATTR_PORT, ntohs(addr->port)))
|
|
|
|
goto nla_put_failure;
|
2020-03-27 14:48:51 -07:00
|
|
|
if (nla_put_u8(skb, MPTCP_PM_ADDR_ATTR_ID, addr->id))
|
|
|
|
goto nla_put_failure;
|
2021-04-06 17:15:57 -07:00
|
|
|
if (nla_put_u32(skb, MPTCP_PM_ADDR_ATTR_FLAGS, entry->flags))
|
2020-03-27 14:48:51 -07:00
|
|
|
goto nla_put_failure;
|
2021-04-06 17:15:57 -07:00
|
|
|
if (entry->ifindex &&
|
|
|
|
nla_put_s32(skb, MPTCP_PM_ADDR_ATTR_IF_IDX, entry->ifindex))
|
2020-03-27 14:48:51 -07:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
2020-04-23 10:10:03 +08:00
|
|
|
if (addr->family == AF_INET &&
|
|
|
|
nla_put_in_addr(skb, MPTCP_PM_ADDR_ATTR_ADDR4,
|
|
|
|
addr->addr.s_addr))
|
|
|
|
goto nla_put_failure;
|
2020-03-27 14:48:51 -07:00
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
2020-04-23 10:10:03 +08:00
|
|
|
else if (addr->family == AF_INET6 &&
|
|
|
|
nla_put_in6_addr(skb, MPTCP_PM_ADDR_ATTR_ADDR6, &addr->addr6))
|
|
|
|
goto nla_put_failure;
|
2020-03-27 14:48:51 -07:00
|
|
|
#endif
|
|
|
|
nla_nest_end(skb, attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(skb, attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
mptcp: pm: move Netlink PM helpers to pm_netlink.c
Before this patch, the PM code was dispersed in different places:
- pm.c had common code for all PMs, but also Netlink specific code that
will not be needed with the future BPF path-managers.
- pm_netlink.c had common Netlink code.
To clarify the code, a reorganisation is suggested here, only by moving
code around, and small helper renaming to avoid confusions:
- pm_netlink.c now only contains common PM Netlink code:
- PM events: this code was already there
- shared helpers around Netlink code that were already there as well
- shared Netlink commands code from pm.c
- pm.c now no longer contain Netlink specific code.
- protocol.h has been updated accordingly:
- mptcp_nl_fill_addr() no longer need to be exported.
The code around the PM is now less confusing, which should help for the
maintenance in the long term.
This will certainly impact future backports, but because other cleanups
have already done recently, and more are coming to ease the addition of
a new path-manager controlled with BPF (struct_ops), doing that now
seems to be a good time. Also, many issues around the PM have been fixed
a few months ago while increasing the code coverage in the selftests, so
such big reorganisation can be done with more confidence now.
No behavioural changes intended.
Reviewed-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20250307-net-next-mptcp-pm-reorg-v1-15-abef20ada03b@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-03-07 12:21:59 +01:00
|
|
|
static int mptcp_pm_get_addr(u8 id, struct mptcp_pm_addr_entry *addr,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
if (info->attrs[MPTCP_PM_ATTR_TOKEN])
|
|
|
|
return mptcp_userspace_pm_get_addr(id, addr, info);
|
|
|
|
return mptcp_pm_nl_get_addr(id, addr, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mptcp_pm_nl_get_addr_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct mptcp_pm_addr_entry addr;
|
|
|
|
struct nlattr *attr;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *reply;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ENDPOINT_ADDR))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR];
|
|
|
|
ret = mptcp_pm_parse_entry(attr, info, false, &addr);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
reply = genlmsg_put_reply(msg, info, &mptcp_genl_family, 0,
|
|
|
|
info->genlhdr->cmd);
|
|
|
|
if (!reply) {
|
|
|
|
GENL_SET_ERR_MSG(info, "not enough space in Netlink message");
|
|
|
|
ret = -EMSGSIZE;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = mptcp_pm_get_addr(addr.addr.id, &addr, info);
|
|
|
|
if (ret) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(info->extack, attr, "address not found");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = mptcp_nl_fill_addr(msg, &addr);
|
|
|
|
if (ret)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
genlmsg_end(msg, reply);
|
|
|
|
ret = genlmsg_reply(msg, info);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mptcp_pm_genl_fill_addr(struct sk_buff *msg,
|
|
|
|
struct netlink_callback *cb,
|
|
|
|
struct mptcp_pm_addr_entry *entry)
|
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq, &mptcp_genl_family,
|
|
|
|
NLM_F_MULTI, MPTCP_PM_CMD_GET_ADDR);
|
|
|
|
if (!hdr)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (mptcp_nl_fill_addr(msg, entry) < 0) {
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mptcp_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
const struct genl_info *info = genl_info_dump(cb);
|
|
|
|
|
|
|
|
if (info->attrs[MPTCP_PM_ATTR_TOKEN])
|
|
|
|
return mptcp_userspace_pm_dump_addr(msg, cb);
|
|
|
|
return mptcp_pm_nl_dump_addr(msg, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mptcp_pm_nl_get_addr_dumpit(struct sk_buff *msg,
|
|
|
|
struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
return mptcp_pm_dump_addr(msg, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mptcp_pm_set_flags(struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct mptcp_pm_addr_entry loc = { .addr = { .family = AF_UNSPEC }, };
|
|
|
|
struct nlattr *attr_loc;
|
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
if (GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ATTR_ADDR))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
attr_loc = info->attrs[MPTCP_PM_ATTR_ADDR];
|
|
|
|
ret = mptcp_pm_parse_entry(attr_loc, info, false, &loc);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (info->attrs[MPTCP_PM_ATTR_TOKEN])
|
|
|
|
return mptcp_userspace_pm_set_flags(&loc, info);
|
|
|
|
return mptcp_pm_nl_set_flags(&loc, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mptcp_pm_nl_set_flags_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
return mptcp_pm_set_flags(info);
|
|
|
|
}
|
|
|
|
|
2021-02-12 16:00:01 -08:00
|
|
|
static void mptcp_nl_mcast_send(struct net *net, struct sk_buff *nlskb, gfp_t gfp)
|
|
|
|
{
|
|
|
|
genlmsg_multicast_netns(&mptcp_genl_family, net,
|
|
|
|
nlskb, 0, MPTCP_PM_EV_GRP_OFFSET, gfp);
|
|
|
|
}
|
|
|
|
|
2022-05-02 13:52:31 -07:00
|
|
|
bool mptcp_userspace_pm_active(const struct mptcp_sock *msk)
|
|
|
|
{
|
|
|
|
return genl_has_listeners(&mptcp_genl_family,
|
|
|
|
sock_net((const struct sock *)msk),
|
|
|
|
MPTCP_PM_EV_GRP_OFFSET);
|
|
|
|
}
|
|
|
|
|
2021-02-12 16:00:01 -08:00
|
|
|
static int mptcp_event_add_subflow(struct sk_buff *skb, const struct sock *ssk)
|
|
|
|
{
|
|
|
|
const struct inet_sock *issk = inet_sk(ssk);
|
|
|
|
const struct mptcp_subflow_context *sf;
|
|
|
|
|
|
|
|
if (nla_put_u16(skb, MPTCP_ATTR_FAMILY, ssk->sk_family))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
switch (ssk->sk_family) {
|
|
|
|
case AF_INET:
|
|
|
|
if (nla_put_in_addr(skb, MPTCP_ATTR_SADDR4, issk->inet_saddr))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (nla_put_in_addr(skb, MPTCP_ATTR_DADDR4, issk->inet_daddr))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
break;
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
case AF_INET6: {
|
2025-02-21 16:43:59 +01:00
|
|
|
if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &issk->pinet6->saddr))
|
2021-02-12 16:00:01 -08:00
|
|
|
return -EMSGSIZE;
|
|
|
|
if (nla_put_in6_addr(skb, MPTCP_ATTR_DADDR6, &ssk->sk_v6_daddr))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nla_put_be16(skb, MPTCP_ATTR_SPORT, issk->inet_sport))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (nla_put_be16(skb, MPTCP_ATTR_DPORT, issk->inet_dport))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
sf = mptcp_subflow_ctx(ssk);
|
|
|
|
if (WARN_ON_ONCE(!sf))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2024-02-15 19:25:31 +01:00
|
|
|
if (nla_put_u8(skb, MPTCP_ATTR_LOC_ID, subflow_get_local_id(sf)))
|
2021-02-12 16:00:01 -08:00
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, sf->remote_id))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mptcp_event_put_token_and_ssk(struct sk_buff *skb,
|
|
|
|
const struct mptcp_sock *msk,
|
|
|
|
const struct sock *ssk)
|
|
|
|
{
|
|
|
|
const struct sock *sk = (const struct sock *)msk;
|
|
|
|
const struct mptcp_subflow_context *sf;
|
|
|
|
u8 sk_err;
|
|
|
|
|
2024-02-02 12:40:10 +01:00
|
|
|
if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)))
|
2021-02-12 16:00:01 -08:00
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (mptcp_event_add_subflow(skb, ssk))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
sf = mptcp_subflow_ctx(ssk);
|
|
|
|
if (WARN_ON_ONCE(!sf))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (nla_put_u8(skb, MPTCP_ATTR_BACKUP, sf->backup))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (ssk->sk_bound_dev_if &&
|
|
|
|
nla_put_s32(skb, MPTCP_ATTR_IF_IDX, ssk->sk_bound_dev_if))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
2023-03-15 20:57:45 +00:00
|
|
|
sk_err = READ_ONCE(ssk->sk_err);
|
2021-02-12 16:00:01 -08:00
|
|
|
if (sk_err && sk->sk_state == TCP_ESTABLISHED &&
|
|
|
|
nla_put_u8(skb, MPTCP_ATTR_ERROR, sk_err))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mptcp_event_sub_established(struct sk_buff *skb,
|
|
|
|
const struct mptcp_sock *msk,
|
|
|
|
const struct sock *ssk)
|
|
|
|
{
|
|
|
|
return mptcp_event_put_token_and_ssk(skb, msk, ssk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mptcp_event_sub_closed(struct sk_buff *skb,
|
|
|
|
const struct mptcp_sock *msk,
|
|
|
|
const struct sock *ssk)
|
|
|
|
{
|
2021-04-01 16:19:44 -07:00
|
|
|
const struct mptcp_subflow_context *sf;
|
|
|
|
|
2021-02-12 16:00:01 -08:00
|
|
|
if (mptcp_event_put_token_and_ssk(skb, msk, ssk))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
2021-04-01 16:19:44 -07:00
|
|
|
sf = mptcp_subflow_ctx(ssk);
|
|
|
|
if (!sf->reset_seen)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (nla_put_u32(skb, MPTCP_ATTR_RESET_REASON, sf->reset_reason))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u32(skb, MPTCP_ATTR_RESET_FLAGS, sf->reset_transient))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
2021-02-12 16:00:01 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mptcp_event_created(struct sk_buff *skb,
|
|
|
|
const struct mptcp_sock *msk,
|
|
|
|
const struct sock *ssk)
|
|
|
|
{
|
2024-02-02 12:40:10 +01:00
|
|
|
int err = nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token));
|
2021-02-12 16:00:01 -08:00
|
|
|
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-05-02 13:52:36 -07:00
|
|
|
if (nla_put_u8(skb, MPTCP_ATTR_SERVER_SIDE, READ_ONCE(msk->pm.server_side)))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
2021-02-12 16:00:01 -08:00
|
|
|
return mptcp_event_add_subflow(skb, ssk);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mptcp_event_addr_removed(const struct mptcp_sock *msk, uint8_t id)
|
|
|
|
{
|
|
|
|
struct net *net = sock_net((const struct sock *)msk);
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
|
|
|
|
return;
|
|
|
|
|
|
|
|
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
|
|
|
if (!skb)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0, MPTCP_EVENT_REMOVED);
|
|
|
|
if (!nlh)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2024-02-02 12:40:10 +01:00
|
|
|
if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)))
|
2021-02-12 16:00:01 -08:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, id))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(skb, nlh);
|
|
|
|
mptcp_nl_mcast_send(net, skb, GFP_ATOMIC);
|
|
|
|
return;
|
|
|
|
|
|
|
|
nla_put_failure:
|
2022-12-08 16:44:30 -08:00
|
|
|
nlmsg_free(skb);
|
2021-02-12 16:00:01 -08:00
|
|
|
}
|
|
|
|
|
2022-05-02 13:52:34 -07:00
|
|
|
void mptcp_event_addr_announced(const struct sock *ssk,
|
2021-02-12 16:00:01 -08:00
|
|
|
const struct mptcp_addr_info *info)
|
|
|
|
{
|
2022-05-02 13:52:34 -07:00
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
|
|
|
|
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
|
|
|
|
struct net *net = sock_net(ssk);
|
2021-02-12 16:00:01 -08:00
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
|
|
|
|
return;
|
|
|
|
|
|
|
|
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
|
|
|
if (!skb)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0,
|
|
|
|
MPTCP_EVENT_ANNOUNCED);
|
|
|
|
if (!nlh)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2024-02-02 12:40:10 +01:00
|
|
|
if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)))
|
2021-02-12 16:00:01 -08:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, info->id))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2022-05-02 13:52:34 -07:00
|
|
|
if (nla_put_be16(skb, MPTCP_ATTR_DPORT,
|
|
|
|
info->port == 0 ?
|
|
|
|
inet_sk(ssk)->inet_dport :
|
|
|
|
info->port))
|
2021-02-12 16:00:01 -08:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
switch (info->family) {
|
|
|
|
case AF_INET:
|
|
|
|
if (nla_put_in_addr(skb, MPTCP_ATTR_DADDR4, info->addr.s_addr))
|
|
|
|
goto nla_put_failure;
|
|
|
|
break;
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
case AF_INET6:
|
|
|
|
if (nla_put_in6_addr(skb, MPTCP_ATTR_DADDR6, &info->addr6))
|
|
|
|
goto nla_put_failure;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_end(skb, nlh);
|
|
|
|
mptcp_nl_mcast_send(net, skb, GFP_ATOMIC);
|
|
|
|
return;
|
|
|
|
|
|
|
|
nla_put_failure:
|
2022-12-08 16:44:30 -08:00
|
|
|
nlmsg_free(skb);
|
2021-02-12 16:00:01 -08:00
|
|
|
}
|
|
|
|
|
2022-11-30 15:06:28 +01:00
|
|
|
void mptcp_event_pm_listener(const struct sock *ssk,
|
|
|
|
enum mptcp_event_type event)
|
|
|
|
{
|
|
|
|
const struct inet_sock *issk = inet_sk(ssk);
|
|
|
|
struct net *net = sock_net(ssk);
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
|
|
|
|
return;
|
|
|
|
|
|
|
|
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!skb)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0, event);
|
|
|
|
if (!nlh)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u16(skb, MPTCP_ATTR_FAMILY, ssk->sk_family))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_be16(skb, MPTCP_ATTR_SPORT, issk->inet_sport))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
switch (ssk->sk_family) {
|
|
|
|
case AF_INET:
|
|
|
|
if (nla_put_in_addr(skb, MPTCP_ATTR_SADDR4, issk->inet_saddr))
|
|
|
|
goto nla_put_failure;
|
|
|
|
break;
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
case AF_INET6: {
|
2025-02-21 16:43:59 +01:00
|
|
|
if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &issk->pinet6->saddr))
|
2022-11-30 15:06:28 +01:00
|
|
|
goto nla_put_failure;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_end(skb, nlh);
|
|
|
|
mptcp_nl_mcast_send(net, skb, GFP_KERNEL);
|
|
|
|
return;
|
|
|
|
|
|
|
|
nla_put_failure:
|
2022-12-08 16:44:30 -08:00
|
|
|
nlmsg_free(skb);
|
2022-11-30 15:06:28 +01:00
|
|
|
}
|
|
|
|
|
2021-02-12 16:00:01 -08:00
|
|
|
void mptcp_event(enum mptcp_event_type type, const struct mptcp_sock *msk,
|
|
|
|
const struct sock *ssk, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct net *net = sock_net((const struct sock *)msk);
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
|
|
|
|
return;
|
|
|
|
|
|
|
|
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
|
|
|
if (!skb)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0, type);
|
|
|
|
if (!nlh)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case MPTCP_EVENT_UNSPEC:
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
break;
|
|
|
|
case MPTCP_EVENT_CREATED:
|
|
|
|
case MPTCP_EVENT_ESTABLISHED:
|
|
|
|
if (mptcp_event_created(skb, msk, ssk) < 0)
|
|
|
|
goto nla_put_failure;
|
|
|
|
break;
|
|
|
|
case MPTCP_EVENT_CLOSED:
|
2024-02-02 12:40:10 +01:00
|
|
|
if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)) < 0)
|
2021-02-12 16:00:01 -08:00
|
|
|
goto nla_put_failure;
|
|
|
|
break;
|
|
|
|
case MPTCP_EVENT_ANNOUNCED:
|
|
|
|
case MPTCP_EVENT_REMOVED:
|
|
|
|
/* call mptcp_event_addr_announced()/removed instead */
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
break;
|
|
|
|
case MPTCP_EVENT_SUB_ESTABLISHED:
|
|
|
|
case MPTCP_EVENT_SUB_PRIORITY:
|
|
|
|
if (mptcp_event_sub_established(skb, msk, ssk) < 0)
|
|
|
|
goto nla_put_failure;
|
|
|
|
break;
|
|
|
|
case MPTCP_EVENT_SUB_CLOSED:
|
|
|
|
if (mptcp_event_sub_closed(skb, msk, ssk) < 0)
|
|
|
|
goto nla_put_failure;
|
|
|
|
break;
|
2022-11-30 15:06:28 +01:00
|
|
|
case MPTCP_EVENT_LISTENER_CREATED:
|
|
|
|
case MPTCP_EVENT_LISTENER_CLOSED:
|
|
|
|
break;
|
2021-02-12 16:00:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_end(skb, nlh);
|
|
|
|
mptcp_nl_mcast_send(net, skb, gfp);
|
|
|
|
return;
|
|
|
|
|
|
|
|
nla_put_failure:
|
2022-12-08 16:44:30 -08:00
|
|
|
nlmsg_free(skb);
|
2021-02-12 16:00:01 -08:00
|
|
|
}
|
|
|
|
|
2024-03-01 19:18:26 +01:00
|
|
|
struct genl_family mptcp_genl_family __ro_after_init = {
|
2020-03-27 14:48:51 -07:00
|
|
|
.name = MPTCP_PM_NAME,
|
|
|
|
.version = MPTCP_PM_VER,
|
|
|
|
.netnsok = true,
|
|
|
|
.module = THIS_MODULE,
|
2023-10-23 11:17:10 -07:00
|
|
|
.ops = mptcp_pm_nl_ops,
|
|
|
|
.n_ops = ARRAY_SIZE(mptcp_pm_nl_ops),
|
2022-08-24 17:18:30 -07:00
|
|
|
.resv_start_op = MPTCP_PM_CMD_SUBFLOW_DESTROY + 1,
|
2020-03-27 14:48:51 -07:00
|
|
|
.mcgrps = mptcp_pm_mcgrps,
|
|
|
|
.n_mcgrps = ARRAY_SIZE(mptcp_pm_mcgrps),
|
|
|
|
};
|
2025-03-13 11:20:50 +01:00
|
|
|
|
|
|
|
void __init mptcp_pm_nl_init(void)
|
|
|
|
{
|
|
|
|
if (genl_register_family(&mptcp_genl_family))
|
|
|
|
panic("Failed to register MPTCP PM netlink family\n");
|
|
|
|
}
|