]>
Commit | Line | Data |
---|---|---|
5147dfb5 DC |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* MPTCP socket monitoring support | |
3 | * | |
4 | * Copyright (c) 2019 Red Hat | |
5 | * | |
6 | * Author: Davide Caratti <[email protected]> | |
7 | */ | |
8 | ||
9 | #include <linux/kernel.h> | |
10 | #include <linux/net.h> | |
11 | #include <linux/inet_diag.h> | |
12 | #include <net/netlink.h> | |
13 | #include <uapi/linux/mptcp.h> | |
14 | #include "protocol.h" | |
15 | ||
16 | static int subflow_get_info(const struct sock *sk, struct sk_buff *skb) | |
17 | { | |
18 | struct mptcp_subflow_context *sf; | |
19 | struct nlattr *start; | |
20 | u32 flags = 0; | |
21 | int err; | |
22 | ||
23 | start = nla_nest_start_noflag(skb, INET_ULP_INFO_MPTCP); | |
24 | if (!start) | |
25 | return -EMSGSIZE; | |
26 | ||
27 | rcu_read_lock(); | |
28 | sf = rcu_dereference(inet_csk(sk)->icsk_ulp_data); | |
29 | if (!sf) { | |
30 | err = 0; | |
31 | goto nla_failure; | |
32 | } | |
33 | ||
34 | if (sf->mp_capable) | |
35 | flags |= MPTCP_SUBFLOW_FLAG_MCAP_REM; | |
36 | if (sf->request_mptcp) | |
37 | flags |= MPTCP_SUBFLOW_FLAG_MCAP_LOC; | |
38 | if (sf->mp_join) | |
39 | flags |= MPTCP_SUBFLOW_FLAG_JOIN_REM; | |
40 | if (sf->request_join) | |
41 | flags |= MPTCP_SUBFLOW_FLAG_JOIN_LOC; | |
42 | if (sf->backup) | |
43 | flags |= MPTCP_SUBFLOW_FLAG_BKUP_REM; | |
44 | if (sf->request_bkup) | |
45 | flags |= MPTCP_SUBFLOW_FLAG_BKUP_LOC; | |
46 | if (sf->fully_established) | |
47 | flags |= MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED; | |
48 | if (sf->conn_finished) | |
49 | flags |= MPTCP_SUBFLOW_FLAG_CONNECTED; | |
50 | if (sf->map_valid) | |
51 | flags |= MPTCP_SUBFLOW_FLAG_MAPVALID; | |
52 | ||
53 | if (nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_TOKEN_REM, sf->remote_token) || | |
54 | nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_TOKEN_LOC, sf->token) || | |
55 | nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ, | |
56 | sf->rel_write_seq) || | |
57 | nla_put_u64_64bit(skb, MPTCP_SUBFLOW_ATTR_MAP_SEQ, sf->map_seq, | |
58 | MPTCP_SUBFLOW_ATTR_PAD) || | |
59 | nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_MAP_SFSEQ, | |
60 | sf->map_subflow_seq) || | |
61 | nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_SSN_OFFSET, sf->ssn_offset) || | |
62 | nla_put_u16(skb, MPTCP_SUBFLOW_ATTR_MAP_DATALEN, | |
63 | sf->map_data_len) || | |
64 | nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_FLAGS, flags) || | |
65 | nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_REM, sf->remote_id) || | |
66 | nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_LOC, sf->local_id)) { | |
67 | err = -EMSGSIZE; | |
68 | goto nla_failure; | |
69 | } | |
70 | ||
71 | rcu_read_unlock(); | |
72 | nla_nest_end(skb, start); | |
73 | return 0; | |
74 | ||
75 | nla_failure: | |
76 | rcu_read_unlock(); | |
77 | nla_nest_cancel(skb, start); | |
78 | return err; | |
79 | } | |
80 | ||
81 | static size_t subflow_get_info_size(const struct sock *sk) | |
82 | { | |
83 | size_t size = 0; | |
84 | ||
85 | size += nla_total_size(0) + /* INET_ULP_INFO_MPTCP */ | |
86 | nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_TOKEN_REM */ | |
87 | nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_TOKEN_LOC */ | |
88 | nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ */ | |
89 | nla_total_size_64bit(8) + /* MPTCP_SUBFLOW_ATTR_MAP_SEQ */ | |
90 | nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_MAP_SFSEQ */ | |
91 | nla_total_size(2) + /* MPTCP_SUBFLOW_ATTR_SSN_OFFSET */ | |
92 | nla_total_size(2) + /* MPTCP_SUBFLOW_ATTR_MAP_DATALEN */ | |
93 | nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_FLAGS */ | |
94 | nla_total_size(1) + /* MPTCP_SUBFLOW_ATTR_ID_REM */ | |
95 | nla_total_size(1) + /* MPTCP_SUBFLOW_ATTR_ID_LOC */ | |
96 | 0; | |
97 | return size; | |
98 | } | |
99 | ||
100 | void mptcp_diag_subflow_init(struct tcp_ulp_ops *ops) | |
101 | { | |
102 | ops->get_info = subflow_get_info; | |
103 | ops->get_info_size = subflow_get_info_size; | |
104 | } |