srx->transport_len > len)
return -EINVAL;
- if (srx->transport.family != rx->proto)
+ if (srx->transport.family != rx->family)
return -EAFNOSUPPORT;
switch (srx->transport.family) {
/*
* find a transport by address
*/
-struct rxrpc_transport *rxrpc_name_to_transport(struct rxrpc_sock *rx,
- struct sockaddr *addr,
- int addr_len, int flags,
- gfp_t gfp)
+struct rxrpc_transport *
+rxrpc_name_to_transport(struct rxrpc_conn_parameters *cp,
+ struct sockaddr *addr,
+ int addr_len,
+ gfp_t gfp)
{
struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr;
struct rxrpc_transport *trans;
- struct rxrpc_peer *peer;
- _enter("%p,%p,%d,%d", rx, addr, addr_len, flags);
-
- ASSERT(rx->local != NULL);
+ _enter("%p,%d", addr, addr_len);
- if (rx->srx.transport_type != srx->transport_type)
+ if (cp->local->srx.transport_type != srx->transport_type)
return ERR_PTR(-ESOCKTNOSUPPORT);
- if (rx->srx.transport.family != srx->transport.family)
+ if (cp->local->srx.transport.family != srx->transport.family)
return ERR_PTR(-EAFNOSUPPORT);
/* find a remote transport endpoint from the local one */
- peer = rxrpc_lookup_peer(rx->local, srx, gfp);
- if (!peer)
+ cp->peer = rxrpc_lookup_peer(cp->local, srx, gfp);
+ if (!cp->peer)
return ERR_PTR(-ENOMEM);
/* find a transport */
- trans = rxrpc_get_transport(rx->local, peer, gfp);
- rxrpc_put_peer(peer);
+ trans = rxrpc_get_transport(cp->local, cp->peer, gfp);
+ rxrpc_put_peer(cp->peer);
_leave(" = %p", trans);
return trans;
}
unsigned long user_call_ID,
gfp_t gfp)
{
+ struct rxrpc_conn_parameters cp;
struct rxrpc_conn_bundle *bundle;
struct rxrpc_transport *trans;
struct rxrpc_call *call;
lock_sock(&rx->sk);
- trans = rxrpc_name_to_transport(rx, (struct sockaddr *)srx,
- sizeof(*srx), 0, gfp);
+ if (!key)
+ key = rx->key;
+ if (key && !key->payload.data[0])
+ key = NULL; /* a no-security key */
+
+ memset(&cp, 0, sizeof(cp));
+ cp.local = rx->local;
+ cp.key = key;
+ cp.security_level = 0;
+ cp.exclusive = false;
+ cp.service_id = srx->srx_service;
+
+ trans = rxrpc_name_to_transport(&cp, (struct sockaddr *)srx,
+ sizeof(*srx), gfp);
if (IS_ERR(trans)) {
call = ERR_CAST(trans);
trans = NULL;
goto out_notrans;
}
-
- if (!key)
- key = rx->key;
- if (key && !key->payload.data[0])
- key = NULL; /* a no-security key */
+ cp.peer = trans->peer;
bundle = rxrpc_get_bundle(rx, trans, key, srx->srx_service, gfp);
if (IS_ERR(bundle)) {
goto out;
}
- call = rxrpc_new_client_call(rx, trans, bundle, user_call_ID, gfp);
+ call = rxrpc_new_client_call(rx, &cp, trans, bundle, user_call_ID, gfp);
rxrpc_put_bundle(trans, bundle);
out:
rxrpc_put_transport(trans);
sk->sk_destruct = rxrpc_sock_destructor;
rx = rxrpc_sk(sk);
- rx->proto = protocol;
+ rx->family = protocol;
rx->calls = RB_ROOT;
INIT_LIST_HEAD(&rx->listen_link);
#define RXRPC_SECURITY_MAX RXRPC_SECURITY_ENCRYPT
struct sockaddr_rxrpc srx; /* local address */
struct sockaddr_rxrpc connect_srx; /* Default client address from connect() */
- sa_family_t proto; /* protocol created with */
+ sa_family_t family; /* protocol family created with */
};
#define rxrpc_sk(__sk) container_of((__sk), struct rxrpc_sock, sk)
u8 security_ix; /* security type */
};
+/*
+ * Keys for matching a connection.
+ */
+struct rxrpc_conn_proto {
+ unsigned long hash_key;
+ struct rxrpc_local *local; /* Representation of local endpoint */
+ u32 epoch; /* epoch of this connection */
+ u32 cid; /* connection ID */
+ u8 in_clientflag; /* RXRPC_CLIENT_INITIATED if we are server */
+ u8 addr_size; /* Size of the address */
+ sa_family_t family; /* Transport protocol */
+ __be16 port; /* Peer UDP/UDP6 port */
+ union { /* Peer address */
+ struct in_addr ipv4_addr;
+ struct in6_addr ipv6_addr;
+ u32 raw_addr[0];
+ };
+};
+
+struct rxrpc_conn_parameters {
+ struct rxrpc_local *local; /* Representation of local endpoint */
+ struct rxrpc_peer *peer; /* Remote endpoint */
+ struct key *key; /* Security details */
+ bool exclusive; /* T if conn is exclusive */
+ u16 service_id; /* Service ID for this connection */
+ u32 security_level; /* Security level selected */
+};
+
/*
* RxRPC connection definition
* - matched by { transport, service_id, conn_id, direction, key }
struct rxrpc_connection {
struct rxrpc_transport *trans; /* transport session */
struct rxrpc_conn_bundle *bundle; /* connection bundle (client) */
+ struct rxrpc_conn_proto proto;
+ struct rxrpc_conn_parameters params;
+
struct work_struct processor; /* connection event processor */
struct rb_node node; /* node in transport's lookup tree */
struct list_head link; /* link in master connection list */
struct sk_buff_head rx_queue; /* received conn-level packets */
struct rxrpc_call *channels[RXRPC_MAXCALLS]; /* channels (active calls) */
const struct rxrpc_security *security; /* applied security module */
- struct key *key; /* security for this connection (client) */
struct key *server_key; /* security for this service */
struct crypto_skcipher *cipher; /* encryption handle */
struct rxrpc_crypt csum_iv; /* packet checksum base */
u8 size_align; /* data size alignment (for security) */
u8 header_size; /* rxrpc + security header size */
u8 security_size; /* security header size */
- u32 security_level; /* security level negotiated */
u32 security_nonce; /* response re-use preventer */
- u32 epoch; /* epoch of this connection */
- u32 cid; /* connection ID */
- u16 service_id; /* service ID for this connection */
u8 security_ix; /* security type */
- u8 in_clientflag; /* RXRPC_CLIENT_INITIATED if we are server */
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
};
unsigned long hash_key; /* Full hash key */
u8 in_clientflag; /* Copy of conn->in_clientflag for hashing */
struct rxrpc_local *local; /* Local endpoint. Used for hashing. */
- sa_family_t proto; /* Frame protocol */
+ sa_family_t family; /* Frame protocol */
u32 call_id; /* call ID on connection */
u32 cid; /* connection ID plus channel index */
u32 epoch; /* epoch of this connection */
extern atomic_t rxrpc_debug_id;
extern struct workqueue_struct *rxrpc_workqueue;
-extern struct rxrpc_transport *rxrpc_name_to_transport(struct rxrpc_sock *,
+extern struct rxrpc_transport *rxrpc_name_to_transport(struct rxrpc_conn_parameters *,
struct sockaddr *,
- int, int, gfp_t);
+ int, gfp_t);
/*
* call_accept.c
void *, sa_family_t, const void *);
struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *, unsigned long);
struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *,
+ struct rxrpc_conn_parameters *,
struct rxrpc_transport *,
struct rxrpc_conn_bundle *,
unsigned long, gfp_t);
struct rxrpc_transport *,
struct key *, u16, gfp_t);
void rxrpc_put_bundle(struct rxrpc_transport *, struct rxrpc_conn_bundle *);
-int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_transport *,
- struct rxrpc_conn_bundle *, struct rxrpc_call *, gfp_t);
+int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_conn_parameters *,
+ struct rxrpc_transport *, struct rxrpc_conn_bundle *,
+ struct rxrpc_call *, gfp_t);
void rxrpc_put_connection(struct rxrpc_connection *);
void __exit rxrpc_destroy_all_connections(void);
struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *,
extern struct rxrpc_connection *
rxrpc_incoming_connection(struct rxrpc_transport *, struct rxrpc_host_header *);
+static inline bool rxrpc_conn_is_client(const struct rxrpc_connection *conn)
+{
+ return conn->out_clientflag;
+}
+
+static inline bool rxrpc_conn_is_service(const struct rxrpc_connection *conn)
+{
+ return conn->proto.in_clientflag;
+}
+
/*
* input.c
*/
msg.msg_controllen = 0;
msg.msg_flags = 0;
- whdr.epoch = htonl(call->conn->epoch);
+ whdr.epoch = htonl(call->conn->proto.epoch);
whdr.cid = htonl(call->cid);
whdr.callNumber = htonl(call->call_id);
whdr.seq = 0;
if (call->state >= RXRPC_CALL_COMPLETE &&
!list_empty(&call->accept_link)) {
_debug("X unlinking once-pending call %p { e=%lx f=%lx c=%x }",
- call, call->events, call->flags, call->conn->cid);
+ call, call->events, call->flags, call->conn->proto.cid);
read_lock_bh(&call->state_lock);
if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
* this means there's a race between clearing the flag and setting the
* work pending bit and the work item being processed again */
if (call->events && !work_pending(&call->processor)) {
- _debug("jumpstart %x", call->conn->cid);
+ _debug("jumpstart %x", call->conn->proto.cid);
rxrpc_queue_call(call);
}
u32 call_id,
u32 epoch,
u16 service_id,
- sa_family_t proto,
+ sa_family_t family,
void *localptr,
unsigned int addr_size,
const u8 *peer_addr)
key += (cid & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT;
key += cid & RXRPC_CHANNELMASK;
key += in_clientflag;
- key += proto;
+ key += family;
/* Step through the peer address in 16-bit portions for speed */
for (i = 0, p = (const u16 *)peer_addr; i < addr_size >> 1; i++, p++)
key += *p;
unsigned int addr_size = 0;
_enter("");
- switch (call->proto) {
+ switch (call->family) {
case AF_INET:
addr_size = sizeof(call->peer_ip.ipv4_addr);
break;
}
key = rxrpc_call_hashfunc(call->in_clientflag, call->cid,
call->call_id, call->epoch,
- call->service_id, call->proto,
+ call->service_id, call->family,
call->conn->trans->local, addr_size,
call->peer_ip.ipv6_addr);
/* Store the full key in the call */
struct rxrpc_call *rxrpc_find_call_hash(
struct rxrpc_host_header *hdr,
void *localptr,
- sa_family_t proto,
+ sa_family_t family,
const void *peer_addr)
{
unsigned long key;
u8 in_clientflag = hdr->flags & RXRPC_CLIENT_INITIATED;
_enter("");
- switch (proto) {
+ switch (family) {
case AF_INET:
addr_size = sizeof(call->peer_ip.ipv4_addr);
break;
key = rxrpc_call_hashfunc(in_clientflag, hdr->cid, hdr->callNumber,
hdr->epoch, hdr->serviceId,
- proto, localptr, addr_size,
+ family, localptr, addr_size,
peer_addr);
hash_for_each_possible_rcu(rxrpc_call_hash, call, hash_node, key) {
if (call->hash_key == key &&
call->cid == hdr->cid &&
call->in_clientflag == in_clientflag &&
call->service_id == hdr->serviceId &&
- call->proto == proto &&
+ call->family == family &&
call->local == localptr &&
memcmp(call->peer_ip.ipv6_addr, peer_addr,
addr_size) == 0 &&
*/
static struct rxrpc_call *rxrpc_alloc_client_call(
struct rxrpc_sock *rx,
+ struct rxrpc_conn_parameters *cp,
struct rxrpc_transport *trans,
struct rxrpc_conn_bundle *bundle,
gfp_t gfp)
call->socket = rx;
call->rx_data_post = 1;
- ret = rxrpc_connect_call(rx, trans, bundle, call, gfp);
+ ret = rxrpc_connect_call(rx, cp, trans, bundle, call, gfp);
if (ret < 0) {
kmem_cache_free(rxrpc_call_jar, call);
return ERR_PTR(ret);
}
/* Record copies of information for hashtable lookup */
- call->proto = rx->proto;
- call->local = trans->local;
- switch (call->proto) {
+ call->family = rx->family;
+ call->local = call->conn->params.local;
+ switch (call->family) {
case AF_INET:
call->peer_ip.ipv4_addr =
trans->peer->srx.transport.sin.sin_addr.s_addr;
sizeof(call->peer_ip.ipv6_addr));
break;
}
- call->epoch = call->conn->epoch;
- call->service_id = call->conn->service_id;
- call->in_clientflag = call->conn->in_clientflag;
+ call->epoch = call->conn->proto.epoch;
+ call->service_id = call->conn->params.service_id;
+ call->in_clientflag = call->conn->proto.in_clientflag;
/* Add the new call to the hashtable */
rxrpc_call_hash_add(call);
* - called in process context with IRQs enabled
*/
struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
+ struct rxrpc_conn_parameters *cp,
struct rxrpc_transport *trans,
struct rxrpc_conn_bundle *bundle,
unsigned long user_call_ID,
rx, trans->debug_id, bundle ? bundle->debug_id : -1,
user_call_ID);
- call = rxrpc_alloc_client_call(rx, trans, bundle, gfp);
+ call = rxrpc_alloc_client_call(rx, cp, trans, bundle, gfp);
if (IS_ERR(call)) {
_leave(" = %ld", PTR_ERR(call));
return call;
write_unlock_bh(&rxrpc_call_lock);
/* Record copies of information for hashtable lookup */
- call->proto = rx->proto;
+ call->family = rx->family;
call->local = conn->trans->local;
- switch (call->proto) {
+ switch (call->family) {
case AF_INET:
call->peer_ip.ipv4_addr =
conn->trans->peer->srx.transport.sin.sin_addr.s_addr;
default:
break;
}
- call->epoch = conn->epoch;
- call->service_id = conn->service_id;
- call->in_clientflag = conn->in_clientflag;
+ call->epoch = conn->proto.epoch;
+ call->service_id = conn->params.service_id;
+ call->in_clientflag = conn->proto.in_clientflag;
/* Add the new call to the hashtable */
rxrpc_call_hash_add(call);
msg.msg_controllen = 0;
msg.msg_flags = 0;
- whdr.epoch = htonl(conn->epoch);
- whdr.cid = htonl(conn->cid);
+ whdr.epoch = htonl(conn->proto.epoch);
+ whdr.cid = htonl(conn->proto.cid);
whdr.callNumber = 0;
whdr.seq = 0;
whdr.type = RXRPC_PACKET_TYPE_ABORT;
whdr.userStatus = 0;
whdr.securityIndex = conn->security_ix;
whdr._rsvd = 0;
- whdr.serviceId = htons(conn->service_id);
+ whdr.serviceId = htons(conn->params.service_id);
word = htonl(conn->local_abort);
ASSERT(conn->security_ix != 0);
- if (!conn->key) {
+ if (!conn->params.key) {
_debug("set up security");
ret = rxrpc_init_server_conn_security(conn);
switch (ret) {
_enter("");
- epoch = conn->epoch;
+ epoch = conn->proto.epoch;
write_lock_bh(&conn->trans->conn_lock);
parent = *p;
xconn = rb_entry(parent, struct rxrpc_connection, node);
- if (epoch < xconn->epoch)
+ if (epoch < xconn->proto.epoch)
p = &(*p)->rb_left;
- else if (epoch > xconn->epoch)
+ else if (epoch > xconn->proto.epoch)
p = &(*p)->rb_right;
- else if (cid < xconn->cid)
+ else if (cid < xconn->proto.cid)
p = &(*p)->rb_left;
- else if (cid > xconn->cid)
+ else if (cid > xconn->proto.cid)
p = &(*p)->rb_right;
else
goto id_exists;
rb_link_node(&conn->node, parent, p);
rb_insert_color(&conn->node, &conn->trans->client_conns);
- conn->cid = cid;
+ conn->proto.cid = cid;
write_unlock_bh(&conn->trans->conn_lock);
_leave(" [CID %x]", cid);
return;
goto attempt_insertion;
xconn = rb_entry(parent, struct rxrpc_connection, node);
- if (epoch < xconn->epoch ||
- cid < xconn->cid)
+ if (epoch < xconn->proto.epoch ||
+ cid < xconn->proto.cid)
goto attempt_insertion;
}
}
* connect a call on an exclusive connection
*/
static int rxrpc_connect_exclusive(struct rxrpc_sock *rx,
+ struct rxrpc_conn_parameters *cp,
struct rxrpc_transport *trans,
- u16 service_id,
struct rxrpc_call *call,
gfp_t gfp)
{
conn->trans = trans;
conn->bundle = NULL;
- conn->service_id = service_id;
- conn->epoch = rxrpc_epoch;
- conn->in_clientflag = 0;
+ conn->params = *cp;
+ conn->proto.local = cp->local;
+ conn->proto.epoch = rxrpc_epoch;
+ conn->proto.cid = 0;
+ conn->proto.in_clientflag = 0;
+ conn->proto.family = cp->peer->srx.transport.family;
conn->out_clientflag = RXRPC_CLIENT_INITIATED;
- conn->cid = 0;
conn->state = RXRPC_CONN_CLIENT;
conn->avail_calls = RXRPC_MAXCALLS - 1;
- conn->security_level = rx->min_sec_level;
- conn->key = key_get(rx->key);
+
+ key_get(conn->params.key);
ret = rxrpc_init_client_conn_security(conn);
if (ret < 0) {
- key_put(conn->key);
+ key_put(conn->params.key);
kfree(conn);
_leave(" = %d [key]", ret);
return ret;
conn->channels[chan] = call;
call->conn = conn;
call->channel = chan;
- call->cid = conn->cid | chan;
+ call->cid = conn->proto.cid | chan;
call->call_id = ++conn->call_counter;
_net("CONNECT client on conn %d chan %d as call %x",
* - called in process context with IRQs enabled
*/
int rxrpc_connect_call(struct rxrpc_sock *rx,
+ struct rxrpc_conn_parameters *cp,
struct rxrpc_transport *trans,
struct rxrpc_conn_bundle *bundle,
struct rxrpc_call *call,
_enter("%p,%lx,", rx, call->user_call_ID);
if (test_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags))
- return rxrpc_connect_exclusive(rx, trans, bundle->service_id,
- call, gfp);
+ return rxrpc_connect_exclusive(rx, cp, trans, call, gfp);
spin_lock(&trans->client_lock);
for (;;) {
candidate->trans = trans;
candidate->bundle = bundle;
- candidate->service_id = bundle->service_id;
- candidate->epoch = rxrpc_epoch;
- candidate->in_clientflag = 0;
+ candidate->params = *cp;
+ candidate->proto.local = cp->local;
+ candidate->proto.epoch = rxrpc_epoch;
+ candidate->proto.cid = 0;
+ candidate->proto.in_clientflag = 0;
+ candidate->proto.family = cp->peer->srx.transport.family;
candidate->out_clientflag = RXRPC_CLIENT_INITIATED;
- candidate->cid = 0;
candidate->state = RXRPC_CONN_CLIENT;
candidate->avail_calls = RXRPC_MAXCALLS;
- candidate->security_level = rx->min_sec_level;
- candidate->key = key_get(bundle->key);
+
+ key_get(candidate->params.key);
ret = rxrpc_init_client_conn_security(candidate);
if (ret < 0) {
- key_put(candidate->key);
+ key_put(candidate->params.key);
kfree(candidate);
_leave(" = %d [key]", ret);
return ret;
conn->channels[chan] = call;
call->conn = conn;
call->channel = chan;
- call->cid = conn->cid | chan;
+ call->cid = conn->proto.cid | chan;
call->call_id = ++conn->call_counter;
_net("CONNECT client on conn %d chan %d as call %x",
while (p) {
conn = rb_entry(p, struct rxrpc_connection, node);
- _debug("maybe %x", conn->cid);
+ _debug("maybe %x", conn->proto.cid);
- if (epoch < conn->epoch)
+ if (epoch < conn->proto.epoch)
p = p->rb_left;
- else if (epoch > conn->epoch)
+ else if (epoch > conn->proto.epoch)
p = p->rb_right;
- else if (cid < conn->cid)
+ else if (cid < conn->proto.cid)
p = p->rb_left;
- else if (cid > conn->cid)
+ else if (cid > conn->proto.cid)
p = p->rb_right;
else
goto found_extant_connection;
}
candidate->trans = trans;
- candidate->epoch = hdr->epoch;
- candidate->cid = hdr->cid & RXRPC_CIDMASK;
- candidate->service_id = hdr->serviceId;
+ candidate->proto.local = trans->local;
+ candidate->proto.epoch = hdr->epoch;
+ candidate->proto.cid = hdr->cid & RXRPC_CIDMASK;
+ candidate->proto.in_clientflag = RXRPC_CLIENT_INITIATED;
+ candidate->params.local = trans->local;
+ candidate->params.peer = trans->peer;
+ candidate->params.service_id = hdr->serviceId;
candidate->security_ix = hdr->securityIndex;
- candidate->in_clientflag = RXRPC_CLIENT_INITIATED;
candidate->out_clientflag = 0;
candidate->state = RXRPC_CONN_SERVER;
- if (candidate->service_id)
+ if (candidate->params.service_id)
candidate->state = RXRPC_CONN_SERVER_UNSECURED;
write_lock_bh(&trans->conn_lock);
p = *pp;
conn = rb_entry(p, struct rxrpc_connection, node);
- if (epoch < conn->epoch)
+ if (epoch < conn->proto.epoch)
pp = &(*pp)->rb_left;
- else if (epoch > conn->epoch)
+ else if (epoch > conn->proto.epoch)
pp = &(*pp)->rb_right;
- else if (cid < conn->cid)
+ else if (cid < conn->proto.cid)
pp = &(*pp)->rb_left;
- else if (cid > conn->cid)
+ else if (cid > conn->proto.cid)
pp = &(*pp)->rb_right;
else
goto found_extant_second;
new = "new";
success:
- _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->cid);
+ _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->proto.cid);
_leave(" = %p {u=%d}", conn, atomic_read(&conn->usage));
return conn;
while (p) {
conn = rb_entry(p, struct rxrpc_connection, node);
- _debug("maybe %x", conn->cid);
+ _debug("maybe %x", conn->proto.cid);
- if (epoch < conn->epoch)
+ if (epoch < conn->proto.epoch)
p = p->rb_left;
- else if (epoch > conn->epoch)
+ else if (epoch > conn->proto.epoch)
p = p->rb_right;
- else if (cid < conn->cid)
+ else if (cid < conn->proto.cid)
p = p->rb_left;
- else if (cid > conn->cid)
+ else if (cid > conn->proto.cid)
p = p->rb_right;
else
goto found;
rxrpc_purge_queue(&conn->rx_queue);
conn->security->clear(conn);
- key_put(conn->key);
+ key_put(conn->params.key);
key_put(conn->server_key);
rxrpc_put_transport(conn->trans);
case RXRPC_PACKET_TYPE_BUSY:
_proto("Rx BUSY %%%u", sp->hdr.serial);
- if (call->conn->out_clientflag)
+ if (rxrpc_conn_is_service(call->conn))
goto protocol_error;
write_lock_bh(&call->state_lock);
case RXRPC_CALL_COMPLETE:
case RXRPC_CALL_CLIENT_FINAL_ACK:
/* complete server call */
- if (call->conn->in_clientflag)
+ if (rxrpc_conn_is_service(call->conn))
goto dead_call;
/* resend last packet of a completed call */
_debug("final ack again");
if (ret < 0)
goto error;
- conn->key = key;
+ conn->params.key = key;
_leave(" = 0 [%d]", key_serial(key));
return 0;
rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
unsigned long user_call_ID)
{
+ struct rxrpc_conn_parameters cp;
struct rxrpc_conn_bundle *bundle;
struct rxrpc_transport *trans;
struct rxrpc_call *call;
if (!msg->msg_name)
return ERR_PTR(-EDESTADDRREQ);
- trans = rxrpc_name_to_transport(rx, msg->msg_name, msg->msg_namelen, 0,
+ key = rx->key;
+ if (key && !rx->key->payload.data[0])
+ key = NULL;
+
+ memset(&cp, 0, sizeof(cp));
+ 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.service_id = srx->srx_service;
+ trans = rxrpc_name_to_transport(&cp, msg->msg_name, msg->msg_namelen,
GFP_KERNEL);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
+ cp.peer = trans->peer;
- key = rx->key;
- if (key && !rx->key->payload.data[0])
- key = NULL;
- bundle = rxrpc_get_bundle(rx, trans, key, srx->srx_service, GFP_KERNEL);
+ bundle = rxrpc_get_bundle(rx, trans, cp.key, srx->srx_service,
+ GFP_KERNEL);
if (IS_ERR(bundle)) {
ret = PTR_ERR(bundle);
goto out_trans;
}
- call = rxrpc_new_client_call(rx, trans, bundle, user_call_ID,
+ call = rxrpc_new_client_call(rx, &cp, trans, bundle, user_call_ID,
GFP_KERNEL);
rxrpc_put_bundle(trans, bundle);
rxrpc_put_transport(trans);
seq = atomic_inc_return(&call->sequence);
- sp->hdr.epoch = conn->epoch;
+ sp->hdr.epoch = conn->proto.epoch;
sp->hdr.cid = call->cid;
sp->hdr.callNumber = call->call_id;
sp->hdr.seq = seq;
" %-8.8s %08x %lx\n",
lbuff,
rbuff,
- call->conn->service_id,
+ call->conn->params.service_id,
call->cid,
call->call_id,
- call->conn->in_clientflag ? "Svc" : "Clt",
+ rxrpc_conn_is_service(call->conn) ? "Svc" : "Clt",
atomic_read(&call->usage),
rxrpc_call_states[call->state],
call->remote_abort ?: call->local_abort,
" %s %08x %08x %08x\n",
lbuff,
rbuff,
- conn->service_id,
- conn->cid,
+ conn->params.service_id,
+ conn->proto.cid,
conn->call_counter,
- conn->in_clientflag ? "Svc" : "Clt",
+ rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
atomic_read(&conn->usage),
rxrpc_conn_states[conn->state],
- key_serial(conn->key),
+ key_serial(conn->params.key),
atomic_read(&conn->serial),
atomic_read(&conn->hi_serial));
/* we transferred the whole data packet */
if (sp->hdr.flags & RXRPC_LAST_PACKET) {
_debug("last");
- if (call->conn->out_clientflag) {
+ if (rxrpc_conn_is_client(call->conn)) {
/* last byte of reply received */
ret = copied;
goto terminal_message;
struct rxrpc_key_token *token;
int ret;
- _enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
+ _enter("{%d},{%x}", conn->debug_id, key_serial(conn->params.key));
- token = conn->key->payload.data[0];
+ token = conn->params.key->payload.data[0];
conn->security_ix = token->security_index;
ci = crypto_alloc_skcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
sizeof(token->kad->session_key)) < 0)
BUG();
- switch (conn->security_level) {
+ switch (conn->params.security_level) {
case RXRPC_SECURITY_PLAIN:
break;
case RXRPC_SECURITY_AUTH:
_enter("");
- if (!conn->key)
+ if (!conn->params.key)
return;
- token = conn->key->payload.data[0];
+ token = conn->params.key->payload.data[0];
memcpy(&iv, token->kad->session_key, sizeof(iv));
- tmpbuf.x[0] = htonl(conn->epoch);
- tmpbuf.x[1] = htonl(conn->cid);
+ tmpbuf.x[0] = htonl(conn->proto.epoch);
+ tmpbuf.x[1] = htonl(conn->proto.cid);
tmpbuf.x[2] = 0;
tmpbuf.x[3] = htonl(conn->security_ix);
rxkhdr.checksum = 0;
/* encrypt from the session key */
- token = call->conn->key->payload.data[0];
+ token = call->conn->params.key->payload.data[0];
memcpy(&iv, token->kad->session_key, sizeof(iv));
sg_init_one(&sg[0], sechdr, sizeof(rxkhdr));
sp = rxrpc_skb(skb);
_enter("{%d{%x}},{#%u},%zu,",
- call->debug_id, key_serial(call->conn->key), sp->hdr.seq,
- data_size);
+ call->debug_id, key_serial(call->conn->params.key),
+ sp->hdr.seq, data_size);
if (!call->conn->cipher)
return 0;
- ret = key_validate(call->conn->key);
+ ret = key_validate(call->conn->params.key);
if (ret < 0)
return ret;
y = 1; /* zero checksums are not permitted */
sp->hdr.cksum = y;
- switch (call->conn->security_level) {
+ switch (call->conn->params.security_level) {
case RXRPC_SECURITY_PLAIN:
ret = 0;
break;
skb_to_sgvec(skb, sg, 0, skb->len);
/* decrypt from the session key */
- token = call->conn->key->payload.data[0];
+ token = call->conn->params.key->payload.data[0];
memcpy(&iv, token->kad->session_key, sizeof(iv));
skcipher_request_set_tfm(req, call->conn->cipher);
sp = rxrpc_skb(skb);
_enter("{%d{%x}},{#%u}",
- call->debug_id, key_serial(call->conn->key), sp->hdr.seq);
+ call->debug_id, key_serial(call->conn->params.key), sp->hdr.seq);
if (!call->conn->cipher)
return 0;
return -EPROTO;
}
- switch (call->conn->security_level) {
+ switch (call->conn->params.security_level) {
case RXRPC_SECURITY_PLAIN:
ret = 0;
break;
u32 serial;
int ret;
- _enter("{%d,%x}", conn->debug_id, key_serial(conn->key));
+ _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));
- ret = key_validate(conn->key);
+ ret = key_validate(conn->params.key);
if (ret < 0)
return ret;
msg.msg_controllen = 0;
msg.msg_flags = 0;
- whdr.epoch = htonl(conn->epoch);
- whdr.cid = htonl(conn->cid);
+ whdr.epoch = htonl(conn->proto.epoch);
+ whdr.cid = htonl(conn->proto.cid);
whdr.callNumber = 0;
whdr.seq = 0;
whdr.type = RXRPC_PACKET_TYPE_CHALLENGE;
whdr.userStatus = 0;
whdr.securityIndex = conn->security_ix;
whdr._rsvd = 0;
- whdr.serviceId = htons(conn->service_id);
+ whdr.serviceId = htons(conn->params.service_id);
iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr);
u32 version, nonce, min_level, abort_code;
int ret;
- _enter("{%d,%x}", conn->debug_id, key_serial(conn->key));
+ _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));
- if (!conn->key) {
+ if (!conn->params.key) {
_leave(" = -EPROTO [no key]");
return -EPROTO;
}
- ret = key_validate(conn->key);
+ ret = key_validate(conn->params.key);
if (ret < 0) {
*_abort_code = RXKADEXPIRED;
return ret;
goto protocol_error;
abort_code = RXKADLEVELFAIL;
- if (conn->security_level < min_level)
+ if (conn->params.security_level < min_level)
goto protocol_error;
- token = conn->key->payload.data[0];
+ token = conn->params.key->payload.data[0];
/* build the response packet */
memset(&resp, 0, sizeof(resp));
resp.version = htonl(RXKAD_VERSION);
- resp.encrypted.epoch = htonl(conn->epoch);
- resp.encrypted.cid = htonl(conn->cid);
+ resp.encrypted.epoch = htonl(conn->proto.epoch);
+ resp.encrypted.cid = htonl(conn->proto.cid);
resp.encrypted.securityIndex = htonl(conn->security_ix);
resp.encrypted.inc_nonce = htonl(nonce + 1);
- resp.encrypted.level = htonl(conn->security_level);
+ resp.encrypted.level = htonl(conn->params.security_level);
resp.kvno = htonl(token->kad->kvno);
resp.ticket_len = htonl(token->kad->ticket_len);
rxkad_decrypt_response(conn, &response, &session_key);
abort_code = RXKADSEALEDINCON;
- if (ntohl(response.encrypted.epoch) != conn->epoch)
+ if (ntohl(response.encrypted.epoch) != conn->proto.epoch)
goto protocol_error_free;
- if (ntohl(response.encrypted.cid) != conn->cid)
+ if (ntohl(response.encrypted.cid) != conn->proto.cid)
goto protocol_error_free;
if (ntohl(response.encrypted.securityIndex) != conn->security_ix)
goto protocol_error_free;
level = ntohl(response.encrypted.level);
if (level > RXRPC_SECURITY_ENCRYPT)
goto protocol_error_free;
- conn->security_level = level;
+ conn->params.security_level = level;
/* create a key to hold the security data and expiration time - after
* this the connection security can be handled in exactly the same way
{
const struct rxrpc_security *sec;
struct rxrpc_key_token *token;
- struct key *key = conn->key;
+ struct key *key = conn->params.key;
int ret;
_enter("{%d},{%x}", conn->debug_id, key_serial(key));
_enter("");
- sprintf(kdesc, "%u:%u", conn->service_id, conn->security_ix);
+ sprintf(kdesc, "%u:%u", conn->params.service_id, conn->security_ix);
sec = rxrpc_security_lookup(conn->security_ix);
if (!sec) {
/* find the service */
read_lock_bh(&local->services_lock);
list_for_each_entry(rx, &local->services, listen_link) {
- if (rx->srx.srx_service == conn->service_id)
+ if (rx->srx.srx_service == conn->params.service_id)
goto found_service;
}