diff options
author | David Howells <dhowells@redhat.com> | 2016-04-04 14:00:40 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2016-07-06 10:49:35 +0100 |
commit | 7877a4a4bdf0d782276f1cba868878aee77718ee (patch) | |
tree | d7bbda493ebfda88069805ac2b19a21e3ef5e771 /net/rxrpc/conn_service.c | |
parent | c6d2b8d764f5edd79f708bdc49d1176072ee77a1 (diff) | |
download | linux-7877a4a4bdf0d782276f1cba868878aee77718ee.tar.gz linux-7877a4a4bdf0d782276f1cba868878aee77718ee.tar.bz2 linux-7877a4a4bdf0d782276f1cba868878aee77718ee.zip |
rxrpc: Split service connection code out into its own file
Split the service-specific connection code out into into its own file. The
client-specific code has already been split out. This will leave just the
common code in the original file.
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'net/rxrpc/conn_service.c')
-rw-r--r-- | net/rxrpc/conn_service.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/net/rxrpc/conn_service.c b/net/rxrpc/conn_service.c new file mode 100644 index 000000000000..cdcac50cd1a8 --- /dev/null +++ b/net/rxrpc/conn_service.c @@ -0,0 +1,145 @@ +/* Service connection management + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include <linux/slab.h> +#include "ar-internal.h" + +/* + * get a record of an incoming connection + */ +struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *local, + struct rxrpc_peer *peer, + struct sk_buff *skb) +{ + struct rxrpc_connection *conn, *candidate = NULL; + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); + struct rb_node *p, **pp; + const char *new = "old"; + u32 epoch, cid; + + _enter(""); + + ASSERT(sp->hdr.flags & RXRPC_CLIENT_INITIATED); + + epoch = sp->hdr.epoch; + cid = sp->hdr.cid & RXRPC_CIDMASK; + + /* search the connection list first */ + read_lock_bh(&peer->conn_lock); + + p = peer->service_conns.rb_node; + while (p) { + conn = rb_entry(p, struct rxrpc_connection, service_node); + + _debug("maybe %x", conn->proto.cid); + + if (epoch < conn->proto.epoch) + p = p->rb_left; + else if (epoch > conn->proto.epoch) + p = p->rb_right; + else if (cid < conn->proto.cid) + p = p->rb_left; + else if (cid > conn->proto.cid) + p = p->rb_right; + else + goto found_extant_connection; + } + read_unlock_bh(&peer->conn_lock); + + /* not yet present - create a candidate for a new record and then + * redo the search */ + candidate = rxrpc_alloc_connection(GFP_NOIO); + if (!candidate) { + _leave(" = -ENOMEM"); + return ERR_PTR(-ENOMEM); + } + + candidate->proto.local = local; + candidate->proto.epoch = sp->hdr.epoch; + candidate->proto.cid = sp->hdr.cid & RXRPC_CIDMASK; + candidate->proto.in_clientflag = RXRPC_CLIENT_INITIATED; + candidate->params.local = local; + candidate->params.peer = peer; + candidate->params.service_id = sp->hdr.serviceId; + candidate->security_ix = sp->hdr.securityIndex; + candidate->out_clientflag = 0; + candidate->state = RXRPC_CONN_SERVICE; + if (candidate->params.service_id) + candidate->state = RXRPC_CONN_SERVICE_UNSECURED; + + write_lock_bh(&peer->conn_lock); + + pp = &peer->service_conns.rb_node; + p = NULL; + while (*pp) { + p = *pp; + conn = rb_entry(p, struct rxrpc_connection, service_node); + + if (epoch < conn->proto.epoch) + pp = &(*pp)->rb_left; + else if (epoch > conn->proto.epoch) + pp = &(*pp)->rb_right; + else if (cid < conn->proto.cid) + pp = &(*pp)->rb_left; + else if (cid > conn->proto.cid) + pp = &(*pp)->rb_right; + else + goto found_extant_second; + } + + /* we can now add the new candidate to the list */ + conn = candidate; + candidate = NULL; + rb_link_node(&conn->service_node, p, pp); + rb_insert_color(&conn->service_node, &peer->service_conns); + rxrpc_get_peer(peer); + rxrpc_get_local(local); + + write_unlock_bh(&peer->conn_lock); + + write_lock(&rxrpc_connection_lock); + list_add_tail(&conn->link, &rxrpc_connections); + write_unlock(&rxrpc_connection_lock); + + new = "new"; + +success: + _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->proto.cid); + + _leave(" = %p {u=%d}", conn, atomic_read(&conn->usage)); + return conn; + + /* we found the connection in the list immediately */ +found_extant_connection: + if (sp->hdr.securityIndex != conn->security_ix) { + read_unlock_bh(&peer->conn_lock); + goto security_mismatch; + } + rxrpc_get_connection(conn); + read_unlock_bh(&peer->conn_lock); + goto success; + + /* we found the connection on the second time through the list */ +found_extant_second: + if (sp->hdr.securityIndex != conn->security_ix) { + write_unlock_bh(&peer->conn_lock); + goto security_mismatch; + } + rxrpc_get_connection(conn); + write_unlock_bh(&peer->conn_lock); + kfree(candidate); + goto success; + +security_mismatch: + kfree(candidate); + _leave(" = -EKEYREJECTED"); + return ERR_PTR(-EKEYREJECTED); +} |