forked from mirrors/linux
		
	mptcp: Add setsockopt()/getsockopt() socket operations
set/getsockopt behaviour with multiple subflows is undefined. Therefore, for now, we return -EOPNOTSUPP unless we're in fallback mode. Co-developed-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com> Signed-off-by: Christoph Paasch <cpaasch@apple.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									214984901a
								
							
						
					
					
						commit
						717e79c867
					
				
					 1 changed files with 58 additions and 0 deletions
				
			
		|  | @ -330,6 +330,62 @@ static void mptcp_destroy(struct sock *sk) | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int mptcp_setsockopt(struct sock *sk, int level, int optname, | ||||||
|  | 			    char __user *uoptval, unsigned int optlen) | ||||||
|  | { | ||||||
|  | 	struct mptcp_sock *msk = mptcp_sk(sk); | ||||||
|  | 	char __kernel *optval; | ||||||
|  | 	int ret = -EOPNOTSUPP; | ||||||
|  | 	struct socket *ssock; | ||||||
|  | 
 | ||||||
|  | 	/* will be treated as __user in tcp_setsockopt */ | ||||||
|  | 	optval = (char __kernel __force *)uoptval; | ||||||
|  | 
 | ||||||
|  | 	pr_debug("msk=%p", msk); | ||||||
|  | 
 | ||||||
|  | 	/* @@ the meaning of setsockopt() when the socket is connected and
 | ||||||
|  | 	 * there are multiple subflows is not defined. | ||||||
|  | 	 */ | ||||||
|  | 	lock_sock(sk); | ||||||
|  | 	ssock = __mptcp_socket_create(msk, MPTCP_SAME_STATE); | ||||||
|  | 	if (!IS_ERR(ssock)) { | ||||||
|  | 		pr_debug("subflow=%p", ssock->sk); | ||||||
|  | 		ret = kernel_setsockopt(ssock, level, optname, optval, optlen); | ||||||
|  | 	} | ||||||
|  | 	release_sock(sk); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int mptcp_getsockopt(struct sock *sk, int level, int optname, | ||||||
|  | 			    char __user *uoptval, int __user *uoption) | ||||||
|  | { | ||||||
|  | 	struct mptcp_sock *msk = mptcp_sk(sk); | ||||||
|  | 	char __kernel *optval; | ||||||
|  | 	int ret = -EOPNOTSUPP; | ||||||
|  | 	int __kernel *option; | ||||||
|  | 	struct socket *ssock; | ||||||
|  | 
 | ||||||
|  | 	/* will be treated as __user in tcp_getsockopt */ | ||||||
|  | 	optval = (char __kernel __force *)uoptval; | ||||||
|  | 	option = (int __kernel __force *)uoption; | ||||||
|  | 
 | ||||||
|  | 	pr_debug("msk=%p", msk); | ||||||
|  | 
 | ||||||
|  | 	/* @@ the meaning of getsockopt() when the socket is connected and
 | ||||||
|  | 	 * there are multiple subflows is not defined. | ||||||
|  | 	 */ | ||||||
|  | 	lock_sock(sk); | ||||||
|  | 	ssock = __mptcp_socket_create(msk, MPTCP_SAME_STATE); | ||||||
|  | 	if (!IS_ERR(ssock)) { | ||||||
|  | 		pr_debug("subflow=%p", ssock->sk); | ||||||
|  | 		ret = kernel_getsockopt(ssock, level, optname, optval, option); | ||||||
|  | 	} | ||||||
|  | 	release_sock(sk); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int mptcp_get_port(struct sock *sk, unsigned short snum) | static int mptcp_get_port(struct sock *sk, unsigned short snum) | ||||||
| { | { | ||||||
| 	struct mptcp_sock *msk = mptcp_sk(sk); | 	struct mptcp_sock *msk = mptcp_sk(sk); | ||||||
|  | @ -380,6 +436,8 @@ static struct proto mptcp_prot = { | ||||||
| 	.init		= mptcp_init_sock, | 	.init		= mptcp_init_sock, | ||||||
| 	.close		= mptcp_close, | 	.close		= mptcp_close, | ||||||
| 	.accept		= mptcp_accept, | 	.accept		= mptcp_accept, | ||||||
|  | 	.setsockopt	= mptcp_setsockopt, | ||||||
|  | 	.getsockopt	= mptcp_getsockopt, | ||||||
| 	.shutdown	= tcp_shutdown, | 	.shutdown	= tcp_shutdown, | ||||||
| 	.destroy	= mptcp_destroy, | 	.destroy	= mptcp_destroy, | ||||||
| 	.sendmsg	= mptcp_sendmsg, | 	.sendmsg	= mptcp_sendmsg, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Peter Krystad
						Peter Krystad