Merge tag 'nfs-for-5.11-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[linux-2.6-microblaze.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 <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 }