mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	tcp: ulp: add functions to dump ulp-specific information
currently, only getsockopt(TCP_ULP) can be invoked to know if a ULP is on
top of a TCP socket. Extend idiag_get_aux() and idiag_get_aux_size(),
introduced by commit b37e88407c ("inet_diag: allow protocols to provide
additional data"), to report the ULP name and other information that can
be made available by the ULP through optional functions.
Users having CAP_NET_ADMIN privileges will then be able to retrieve this
information through inet_diag_handler, if they specify INET_DIAG_INFO in
the request.
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									15a7dea750
								
							
						
					
					
						commit
						61723b3932
					
				
					 3 changed files with 62 additions and 1 deletions
				
			
		| 
						 | 
					@ -2122,6 +2122,9 @@ struct tcp_ulp_ops {
 | 
				
			||||||
	void (*update)(struct sock *sk, struct proto *p);
 | 
						void (*update)(struct sock *sk, struct proto *p);
 | 
				
			||||||
	/* cleanup ulp */
 | 
						/* cleanup ulp */
 | 
				
			||||||
	void (*release)(struct sock *sk);
 | 
						void (*release)(struct sock *sk);
 | 
				
			||||||
 | 
						/* diagnostic */
 | 
				
			||||||
 | 
						int (*get_info)(const struct sock *sk, struct sk_buff *skb);
 | 
				
			||||||
 | 
						size_t (*get_info_size)(const struct sock *sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char		name[TCP_ULP_NAME_MAX];
 | 
						char		name[TCP_ULP_NAME_MAX];
 | 
				
			||||||
	struct module	*owner;
 | 
						struct module	*owner;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -153,11 +153,19 @@ enum {
 | 
				
			||||||
	INET_DIAG_BBRINFO,	/* request as INET_DIAG_VEGASINFO */
 | 
						INET_DIAG_BBRINFO,	/* request as INET_DIAG_VEGASINFO */
 | 
				
			||||||
	INET_DIAG_CLASS_ID,	/* request as INET_DIAG_TCLASS */
 | 
						INET_DIAG_CLASS_ID,	/* request as INET_DIAG_TCLASS */
 | 
				
			||||||
	INET_DIAG_MD5SIG,
 | 
						INET_DIAG_MD5SIG,
 | 
				
			||||||
 | 
						INET_DIAG_ULP_INFO,
 | 
				
			||||||
	__INET_DIAG_MAX,
 | 
						__INET_DIAG_MAX,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define INET_DIAG_MAX (__INET_DIAG_MAX - 1)
 | 
					#define INET_DIAG_MAX (__INET_DIAG_MAX - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						INET_ULP_INFO_UNSPEC,
 | 
				
			||||||
 | 
						INET_ULP_INFO_NAME,
 | 
				
			||||||
 | 
						__INET_ULP_INFO_MAX,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#define INET_ULP_INFO_MAX (__INET_ULP_INFO_MAX - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* INET_DIAG_MEM */
 | 
					/* INET_DIAG_MEM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct inet_diag_meminfo {
 | 
					struct inet_diag_meminfo {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,13 +81,42 @@ static int tcp_diag_put_md5sig(struct sk_buff *skb,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcp_diag_put_ulp(struct sk_buff *skb, struct sock *sk,
 | 
				
			||||||
 | 
								    const struct tcp_ulp_ops *ulp_ops)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nlattr *nest;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nest = nla_nest_start_noflag(skb, INET_DIAG_ULP_INFO);
 | 
				
			||||||
 | 
						if (!nest)
 | 
				
			||||||
 | 
							return -EMSGSIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = nla_put_string(skb, INET_ULP_INFO_NAME, ulp_ops->name);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto nla_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ulp_ops->get_info)
 | 
				
			||||||
 | 
							err = ulp_ops->get_info(sk, skb);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto nla_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nla_nest_end(skb, nest);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					nla_failure:
 | 
				
			||||||
 | 
						nla_nest_cancel(skb, nest);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tcp_diag_get_aux(struct sock *sk, bool net_admin,
 | 
					static int tcp_diag_get_aux(struct sock *sk, bool net_admin,
 | 
				
			||||||
			    struct sk_buff *skb)
 | 
								    struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct inet_connection_sock *icsk = inet_csk(sk);
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_TCP_MD5SIG
 | 
					#ifdef CONFIG_TCP_MD5SIG
 | 
				
			||||||
	if (net_admin) {
 | 
						if (net_admin) {
 | 
				
			||||||
		struct tcp_md5sig_info *md5sig;
 | 
							struct tcp_md5sig_info *md5sig;
 | 
				
			||||||
		int err = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rcu_read_lock();
 | 
							rcu_read_lock();
 | 
				
			||||||
		md5sig = rcu_dereference(tcp_sk(sk)->md5sig_info);
 | 
							md5sig = rcu_dereference(tcp_sk(sk)->md5sig_info);
 | 
				
			||||||
| 
						 | 
					@ -99,11 +128,21 @@ static int tcp_diag_get_aux(struct sock *sk, bool net_admin,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (net_admin) {
 | 
				
			||||||
 | 
							const struct tcp_ulp_ops *ulp_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ulp_ops = icsk->icsk_ulp_ops;
 | 
				
			||||||
 | 
							if (ulp_ops)
 | 
				
			||||||
 | 
								err = tcp_diag_put_ulp(skb, sk, ulp_ops);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t tcp_diag_get_aux_size(struct sock *sk, bool net_admin)
 | 
					static size_t tcp_diag_get_aux_size(struct sock *sk, bool net_admin)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct inet_connection_sock *icsk = inet_csk(sk);
 | 
				
			||||||
	size_t size = 0;
 | 
						size_t size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_TCP_MD5SIG
 | 
					#ifdef CONFIG_TCP_MD5SIG
 | 
				
			||||||
| 
						 | 
					@ -124,6 +163,17 @@ static size_t tcp_diag_get_aux_size(struct sock *sk, bool net_admin)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (net_admin) {
 | 
				
			||||||
 | 
							const struct tcp_ulp_ops *ulp_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ulp_ops = icsk->icsk_ulp_ops;
 | 
				
			||||||
 | 
							if (ulp_ops) {
 | 
				
			||||||
 | 
								size += nla_total_size(0) +
 | 
				
			||||||
 | 
									nla_total_size(TCP_ULP_NAME_MAX);
 | 
				
			||||||
 | 
								if (ulp_ops->get_info_size)
 | 
				
			||||||
 | 
									size += ulp_ops->get_info_size(sk);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return size;
 | 
						return size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue