18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* MPTCP socket monitoring support 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2019 Red Hat 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: Davide Caratti <dcaratti@redhat.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/net.h> 118c2ecf20Sopenharmony_ci#include <linux/inet_diag.h> 128c2ecf20Sopenharmony_ci#include <net/netlink.h> 138c2ecf20Sopenharmony_ci#include <uapi/linux/mptcp.h> 148c2ecf20Sopenharmony_ci#include "protocol.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic int subflow_get_info(const struct sock *sk, struct sk_buff *skb) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct mptcp_subflow_context *sf; 198c2ecf20Sopenharmony_ci struct nlattr *start; 208c2ecf20Sopenharmony_ci u32 flags = 0; 218c2ecf20Sopenharmony_ci int err; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci start = nla_nest_start_noflag(skb, INET_ULP_INFO_MPTCP); 248c2ecf20Sopenharmony_ci if (!start) 258c2ecf20Sopenharmony_ci return -EMSGSIZE; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci rcu_read_lock(); 288c2ecf20Sopenharmony_ci sf = rcu_dereference(inet_csk(sk)->icsk_ulp_data); 298c2ecf20Sopenharmony_ci if (!sf) { 308c2ecf20Sopenharmony_ci err = 0; 318c2ecf20Sopenharmony_ci goto nla_failure; 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (sf->mp_capable) 358c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_MCAP_REM; 368c2ecf20Sopenharmony_ci if (sf->request_mptcp) 378c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_MCAP_LOC; 388c2ecf20Sopenharmony_ci if (sf->mp_join) 398c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_JOIN_REM; 408c2ecf20Sopenharmony_ci if (sf->request_join) 418c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_JOIN_LOC; 428c2ecf20Sopenharmony_ci if (sf->backup) 438c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_BKUP_REM; 448c2ecf20Sopenharmony_ci if (sf->request_bkup) 458c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_BKUP_LOC; 468c2ecf20Sopenharmony_ci if (sf->fully_established) 478c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED; 488c2ecf20Sopenharmony_ci if (sf->conn_finished) 498c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_CONNECTED; 508c2ecf20Sopenharmony_ci if (sf->map_valid) 518c2ecf20Sopenharmony_ci flags |= MPTCP_SUBFLOW_FLAG_MAPVALID; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_TOKEN_REM, sf->remote_token) || 548c2ecf20Sopenharmony_ci nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_TOKEN_LOC, sf->token) || 558c2ecf20Sopenharmony_ci nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ, 568c2ecf20Sopenharmony_ci sf->rel_write_seq) || 578c2ecf20Sopenharmony_ci nla_put_u64_64bit(skb, MPTCP_SUBFLOW_ATTR_MAP_SEQ, sf->map_seq, 588c2ecf20Sopenharmony_ci MPTCP_SUBFLOW_ATTR_PAD) || 598c2ecf20Sopenharmony_ci nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_MAP_SFSEQ, 608c2ecf20Sopenharmony_ci sf->map_subflow_seq) || 618c2ecf20Sopenharmony_ci nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_SSN_OFFSET, sf->ssn_offset) || 628c2ecf20Sopenharmony_ci nla_put_u16(skb, MPTCP_SUBFLOW_ATTR_MAP_DATALEN, 638c2ecf20Sopenharmony_ci sf->map_data_len) || 648c2ecf20Sopenharmony_ci nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_FLAGS, flags) || 658c2ecf20Sopenharmony_ci nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_REM, sf->remote_id) || 668c2ecf20Sopenharmony_ci nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_LOC, sf->local_id)) { 678c2ecf20Sopenharmony_ci err = -EMSGSIZE; 688c2ecf20Sopenharmony_ci goto nla_failure; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci rcu_read_unlock(); 728c2ecf20Sopenharmony_ci nla_nest_end(skb, start); 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cinla_failure: 768c2ecf20Sopenharmony_ci rcu_read_unlock(); 778c2ecf20Sopenharmony_ci nla_nest_cancel(skb, start); 788c2ecf20Sopenharmony_ci return err; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic size_t subflow_get_info_size(const struct sock *sk) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci size_t size = 0; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci size += nla_total_size(0) + /* INET_ULP_INFO_MPTCP */ 868c2ecf20Sopenharmony_ci nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_TOKEN_REM */ 878c2ecf20Sopenharmony_ci nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_TOKEN_LOC */ 888c2ecf20Sopenharmony_ci nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ */ 898c2ecf20Sopenharmony_ci nla_total_size_64bit(8) + /* MPTCP_SUBFLOW_ATTR_MAP_SEQ */ 908c2ecf20Sopenharmony_ci nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_MAP_SFSEQ */ 918c2ecf20Sopenharmony_ci nla_total_size(2) + /* MPTCP_SUBFLOW_ATTR_SSN_OFFSET */ 928c2ecf20Sopenharmony_ci nla_total_size(2) + /* MPTCP_SUBFLOW_ATTR_MAP_DATALEN */ 938c2ecf20Sopenharmony_ci nla_total_size(4) + /* MPTCP_SUBFLOW_ATTR_FLAGS */ 948c2ecf20Sopenharmony_ci nla_total_size(1) + /* MPTCP_SUBFLOW_ATTR_ID_REM */ 958c2ecf20Sopenharmony_ci nla_total_size(1) + /* MPTCP_SUBFLOW_ATTR_ID_LOC */ 968c2ecf20Sopenharmony_ci 0; 978c2ecf20Sopenharmony_ci return size; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_civoid mptcp_diag_subflow_init(struct tcp_ulp_ops *ops) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci ops->get_info = subflow_get_info; 1038c2ecf20Sopenharmony_ci ops->get_info_size = subflow_get_info_size; 1048c2ecf20Sopenharmony_ci} 105