⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 af_rxrpc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* AF_RXRPC implementation * * Copyright (C) 2007 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/module.h>#include <linux/net.h>#include <linux/skbuff.h>#include <linux/poll.h>#include <linux/proc_fs.h>#include <linux/key-type.h>#include <net/net_namespace.h>#include <net/sock.h>#include <net/af_rxrpc.h>#include "ar-internal.h"MODULE_DESCRIPTION("RxRPC network protocol");MODULE_AUTHOR("Red Hat, Inc.");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_RXRPC);unsigned rxrpc_debug; // = RXRPC_DEBUG_KPROTO;module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(rxrpc_debug, "RxRPC debugging mask");static int sysctl_rxrpc_max_qlen __read_mostly = 10;static struct proto rxrpc_proto;static const struct proto_ops rxrpc_rpc_ops;/* local epoch for detecting local-end reset */__be32 rxrpc_epoch;/* current debugging ID */atomic_t rxrpc_debug_id;/* count of skbs currently in use */atomic_t rxrpc_n_skbs;struct workqueue_struct *rxrpc_workqueue;static void rxrpc_sock_destructor(struct sock *);/* * see if an RxRPC socket is currently writable */static inline int rxrpc_writable(struct sock *sk){	return atomic_read(&sk->sk_wmem_alloc) < (size_t) sk->sk_sndbuf;}/* * wait for write bufferage to become available */static void rxrpc_write_space(struct sock *sk){	_enter("%p", sk);	read_lock(&sk->sk_callback_lock);	if (rxrpc_writable(sk)) {		if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))			wake_up_interruptible(sk->sk_sleep);		sk_wake_async(sk, 2, POLL_OUT);	}	read_unlock(&sk->sk_callback_lock);}/* * validate an RxRPC address */static int rxrpc_validate_address(struct rxrpc_sock *rx,				  struct sockaddr_rxrpc *srx,				  int len){	if (len < sizeof(struct sockaddr_rxrpc))		return -EINVAL;	if (srx->srx_family != AF_RXRPC)		return -EAFNOSUPPORT;	if (srx->transport_type != SOCK_DGRAM)		return -ESOCKTNOSUPPORT;	len -= offsetof(struct sockaddr_rxrpc, transport);	if (srx->transport_len < sizeof(sa_family_t) ||	    srx->transport_len > len)		return -EINVAL;	if (srx->transport.family != rx->proto)		return -EAFNOSUPPORT;	switch (srx->transport.family) {	case AF_INET:		_debug("INET: %x @ %u.%u.%u.%u",		       ntohs(srx->transport.sin.sin_port),		       NIPQUAD(srx->transport.sin.sin_addr));		if (srx->transport_len > 8)			memset((void *)&srx->transport + 8, 0,			       srx->transport_len - 8);		break;	case AF_INET6:	default:		return -EAFNOSUPPORT;	}	return 0;}/* * bind a local address to an RxRPC socket */static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len){	struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) saddr;	struct sock *sk = sock->sk;	struct rxrpc_local *local;	struct rxrpc_sock *rx = rxrpc_sk(sk), *prx;	__be16 service_id;	int ret;	_enter("%p,%p,%d", rx, saddr, len);	ret = rxrpc_validate_address(rx, srx, len);	if (ret < 0)		goto error;	lock_sock(&rx->sk);	if (rx->sk.sk_state != RXRPC_UNCONNECTED) {		ret = -EINVAL;		goto error_unlock;	}	memcpy(&rx->srx, srx, sizeof(rx->srx));	/* find a local transport endpoint if we don't have one already */	local = rxrpc_lookup_local(&rx->srx);	if (IS_ERR(local)) {		ret = PTR_ERR(local);		goto error_unlock;	}	rx->local = local;	if (srx->srx_service) {		service_id = htons(srx->srx_service);		write_lock_bh(&local->services_lock);		list_for_each_entry(prx, &local->services, listen_link) {			if (prx->service_id == service_id)				goto service_in_use;		}		rx->service_id = service_id;		list_add_tail(&rx->listen_link, &local->services);		write_unlock_bh(&local->services_lock);		rx->sk.sk_state = RXRPC_SERVER_BOUND;	} else {		rx->sk.sk_state = RXRPC_CLIENT_BOUND;	}	release_sock(&rx->sk);	_leave(" = 0");	return 0;service_in_use:	ret = -EADDRINUSE;	write_unlock_bh(&local->services_lock);error_unlock:	release_sock(&rx->sk);error:	_leave(" = %d", ret);	return ret;}/* * set the number of pending calls permitted on a listening socket */static int rxrpc_listen(struct socket *sock, int backlog){	struct sock *sk = sock->sk;	struct rxrpc_sock *rx = rxrpc_sk(sk);	int ret;	_enter("%p,%d", rx, backlog);	lock_sock(&rx->sk);	switch (rx->sk.sk_state) {	case RXRPC_UNCONNECTED:		ret = -EADDRNOTAVAIL;		break;	case RXRPC_CLIENT_BOUND:	case RXRPC_CLIENT_CONNECTED:	default:		ret = -EBUSY;		break;	case RXRPC_SERVER_BOUND:		ASSERT(rx->local != NULL);		sk->sk_max_ack_backlog = backlog;		rx->sk.sk_state = RXRPC_SERVER_LISTENING;		ret = 0;		break;	}	release_sock(&rx->sk);	_leave(" = %d", ret);	return ret;}/* * find a transport by address */static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock,						       struct sockaddr *addr,						       int addr_len, int flags,						       gfp_t gfp){	struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr;	struct rxrpc_transport *trans;	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);	struct rxrpc_peer *peer;	_enter("%p,%p,%d,%d", rx, addr, addr_len, flags);	ASSERT(rx->local != NULL);	ASSERT(rx->sk.sk_state > RXRPC_UNCONNECTED);	if (rx->srx.transport_type != srx->transport_type)		return ERR_PTR(-ESOCKTNOSUPPORT);	if (rx->srx.transport.family != srx->transport.family)		return ERR_PTR(-EAFNOSUPPORT);	/* find a remote transport endpoint from the local one */	peer = rxrpc_get_peer(srx, gfp);	if (IS_ERR(peer))		return ERR_PTR(PTR_ERR(peer));	/* find a transport */	trans = rxrpc_get_transport(rx->local, peer, gfp);	rxrpc_put_peer(peer);	_leave(" = %p", trans);	return trans;}/** * rxrpc_kernel_begin_call - Allow a kernel service to begin a call * @sock: The socket on which to make the call * @srx: The address of the peer to contact (defaults to socket setting) * @key: The security context to use (defaults to socket setting) * @user_call_ID: The ID to use * * Allow a kernel service to begin a call on the nominated socket.  This just * sets up all the internal tracking structures and allocates connection and * call IDs as appropriate.  The call to be used is returned. * * The default socket destination address and security may be overridden by * supplying @srx and @key. */struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,					   struct sockaddr_rxrpc *srx,					   struct key *key,					   unsigned long user_call_ID,					   gfp_t gfp){	struct rxrpc_conn_bundle *bundle;	struct rxrpc_transport *trans;	struct rxrpc_call *call;	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);	__be16 service_id;	_enter(",,%x,%lx", key_serial(key), user_call_ID);	lock_sock(&rx->sk);	if (srx) {		trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx,						sizeof(*srx), 0, gfp);		if (IS_ERR(trans)) {			call = ERR_PTR(PTR_ERR(trans));			trans = NULL;			goto out;		}	} else {		trans = rx->trans;		if (!trans) {			call = ERR_PTR(-ENOTCONN);			goto out;		}		atomic_inc(&trans->usage);	}	service_id = rx->service_id;	if (srx)		service_id = htons(srx->srx_service);	if (!key)		key = rx->key;	if (key && !key->payload.data)		key = NULL; /* a no-security key */	bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);	if (IS_ERR(bundle)) {		call = ERR_PTR(PTR_ERR(bundle));		goto out;	}	call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID, true,				     gfp);	rxrpc_put_bundle(trans, bundle);out:	rxrpc_put_transport(trans);	release_sock(&rx->sk);	_leave(" = %p", call);	return call;}EXPORT_SYMBOL(rxrpc_kernel_begin_call);/** * rxrpc_kernel_end_call - Allow a kernel service to end a call it was using * @call: The call to end * * Allow a kernel service to end a call it was using.  The call must be * complete before this is called (the call should be aborted if necessary). */void rxrpc_kernel_end_call(struct rxrpc_call *call){	_enter("%d{%d}", call->debug_id, atomic_read(&call->usage));	rxrpc_remove_user_ID(call->socket, call);	rxrpc_put_call(call);}EXPORT_SYMBOL(rxrpc_kernel_end_call);/** * rxrpc_kernel_intercept_rx_messages - Intercept received RxRPC messages * @sock: The socket to intercept received messages on * @interceptor: The function to pass the messages to * * Allow a kernel service to intercept messages heading for the Rx queue on an * RxRPC socket.  They get passed to the specified function instead. * @interceptor should free the socket buffers it is given.  @interceptor is * called with the socket receive queue spinlock held and softirqs disabled - * this ensures that the messages will be delivered in the right order. */void rxrpc_kernel_intercept_rx_messages(struct socket *sock,					rxrpc_interceptor_t interceptor){	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);	_enter("");	rx->interceptor = interceptor;}EXPORT_SYMBOL(rxrpc_kernel_intercept_rx_messages);/* * connect an RxRPC socket * - this just targets it at a specific destination; no actual connection *   negotiation takes place */static int rxrpc_connect(struct socket *sock, struct sockaddr *addr,			 int addr_len, int flags){	struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr;	struct sock *sk = sock->sk;	struct rxrpc_transport *trans;	struct rxrpc_local *local;	struct rxrpc_sock *rx = rxrpc_sk(sk);	int ret;	_enter("%p,%p,%d,%d", rx, addr, addr_len, flags);	ret = rxrpc_validate_address(rx, srx, addr_len);	if (ret < 0) {		_leave(" = %d [bad addr]", ret);		return ret;	}	lock_sock(&rx->sk);	switch (rx->sk.sk_state) {	case RXRPC_UNCONNECTED:		/* find a local transport endpoint if we don't have one already */		ASSERTCMP(rx->local, ==, NULL);		rx->srx.srx_family = AF_RXRPC;		rx->srx.srx_service = 0;		rx->srx.transport_type = srx->transport_type;		rx->srx.transport_len = sizeof(sa_family_t);		rx->srx.transport.family = srx->transport.family;		local = rxrpc_lookup_local(&rx->srx);		if (IS_ERR(local)) {			release_sock(&rx->sk);			return PTR_ERR(local);		}		rx->local = local;		rx->sk.sk_state = RXRPC_CLIENT_BOUND;	case RXRPC_CLIENT_BOUND:		break;	case RXRPC_CLIENT_CONNECTED:		release_sock(&rx->sk);		return -EISCONN;	default:		release_sock(&rx->sk);		return -EBUSY; /* server sockets can't connect as well */	}	trans = rxrpc_name_to_transport(sock, addr, addr_len, flags,					GFP_KERNEL);	if (IS_ERR(trans)) {		release_sock(&rx->sk);		_leave(" = %ld", PTR_ERR(trans));		return PTR_ERR(trans);	}	rx->trans = trans;	rx->service_id = htons(srx->srx_service);	rx->sk.sk_state = RXRPC_CLIENT_CONNECTED;	release_sock(&rx->sk);	return 0;}/* * send a message through an RxRPC socket * - in a client this does a number of things: *   - finds/sets up a connection for the security specified (if any) *   - initiates a call (ID in control data) *   - ends the request phase of a call (if MSG_MORE is not set) *   - sends a call data packet *   - may send an abort (abort code in control data) */static int rxrpc_sendmsg(struct kiocb *iocb, struct socket *sock,			 struct msghdr *m, size_t len){	struct rxrpc_transport *trans;	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);

⌨️ 快捷键说明

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