📄 af_rxrpc.c
字号:
/* 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 + -