connection.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 777 行 · 第 1/2 页

C
777
字号
/* connection.c: Rx connection routines * * Copyright (C) 2002 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 License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/sched.h>#include <linux/slab.h>#include <linux/module.h>#include <rxrpc/rxrpc.h>#include <rxrpc/transport.h>#include <rxrpc/peer.h>#include <rxrpc/connection.h>#include <rxrpc/call.h>#include <rxrpc/message.h>#include <linux/udp.h>#include <linux/ip.h>#include <net/sock.h>#include <asm/uaccess.h>#include "internal.h"__RXACCT_DECL(atomic_t rxrpc_connection_count);LIST_HEAD(rxrpc_conns);DECLARE_RWSEM(rxrpc_conns_sem);unsigned long rxrpc_conn_timeout = 60 * 60;static void __rxrpc_conn_timeout(rxrpc_timer_t *timer){	struct rxrpc_connection *conn =		list_entry(timer, struct rxrpc_connection, timeout);	_debug("Rx CONN TIMEOUT [%p{u=%d}]", conn, atomic_read(&conn->usage));	rxrpc_conn_do_timeout(conn);}static const struct rxrpc_timer_ops rxrpc_conn_timer_ops = {	.timed_out	= __rxrpc_conn_timeout,};/*****************************************************************************//* * create a new connection record */static inline int __rxrpc_create_connection(struct rxrpc_peer *peer,					    struct rxrpc_connection **_conn){	struct rxrpc_connection *conn;	_enter("%p",peer);	/* allocate and initialise a connection record */	conn = kmalloc(sizeof(struct rxrpc_connection), GFP_KERNEL);	if (!conn) {		_leave(" = -ENOMEM");		return -ENOMEM;	}	memset(conn, 0, sizeof(struct rxrpc_connection));	atomic_set(&conn->usage, 1);	INIT_LIST_HEAD(&conn->link);	INIT_LIST_HEAD(&conn->id_link);	init_waitqueue_head(&conn->chanwait);	spin_lock_init(&conn->lock);	rxrpc_timer_init(&conn->timeout, &rxrpc_conn_timer_ops);	do_gettimeofday(&conn->atime);	conn->mtu_size = 1024;	conn->peer = peer;	conn->trans = peer->trans;	__RXACCT(atomic_inc(&rxrpc_connection_count));	*_conn = conn;	_leave(" = 0 (%p)", conn);	return 0;} /* end __rxrpc_create_connection() *//*****************************************************************************//* * create a new connection record for outgoing connections */int rxrpc_create_connection(struct rxrpc_transport *trans,			    __be16 port,			    __be32 addr,			    uint16_t service_id,			    void *security,			    struct rxrpc_connection **_conn){	struct rxrpc_connection *candidate, *conn;	struct rxrpc_peer *peer;	struct list_head *_p;	__be32 connid;	int ret;	_enter("%p{%hu},%u,%hu", trans, trans->port, ntohs(port), service_id);	/* get a peer record */	ret = rxrpc_peer_lookup(trans, addr, &peer);	if (ret < 0) {		_leave(" = %d", ret);		return ret;	}	/* allocate and initialise a connection record */	ret = __rxrpc_create_connection(peer, &candidate);	if (ret < 0) {		rxrpc_put_peer(peer);		_leave(" = %d", ret);		return ret;	}	/* fill in the specific bits */	candidate->addr.sin_family	= AF_INET;	candidate->addr.sin_port	= port;	candidate->addr.sin_addr.s_addr	= addr;	candidate->in_epoch		= rxrpc_epoch;	candidate->out_epoch		= rxrpc_epoch;	candidate->in_clientflag	= 0;	candidate->out_clientflag	= RXRPC_CLIENT_INITIATED;	candidate->service_id		= htons(service_id);	/* invent a unique connection ID */	write_lock(&peer->conn_idlock); try_next_id:	connid = htonl(peer->conn_idcounter & RXRPC_CIDMASK);	peer->conn_idcounter += RXRPC_MAXCALLS;	list_for_each(_p, &peer->conn_idlist) {		conn = list_entry(_p, struct rxrpc_connection, id_link);		if (connid == conn->conn_id)			goto try_next_id;		if (connid > conn->conn_id)			break;	}	_debug("selected candidate conn ID %x.%u",	       ntohl(peer->addr.s_addr), ntohl(connid));	candidate->conn_id = connid;	list_add_tail(&candidate->id_link, _p);	write_unlock(&peer->conn_idlock);	/* attach to peer */	candidate->peer = peer;	write_lock(&peer->conn_lock);	/* search the peer's transport graveyard list */	spin_lock(&peer->conn_gylock);	list_for_each(_p, &peer->conn_graveyard) {		conn = list_entry(_p, struct rxrpc_connection, link);		if (conn->addr.sin_port	== candidate->addr.sin_port	&&		    conn->security_ix	== candidate->security_ix	&&		    conn->service_id	== candidate->service_id	&& 		    conn->in_clientflag	== 0)			goto found_in_graveyard;	}	spin_unlock(&peer->conn_gylock);	/* pick the new candidate */	_debug("created connection: {%08x} [out]", ntohl(candidate->conn_id));	atomic_inc(&peer->conn_count);	conn = candidate;	candidate = NULL; make_active:	list_add_tail(&conn->link, &peer->conn_active);	write_unlock(&peer->conn_lock);	if (candidate) {		write_lock(&peer->conn_idlock);		list_del(&candidate->id_link);		write_unlock(&peer->conn_idlock);		__RXACCT(atomic_dec(&rxrpc_connection_count));		kfree(candidate);	}	else {		down_write(&rxrpc_conns_sem);		list_add_tail(&conn->proc_link, &rxrpc_conns);		up_write(&rxrpc_conns_sem);	}	*_conn = conn;	_leave(" = 0 (%p)", conn);	return 0;	/* handle resurrecting a connection from the graveyard */ found_in_graveyard:	_debug("resurrecting connection: {%08x} [out]", ntohl(conn->conn_id));	rxrpc_get_connection(conn);	rxrpc_krxtimod_del_timer(&conn->timeout);	list_del_init(&conn->link);	spin_unlock(&peer->conn_gylock);	goto make_active;} /* end rxrpc_create_connection() *//*****************************************************************************//* * lookup the connection for an incoming packet * - create a new connection record for unrecorded incoming connections */int rxrpc_connection_lookup(struct rxrpc_peer *peer,			    struct rxrpc_message *msg,			    struct rxrpc_connection **_conn){	struct rxrpc_connection *conn, *candidate = NULL;	struct list_head *_p;	int ret, fresh = 0;	__be32 x_epoch, x_connid;	__be16 x_port, x_servid;	__u32 x_secix;	u8 x_clflag;	_enter("%p{{%hu}},%u,%hu",	       peer,	       peer->trans->port,	       ntohs(msg->pkt->h.uh->source),	       ntohs(msg->hdr.serviceId));	x_port		= msg->pkt->h.uh->source;	x_epoch		= msg->hdr.epoch;	x_clflag	= msg->hdr.flags & RXRPC_CLIENT_INITIATED;	x_connid	= htonl(ntohl(msg->hdr.cid) & RXRPC_CIDMASK);	x_servid	= msg->hdr.serviceId;	x_secix		= msg->hdr.securityIndex;	/* [common case] search the transport's active list first */	read_lock(&peer->conn_lock);	list_for_each(_p, &peer->conn_active) {		conn = list_entry(_p, struct rxrpc_connection, link);		if (conn->addr.sin_port		== x_port	&&		    conn->in_epoch		== x_epoch	&&		    conn->conn_id		== x_connid	&&		    conn->security_ix		== x_secix	&&		    conn->service_id		== x_servid	&& 		    conn->in_clientflag		== x_clflag)			goto found_active;	}	read_unlock(&peer->conn_lock);	/* [uncommon case] not active 	 * - create a candidate for a new record if an inbound connection	 * - only examine the graveyard for an outbound connection	 */	if (x_clflag) {		ret = __rxrpc_create_connection(peer, &candidate);		if (ret < 0) {			_leave(" = %d", ret);			return ret;		}		/* fill in the specifics */		candidate->addr.sin_family	= AF_INET;		candidate->addr.sin_port	= x_port;		candidate->addr.sin_addr.s_addr = msg->pkt->nh.iph->saddr;		candidate->in_epoch		= x_epoch;		candidate->out_epoch		= x_epoch;		candidate->in_clientflag	= RXRPC_CLIENT_INITIATED;		candidate->out_clientflag	= 0;		candidate->conn_id		= x_connid;		candidate->service_id		= x_servid;		candidate->security_ix		= x_secix;	}	/* search the active list again, just in case it appeared whilst we	 * were busy */	write_lock(&peer->conn_lock);	list_for_each(_p, &peer->conn_active) {		conn = list_entry(_p, struct rxrpc_connection, link);		if (conn->addr.sin_port		== x_port	&&		    conn->in_epoch		== x_epoch	&&		    conn->conn_id		== x_connid	&&		    conn->security_ix		== x_secix	&&		    conn->service_id		== x_servid	&& 		    conn->in_clientflag		== x_clflag)			goto found_active_second_chance;	}	/* search the transport's graveyard list */	spin_lock(&peer->conn_gylock);	list_for_each(_p, &peer->conn_graveyard) {		conn = list_entry(_p, struct rxrpc_connection, link);		if (conn->addr.sin_port		== x_port	&&		    conn->in_epoch		== x_epoch	&&		    conn->conn_id		== x_connid	&&		    conn->security_ix		== x_secix	&&		    conn->service_id		== x_servid	&& 		    conn->in_clientflag		== x_clflag)			goto found_in_graveyard;	}	spin_unlock(&peer->conn_gylock);	/* outbound connections aren't created here */	if (!x_clflag) {		write_unlock(&peer->conn_lock);		_leave(" = -ENOENT");		return -ENOENT;	}	/* we can now add the new candidate to the list */	_debug("created connection: {%08x} [in]", ntohl(candidate->conn_id));	rxrpc_get_peer(peer);	conn = candidate;	candidate = NULL;	atomic_inc(&peer->conn_count);	fresh = 1; make_active:	list_add_tail(&conn->link, &peer->conn_active); success_uwfree:	write_unlock(&peer->conn_lock);	if (candidate) {		write_lock(&peer->conn_idlock);		list_del(&candidate->id_link);		write_unlock(&peer->conn_idlock);		__RXACCT(atomic_dec(&rxrpc_connection_count));		kfree(candidate);	}	if (fresh) {		down_write(&rxrpc_conns_sem);		list_add_tail(&conn->proc_link, &rxrpc_conns);		up_write(&rxrpc_conns_sem);	} success:	*_conn = conn;	_leave(" = 0 (%p)", conn);	return 0;	/* handle the connection being found in the active list straight off */ found_active:	rxrpc_get_connection(conn);	read_unlock(&peer->conn_lock);	goto success;	/* handle resurrecting a connection from the graveyard */ found_in_graveyard:	_debug("resurrecting connection: {%08x} [in]", ntohl(conn->conn_id));	rxrpc_get_peer(peer);	rxrpc_get_connection(conn);	rxrpc_krxtimod_del_timer(&conn->timeout);	list_del_init(&conn->link);	spin_unlock(&peer->conn_gylock);	goto make_active;	/* handle finding the connection on the second time through the active	 * list */ found_active_second_chance:	rxrpc_get_connection(conn);	goto success_uwfree;} /* end rxrpc_connection_lookup() *//*****************************************************************************//* * finish using a connection record * - it will be transferred to the peer's connection graveyard when refcount *   reaches 0 */void rxrpc_put_connection(struct rxrpc_connection *conn){	struct rxrpc_peer *peer;	if (!conn)		return;	_enter("%p{u=%d p=%hu}",	       conn, atomic_read(&conn->usage), ntohs(conn->addr.sin_port));	peer = conn->peer;	spin_lock(&peer->conn_gylock);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?