2020-03-27 14:48:49 -07:00
// SPDX-License-Identifier: GPL-2.0
/* MPTCP socket monitoring support
*
* Copyright ( c ) 2019 Red Hat
*
* Author : Davide Caratti < dcaratti @ redhat . com >
*/
# include <linux/kernel.h>
# include <linux/net.h>
# include <linux/inet_diag.h>
# include <net/netlink.h>
# include "protocol.h"
2024-02-15 19:25:30 +01:00
static int subflow_get_info ( struct sock * sk , struct sk_buff * skb )
2020-03-27 14:48:49 -07:00
{
struct mptcp_subflow_context * sf ;
struct nlattr * start ;
u32 flags = 0 ;
2024-02-15 19:25:30 +01:00
bool slow ;
2020-03-27 14:48:49 -07:00
int err ;
2024-02-23 17:14:19 +01:00
if ( inet_sk_state_load ( sk ) = = TCP_LISTEN )
return 0 ;
2020-03-27 14:48:49 -07:00
start = nla_nest_start_noflag ( skb , INET_ULP_INFO_MPTCP ) ;
if ( ! start )
return - EMSGSIZE ;
2024-02-15 19:25:30 +01:00
slow = lock_sock_fast ( sk ) ;
2020-03-27 14:48:49 -07:00
rcu_read_lock ( ) ;
sf = rcu_dereference ( inet_csk ( sk ) - > icsk_ulp_data ) ;
if ( ! sf ) {
err = 0 ;
goto nla_failure ;
}
if ( sf - > mp_capable )
flags | = MPTCP_SUBFLOW_FLAG_MCAP_REM ;
if ( sf - > request_mptcp )
flags | = MPTCP_SUBFLOW_FLAG_MCAP_LOC ;
if ( sf - > mp_join )
flags | = MPTCP_SUBFLOW_FLAG_JOIN_REM ;
if ( sf - > request_join )
flags | = MPTCP_SUBFLOW_FLAG_JOIN_LOC ;
if ( sf - > backup )
flags | = MPTCP_SUBFLOW_FLAG_BKUP_REM ;
if ( sf - > request_bkup )
flags | = MPTCP_SUBFLOW_FLAG_BKUP_LOC ;
if ( sf - > fully_established )
flags | = MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED ;
if ( sf - > conn_finished )
flags | = MPTCP_SUBFLOW_FLAG_CONNECTED ;
if ( sf - > map_valid )
flags | = MPTCP_SUBFLOW_FLAG_MAPVALID ;
if ( nla_put_u32 ( skb , MPTCP_SUBFLOW_ATTR_TOKEN_REM , sf - > remote_token ) | |
nla_put_u32 ( skb , MPTCP_SUBFLOW_ATTR_TOKEN_LOC , sf - > token ) | |
nla_put_u32 ( skb , MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ ,
sf - > rel_write_seq ) | |
nla_put_u64_64bit ( skb , MPTCP_SUBFLOW_ATTR_MAP_SEQ , sf - > map_seq ,
MPTCP_SUBFLOW_ATTR_PAD ) | |
nla_put_u32 ( skb , MPTCP_SUBFLOW_ATTR_MAP_SFSEQ ,
sf - > map_subflow_seq ) | |
nla_put_u32 ( skb , MPTCP_SUBFLOW_ATTR_SSN_OFFSET , sf - > ssn_offset ) | |
nla_put_u16 ( skb , MPTCP_SUBFLOW_ATTR_MAP_DATALEN ,
sf - > map_data_len ) | |
nla_put_u32 ( skb , MPTCP_SUBFLOW_ATTR_FLAGS , flags ) | |
nla_put_u8 ( skb , MPTCP_SUBFLOW_ATTR_ID_REM , sf - > remote_id ) | |
2024-02-15 19:25:31 +01:00
nla_put_u8 ( skb , MPTCP_SUBFLOW_ATTR_ID_LOC , subflow_get_local_id ( sf ) ) ) {
2020-03-27 14:48:49 -07:00
err = - EMSGSIZE ;
goto nla_failure ;
}
rcu_read_unlock ( ) ;
2024-02-15 19:25:30 +01:00
unlock_sock_fast ( sk , slow ) ;
2020-03-27 14:48:49 -07:00
nla_nest_end ( skb , start ) ;
return 0 ;
nla_failure :
rcu_read_unlock ( ) ;
2024-02-15 19:25:30 +01:00
unlock_sock_fast ( sk , slow ) ;
2020-03-27 14:48:49 -07:00
nla_nest_cancel ( skb , start ) ;
return err ;
}
static size_t subflow_get_info_size ( const struct sock * sk )
{
size_t size = 0 ;
size + = nla_total_size ( 0 ) + /* INET_ULP_INFO_MPTCP */
nla_total_size ( 4 ) + /* MPTCP_SUBFLOW_ATTR_TOKEN_REM */
nla_total_size ( 4 ) + /* MPTCP_SUBFLOW_ATTR_TOKEN_LOC */
nla_total_size ( 4 ) + /* MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ */
nla_total_size_64bit ( 8 ) + /* MPTCP_SUBFLOW_ATTR_MAP_SEQ */
nla_total_size ( 4 ) + /* MPTCP_SUBFLOW_ATTR_MAP_SFSEQ */
nla_total_size ( 2 ) + /* MPTCP_SUBFLOW_ATTR_SSN_OFFSET */
nla_total_size ( 2 ) + /* MPTCP_SUBFLOW_ATTR_MAP_DATALEN */
nla_total_size ( 4 ) + /* MPTCP_SUBFLOW_ATTR_FLAGS */
nla_total_size ( 1 ) + /* MPTCP_SUBFLOW_ATTR_ID_REM */
nla_total_size ( 1 ) + /* MPTCP_SUBFLOW_ATTR_ID_LOC */
0 ;
return size ;
}
void mptcp_diag_subflow_init ( struct tcp_ulp_ops * ops )
{
ops - > get_info = subflow_get_info ;
ops - > get_info_size = subflow_get_info_size ;
}