forked from mirrors/linux
		
	mptcp: setsockopt: handle SO_KEEPALIVE and SO_PRIORITY
start with something simple: both take an integer value, both need to be mirrored to all subflows. Acked-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									df00b087da
								
							
						
					
					
						commit
						1b3e7ede13
					
				
					 1 changed files with 106 additions and 0 deletions
				
			
		|  | @ -45,6 +45,90 @@ static u32 sockopt_seq_reset(const struct sock *sk) | ||||||
| 	return (u32)sk->sk_state << 24u; | 	return (u32)sk->sk_state << 24u; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void sockopt_seq_inc(struct mptcp_sock *msk) | ||||||
|  | { | ||||||
|  | 	u32 seq = (msk->setsockopt_seq + 1) & 0x00ffffff; | ||||||
|  | 
 | ||||||
|  | 	msk->setsockopt_seq = sockopt_seq_reset((struct sock *)msk) + seq; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int mptcp_get_int_option(struct mptcp_sock *msk, sockptr_t optval, | ||||||
|  | 				unsigned int optlen, int *val) | ||||||
|  | { | ||||||
|  | 	if (optlen < sizeof(int)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_sockptr(val, optval, sizeof(*val))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void mptcp_sol_socket_sync_intval(struct mptcp_sock *msk, int optname, int val) | ||||||
|  | { | ||||||
|  | 	struct mptcp_subflow_context *subflow; | ||||||
|  | 	struct sock *sk = (struct sock *)msk; | ||||||
|  | 
 | ||||||
|  | 	lock_sock(sk); | ||||||
|  | 	sockopt_seq_inc(msk); | ||||||
|  | 
 | ||||||
|  | 	mptcp_for_each_subflow(msk, subflow) { | ||||||
|  | 		struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | ||||||
|  | 		bool slow = lock_sock_fast(ssk); | ||||||
|  | 
 | ||||||
|  | 		switch (optname) { | ||||||
|  | 		case SO_KEEPALIVE: | ||||||
|  | 			if (ssk->sk_prot->keepalive) | ||||||
|  | 				ssk->sk_prot->keepalive(ssk, !!val); | ||||||
|  | 			sock_valbool_flag(ssk, SOCK_KEEPOPEN, !!val); | ||||||
|  | 			break; | ||||||
|  | 		case SO_PRIORITY: | ||||||
|  | 			ssk->sk_priority = val; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		subflow->setsockopt_seq = msk->setsockopt_seq; | ||||||
|  | 		unlock_sock_fast(ssk, slow); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	release_sock(sk); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int mptcp_sol_socket_intval(struct mptcp_sock *msk, int optname, int val) | ||||||
|  | { | ||||||
|  | 	sockptr_t optval = KERNEL_SOCKPTR(&val); | ||||||
|  | 	struct sock *sk = (struct sock *)msk; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname, | ||||||
|  | 			      optval, sizeof(val)); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	mptcp_sol_socket_sync_intval(msk, optname, val); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int mptcp_setsockopt_sol_socket_int(struct mptcp_sock *msk, int optname, | ||||||
|  | 					   sockptr_t optval, unsigned int optlen) | ||||||
|  | { | ||||||
|  | 	int val, ret; | ||||||
|  | 
 | ||||||
|  | 	ret = mptcp_get_int_option(msk, optval, optlen, &val); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	switch (optname) { | ||||||
|  | 	case SO_KEEPALIVE: | ||||||
|  | 		mptcp_sol_socket_sync_intval(msk, optname, val); | ||||||
|  | 		return 0; | ||||||
|  | 	case SO_PRIORITY: | ||||||
|  | 		return mptcp_sol_socket_intval(msk, optname, val); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return -ENOPROTOOPT; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, | static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, | ||||||
| 				       sockptr_t optval, unsigned int optlen) | 				       sockptr_t optval, unsigned int optlen) | ||||||
| { | { | ||||||
|  | @ -71,6 +155,9 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, | ||||||
| 		} | 		} | ||||||
| 		release_sock(sk); | 		release_sock(sk); | ||||||
| 		return ret; | 		return ret; | ||||||
|  | 	case SO_KEEPALIVE: | ||||||
|  | 	case SO_PRIORITY: | ||||||
|  | 		return mptcp_setsockopt_sol_socket_int(msk, optname, optval, optlen); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname, optval, optlen); | 	return sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname, optval, optlen); | ||||||
|  | @ -371,8 +458,27 @@ int mptcp_getsockopt(struct sock *sk, int level, int optname, | ||||||
| 	return -EOPNOTSUPP; | 	return -EOPNOTSUPP; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk) | ||||||
|  | { | ||||||
|  | 	struct sock *sk = (struct sock *)msk; | ||||||
|  | 
 | ||||||
|  | 	if (ssk->sk_prot->keepalive) { | ||||||
|  | 		if (sock_flag(sk, SOCK_KEEPOPEN)) | ||||||
|  | 			ssk->sk_prot->keepalive(ssk, 1); | ||||||
|  | 		else | ||||||
|  | 			ssk->sk_prot->keepalive(ssk, 0); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ssk->sk_priority = sk->sk_priority; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void __mptcp_sockopt_sync(struct mptcp_sock *msk, struct sock *ssk) | static void __mptcp_sockopt_sync(struct mptcp_sock *msk, struct sock *ssk) | ||||||
| { | { | ||||||
|  | 	bool slow = lock_sock_fast(ssk); | ||||||
|  | 
 | ||||||
|  | 	sync_socket_options(msk, ssk); | ||||||
|  | 
 | ||||||
|  | 	unlock_sock_fast(ssk, slow); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void mptcp_sockopt_sync(struct mptcp_sock *msk, struct sock *ssk) | void mptcp_sockopt_sync(struct mptcp_sock *msk, struct sock *ssk) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Florian Westphal
						Florian Westphal