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