summaryrefslogtreecommitdiffstats
path: root/net/rxrpc/output.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-04-04 14:00:37 +0100
committerDavid Howells <dhowells@redhat.com>2016-06-22 09:10:00 +0100
commitcc8feb8edd92d854be552fe4f5e0eeabca40b9ee (patch)
tree63c8bb0b2738f0c6b98cc51e58ef6a7611ddbc07 /net/rxrpc/output.c
parent85f32278bd98fa89dff528b0baea4ae6eea4cc5d (diff)
downloadlinux-cc8feb8edd92d854be552fe4f5e0eeabca40b9ee.tar.gz
linux-cc8feb8edd92d854be552fe4f5e0eeabca40b9ee.tar.bz2
linux-cc8feb8edd92d854be552fe4f5e0eeabca40b9ee.zip
rxrpc: Fix exclusive connection handling
"Exclusive connections" are meant to be used for a single client call and then scrapped. The idea is to limit the use of the negotiated security context. The current code, however, isn't doing this: it is instead restricting the socket to a single virtual connection and doing all the calls over that. This is changed such that the socket no longer maintains a special virtual connection over which it will do all the calls, but rather gets a new one each time a new exclusive call is made. Further, using a socket option for this is a poor choice. It should be done on sendmsg with a control message marker instead so that calls can be marked exclusive individually. To that end, add RXRPC_EXCLUSIVE_CALL which, if passed to sendmsg() as a control message element, will cause the call to be done on an single-use connection. The socket option (RXRPC_EXCLUSIVE_CONNECTION) still exists and, if set, will override any lack of RXRPC_EXCLUSIVE_CALL being specified so that programs using the setsockopt() will appear to work the same. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'net/rxrpc/output.c')
-rw-r--r--net/rxrpc/output.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c
index becbaa7c0a7c..6f8ab0ef839f 100644
--- a/net/rxrpc/output.c
+++ b/net/rxrpc/output.c
@@ -35,7 +35,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
static int rxrpc_sendmsg_cmsg(struct msghdr *msg,
unsigned long *user_call_ID,
enum rxrpc_command *command,
- u32 *abort_code)
+ u32 *abort_code,
+ bool *_exclusive)
{
struct cmsghdr *cmsg;
bool got_user_ID = false;
@@ -93,6 +94,11 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg,
return -EINVAL;
break;
+ case RXRPC_EXCLUSIVE_CALL:
+ *_exclusive = true;
+ if (len != 0)
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -131,7 +137,7 @@ static void rxrpc_send_abort(struct rxrpc_call *call, u32 abort_code)
*/
static struct rxrpc_call *
rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
- unsigned long user_call_ID)
+ unsigned long user_call_ID, bool exclusive)
{
struct rxrpc_conn_parameters cp;
struct rxrpc_conn_bundle *bundle;
@@ -155,7 +161,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
cp.local = rx->local;
cp.key = rx->key;
cp.security_level = rx->min_sec_level;
- cp.exclusive = test_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags);
+ cp.exclusive = rx->exclusive | exclusive;
cp.service_id = srx->srx_service;
trans = rxrpc_name_to_transport(&cp, msg->msg_name, msg->msg_namelen,
GFP_KERNEL);
@@ -201,12 +207,14 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
enum rxrpc_command cmd;
struct rxrpc_call *call;
unsigned long user_call_ID = 0;
+ bool exclusive = false;
u32 abort_code = 0;
int ret;
_enter("");
- ret = rxrpc_sendmsg_cmsg(msg, &user_call_ID, &cmd, &abort_code);
+ ret = rxrpc_sendmsg_cmsg(msg, &user_call_ID, &cmd, &abort_code,
+ &exclusive);
if (ret < 0)
return ret;
@@ -224,7 +232,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
if (!call) {
if (cmd != RXRPC_CMD_SEND_DATA)
return -EBADSLT;
- call = rxrpc_new_client_call_for_sendmsg(rx, msg, user_call_ID);
+ call = rxrpc_new_client_call_for_sendmsg(rx, msg, user_call_ID,
+ exclusive);
if (IS_ERR(call))
return PTR_ERR(call);
}