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

📄 ar-output.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* RxRPC packet transmission * * 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/net.h>#include <linux/skbuff.h>#include <linux/circ_buf.h>#include <net/sock.h>#include <net/af_rxrpc.h>#include "ar-internal.h"int rxrpc_resend_timeout = 4;static int rxrpc_send_data(struct kiocb *iocb,			   struct rxrpc_sock *rx,			   struct rxrpc_call *call,			   struct msghdr *msg, size_t len);/* * extract control messages from the sendmsg() control buffer */static int rxrpc_sendmsg_cmsg(struct rxrpc_sock *rx, struct msghdr *msg,			      unsigned long *user_call_ID,			      enum rxrpc_command *command,			      u32 *abort_code,			      bool server){	struct cmsghdr *cmsg;	int len;	*command = RXRPC_CMD_SEND_DATA;	if (msg->msg_controllen == 0)		return -EINVAL;	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {		if (!CMSG_OK(msg, cmsg))			return -EINVAL;		len = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));		_debug("CMSG %d, %d, %d",		       cmsg->cmsg_level, cmsg->cmsg_type, len);		if (cmsg->cmsg_level != SOL_RXRPC)			continue;		switch (cmsg->cmsg_type) {		case RXRPC_USER_CALL_ID:			if (msg->msg_flags & MSG_CMSG_COMPAT) {				if (len != sizeof(u32))					return -EINVAL;				*user_call_ID = *(u32 *) CMSG_DATA(cmsg);			} else {				if (len != sizeof(unsigned long))					return -EINVAL;				*user_call_ID = *(unsigned long *)					CMSG_DATA(cmsg);			}			_debug("User Call ID %lx", *user_call_ID);			break;		case RXRPC_ABORT:			if (*command != RXRPC_CMD_SEND_DATA)				return -EINVAL;			*command = RXRPC_CMD_SEND_ABORT;			if (len != sizeof(*abort_code))				return -EINVAL;			*abort_code = *(unsigned int *) CMSG_DATA(cmsg);			_debug("Abort %x", *abort_code);			if (*abort_code == 0)				return -EINVAL;			break;		case RXRPC_ACCEPT:			if (*command != RXRPC_CMD_SEND_DATA)				return -EINVAL;			*command = RXRPC_CMD_ACCEPT;			if (len != 0)				return -EINVAL;			if (!server)				return -EISCONN;			break;		default:			return -EINVAL;		}	}	_leave(" = 0");	return 0;}/* * abort a call, sending an ABORT packet to the peer */static void rxrpc_send_abort(struct rxrpc_call *call, u32 abort_code){	write_lock_bh(&call->state_lock);	if (call->state <= RXRPC_CALL_COMPLETE) {		call->state = RXRPC_CALL_LOCALLY_ABORTED;		call->abort_code = abort_code;		set_bit(RXRPC_CALL_ABORT, &call->events);		del_timer_sync(&call->resend_timer);		del_timer_sync(&call->ack_timer);		clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);		clear_bit(RXRPC_CALL_ACK, &call->events);		clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);		rxrpc_queue_call(call);	}	write_unlock_bh(&call->state_lock);}/* * send a message forming part of a client call through an RxRPC socket * - caller holds the socket locked * - the socket may be either a client socket or a server socket */int rxrpc_client_sendmsg(struct kiocb *iocb, struct rxrpc_sock *rx,			 struct rxrpc_transport *trans, struct msghdr *msg,			 size_t len){	struct rxrpc_conn_bundle *bundle;	enum rxrpc_command cmd;	struct rxrpc_call *call;	unsigned long user_call_ID = 0;	struct key *key;	__be16 service_id;	u32 abort_code = 0;	int ret;	_enter("");	ASSERT(trans != NULL);	ret = rxrpc_sendmsg_cmsg(rx, msg, &user_call_ID, &cmd, &abort_code,				 false);	if (ret < 0)		return ret;	bundle = NULL;	if (trans) {		service_id = rx->service_id;		if (msg->msg_name) {			struct sockaddr_rxrpc *srx =				(struct sockaddr_rxrpc *) msg->msg_name;			service_id = htons(srx->srx_service);		}		key = rx->key;		if (key && !rx->key->payload.data)			key = NULL;		bundle = rxrpc_get_bundle(rx, trans, key, service_id,					  GFP_KERNEL);		if (IS_ERR(bundle))			return PTR_ERR(bundle);	}	call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID,				     abort_code == 0, GFP_KERNEL);	if (trans)		rxrpc_put_bundle(trans, bundle);	if (IS_ERR(call)) {		_leave(" = %ld", PTR_ERR(call));		return PTR_ERR(call);	}	_debug("CALL %d USR %lx ST %d on CONN %p",	       call->debug_id, call->user_call_ID, call->state, call->conn);	if (call->state >= RXRPC_CALL_COMPLETE) {		/* it's too late for this call */		ret = -ESHUTDOWN;	} else if (cmd == RXRPC_CMD_SEND_ABORT) {		rxrpc_send_abort(call, abort_code);	} else if (cmd != RXRPC_CMD_SEND_DATA) {		ret = -EINVAL;	} else if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST) {		/* request phase complete for this client call */		ret = -EPROTO;	} else {		ret = rxrpc_send_data(iocb, rx, call, msg, len);	}	rxrpc_put_call(call);	_leave(" = %d", ret);	return ret;}/** * rxrpc_kernel_send_data - Allow a kernel service to send data on a call * @call: The call to send data through * @msg: The data to send * @len: The amount of data to send * * Allow a kernel service to send data on a call.  The call must be in an state * appropriate to sending data.  No control data should be supplied in @msg, * nor should an address be supplied.  MSG_MORE should be flagged if there's * more data to come, otherwise this data will end the transmission phase. */int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg,			   size_t len){	int ret;	_enter("{%d,%s},", call->debug_id, rxrpc_call_states[call->state]);	ASSERTCMP(msg->msg_name, ==, NULL);	ASSERTCMP(msg->msg_control, ==, NULL);	lock_sock(&call->socket->sk);	_debug("CALL %d USR %lx ST %d on CONN %p",	       call->debug_id, call->user_call_ID, call->state, call->conn);	if (call->state >= RXRPC_CALL_COMPLETE) {		ret = -ESHUTDOWN; /* it's too late for this call */	} else if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST &&		   call->state != RXRPC_CALL_SERVER_ACK_REQUEST &&		   call->state != RXRPC_CALL_SERVER_SEND_REPLY) {		ret = -EPROTO; /* request phase complete for this client call */	} else {		mm_segment_t oldfs = get_fs();		set_fs(KERNEL_DS);		ret = rxrpc_send_data(NULL, call->socket, call, msg, len);		set_fs(oldfs);	}	release_sock(&call->socket->sk);	_leave(" = %d", ret);	return ret;}EXPORT_SYMBOL(rxrpc_kernel_send_data);/* * rxrpc_kernel_abort_call - Allow a kernel service to abort a call * @call: The call to be aborted * @abort_code: The abort code to stick into the ABORT packet * * Allow a kernel service to abort a call, if it's still in an abortable state. */void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code){	_enter("{%d},%d", call->debug_id, abort_code);	lock_sock(&call->socket->sk);	_debug("CALL %d USR %lx ST %d on CONN %p",	       call->debug_id, call->user_call_ID, call->state, call->conn);	if (call->state < RXRPC_CALL_COMPLETE)		rxrpc_send_abort(call, abort_code);	release_sock(&call->socket->sk);	_leave("");}EXPORT_SYMBOL(rxrpc_kernel_abort_call);/* * send a message through a server socket * - caller holds the socket locked */int rxrpc_server_sendmsg(struct kiocb *iocb, struct rxrpc_sock *rx,			 struct msghdr *msg, size_t len){	enum rxrpc_command cmd;	struct rxrpc_call *call;	unsigned long user_call_ID = 0;	u32 abort_code = 0;	int ret;	_enter("");	ret = rxrpc_sendmsg_cmsg(rx, msg, &user_call_ID, &cmd, &abort_code,				 true);	if (ret < 0)		return ret;	if (cmd == RXRPC_CMD_ACCEPT) {		call = rxrpc_accept_call(rx, user_call_ID);		if (IS_ERR(call))			return PTR_ERR(call);		rxrpc_put_call(call);		return 0;	}	call = rxrpc_find_server_call(rx, user_call_ID);	if (!call)		return -EBADSLT;	if (call->state >= RXRPC_CALL_COMPLETE) {		ret = -ESHUTDOWN;		goto out;	}	switch (cmd) {	case RXRPC_CMD_SEND_DATA:		if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST &&		    call->state != RXRPC_CALL_SERVER_ACK_REQUEST &&		    call->state != RXRPC_CALL_SERVER_SEND_REPLY) {			/* Tx phase not yet begun for this call */			ret = -EPROTO;			break;		}		ret = rxrpc_send_data(iocb, rx, call, msg, len);		break;	case RXRPC_CMD_SEND_ABORT:		rxrpc_send_abort(call, abort_code);		break;	default:		BUG();	}	out:	rxrpc_put_call(call);	_leave(" = %d", ret);	return ret;}/* * send a packet through the transport endpoint */int rxrpc_send_packet(struct rxrpc_transport *trans, struct sk_buff *skb){	struct kvec iov[1];	struct msghdr msg;	int ret, opt;	_enter(",{%d}", skb->len);	iov[0].iov_base = skb->head;	iov[0].iov_len = skb->len;	msg.msg_name = &trans->peer->srx.transport.sin;	msg.msg_namelen = sizeof(trans->peer->srx.transport.sin);	msg.msg_control = NULL;	msg.msg_controllen = 0;	msg.msg_flags = 0;	/* send the packet with the don't fragment bit set if we currently	 * think it's small enough */	if (skb->len - sizeof(struct rxrpc_header) < trans->peer->maxdata) {		down_read(&trans->local->defrag_sem);		/* send the packet by UDP		 * - returns -EMSGSIZE if UDP would have to fragment the packet		 *   to go out of the interface		 *   - in which case, we'll have processed the ICMP error		 *     message and update the peer record		 */		ret = kernel_sendmsg(trans->local->socket, &msg, iov, 1,				     iov[0].iov_len);		up_read(&trans->local->defrag_sem);		if (ret == -EMSGSIZE)			goto send_fragmentable;		_leave(" = %d [%u]", ret, trans->peer->maxdata);		return ret;	}

⌨️ 快捷键说明

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