@@ -36,6 +36,7 @@ struct sockaddr_rxrpc {
#define RXRPC_MIN_SECURITY_LEVEL 4 /* minimum security level */
#define RXRPC_UPGRADEABLE_SERVICE 5 /* Upgrade service[0] -> service[1] */
#define RXRPC_SUPPORTED_CMSG 6 /* Get highest supported control message type */
+#define RXRPC_BIND_CHANNEL 7 /* Bind a socket as an additional recvmsg channel */
/*
* RxRPC control messages
@@ -733,6 +733,71 @@ int rxrpc_sock_set_upgradeable_service(struct sock *sk, unsigned int val[2])
}
EXPORT_SYMBOL(rxrpc_sock_set_upgradeable_service);
+/*
+ * Bind this socket to another socket that's already set up and listening to
+ * use this as an additional channel for receiving new service calls.
+ */
+static int rxrpc_bind_channel(struct rxrpc_sock *rx2, int fd)
+{
+ struct rxrpc_service *b;
+ struct rxrpc_sock *rx1;
+ struct socket *sock1;
+ unsigned long *call_id_backlog;
+ int ret;
+
+ if (rx2->sk.sk_state != RXRPC_UNBOUND)
+ return -EISCONN;
+ if (rx2->service || rx2->exclusive)
+ return -EINVAL;
+
+ sock1 = sockfd_lookup(fd, &ret);
+ if (!sock1)
+ return ret;
+ rx1 = rxrpc_sk(sock1->sk);
+
+ ret = -EINVAL;
+ if (rx1 == rx2 || rx2->family != rx1->family ||
+ sock_net(&rx2->sk) != sock_net(&rx1->sk))
+ goto error;
+
+ ret = -EISCONN;
+ if (rx1->sk.sk_state != RXRPC_SERVER_LISTENING)
+ goto error;
+
+ ret = -ENOMEM;
+ call_id_backlog = kcalloc(RXRPC_BACKLOG_MAX,
+ sizeof(call_id_backlog[0]),
+ GFP_KERNEL);
+ if (!call_id_backlog)
+ goto error;
+
+ lock_sock_nested(&rx1->sk, 1);
+
+ ret = -EISCONN;
+ if (rx1->sk.sk_state != RXRPC_SERVER_LISTENING)
+ goto error_unlock;
+
+ b = rx1->service;
+ refcount_inc(&b->ref);
+ refcount_inc(&b->active);
+ rx2->service = b;
+ rx2->srx = rx1->srx;
+ rx2->call_id_backlog = call_id_backlog;
+ rx2->min_sec_level = rx1->min_sec_level;
+ rx2->local = rxrpc_get_local(rx1->local);
+ atomic_inc(&rx1->local->active_users);
+ rx2->sk.sk_state = RXRPC_SERVER_LISTENING;
+ call_id_backlog = NULL;
+ ret = 0;
+
+error_unlock:
+ release_sock(&rx1->sk);
+ kfree(call_id_backlog);
+error:
+ fput(sock1->file);
+ return ret;
+}
+
/*
* set RxRPC socket options
*/
@@ -742,7 +807,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
unsigned int min_sec_level;
u16 service_upgrade[2];
- int ret;
+ int ret, fd;
_enter(",%d,%d,,%d", level, optname, optlen);
@@ -817,6 +882,18 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
goto error;
goto success;
+ case RXRPC_BIND_CHANNEL:
+ ret = -EINVAL;
+ if (optlen != sizeof(fd))
+ goto error;
+ ret = -EFAULT;
+ if (copy_from_sockptr(&fd, optval, sizeof(fd)) != 0)
+ goto error;
+ ret = rxrpc_bind_channel(rx, fd);
+ if (ret < 0)
+ goto error;
+ goto success;
+
default:
break;
}
@@ -296,8 +296,6 @@ void rxrpc_deactivate_service(struct rxrpc_sock *rx)
if (!refcount_dec_and_test(&rx->service->active))
return;
- kdebug("-- deactivate --");
-
/* Now that active is 0, make sure that there aren't any incoming calls
* being set up before we clear the preallocation buffers.
*/
@@ -335,12 +333,9 @@ void rxrpc_deactivate_service(struct rxrpc_sock *rx)
head = b->call_backlog_head;
tail = b->call_backlog_tail;
- kdebug("backlog %x %x", head, tail);
while (CIRC_CNT(head, tail, size) > 0) {
struct rxrpc_call *call = b->call_backlog[tail];
- kdebug("discard c=%08x", call->debug_id);
-
trace_rxrpc_call(call->debug_id, rxrpc_call_discard,
refcount_read(&call->ref),
NULL, (const void *)call->user_call_ID);
@@ -712,7 +712,7 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
if (WARN_ON(!test_bit(RXRPC_CALL_RELEASED, &call->flags))) {
- kdebug("### UNRELEASED c=%08x", call->debug_id);
+ pr_warn("### UNRELEASED c=%08x", call->debug_id);
return;
}