transport.c

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

C
865
字号
	_leave(" = 0 #%d", atomic_read(&rxrpc_message_count));	return 0; error:	while (!list_empty(msgq)) {		msg = list_entry(msgq->next, struct rxrpc_message, link);		list_del_init(&msg->link);		rxrpc_put_message(msg);	}	_leave(" = %d", ret);	return ret;} /* end rxrpc_incoming_msg() *//*****************************************************************************//* * accept a new call * - called from krxiod in process context */void rxrpc_trans_receive_packet(struct rxrpc_transport *trans){	struct rxrpc_message *msg;	struct rxrpc_peer *peer;	struct sk_buff *pkt;	int ret;	__be32 addr;	__be16 port;	LIST_HEAD(msgq);	_enter("%p{%d}", trans, trans->port);	for (;;) {		/* deal with outstanting errors first */		if (trans->error_rcvd)			rxrpc_trans_receive_error_report(trans);		/* attempt to receive a packet */		pkt = skb_recv_datagram(trans->socket->sk, 0, 1, &ret);		if (!pkt) {			if (ret == -EAGAIN) {				_leave(" EAGAIN");				return;			}			/* an icmp error may have occurred */			rxrpc_krxiod_queue_transport(trans);			_leave(" error %d\n", ret);			return;		}		/* we'll probably need to checksum it (didn't call		 * sock_recvmsg) */		if (pkt->ip_summed != CHECKSUM_UNNECESSARY) {			if ((unsigned short)			    csum_fold(skb_checksum(pkt, 0, pkt->len,						   pkt->csum))) {				kfree_skb(pkt);				rxrpc_krxiod_queue_transport(trans);				_leave(" CSUM failed");				return;			}		}		addr = pkt->nh.iph->saddr;		port = pkt->h.uh->source;		_net("Rx Received UDP packet from %08x:%04hu",		     ntohl(addr), ntohs(port));		/* unmarshall the Rx parameters and split jumbo packets */		ret = rxrpc_incoming_msg(trans, pkt, &msgq);		if (ret < 0) {			kfree_skb(pkt);			rxrpc_krxiod_queue_transport(trans);			_leave(" bad packet");			return;		}		BUG_ON(list_empty(&msgq));		msg = list_entry(msgq.next, struct rxrpc_message, link);		/* locate the record for the peer from which it		 * originated */		ret = rxrpc_peer_lookup(trans, addr, &peer);		if (ret < 0) {			kdebug("Rx No connections from that peer");			rxrpc_trans_immediate_abort(trans, msg, -EINVAL);			goto finished_msg;		}		/* try and find a matching connection */		ret = rxrpc_connection_lookup(peer, msg, &msg->conn);		if (ret < 0) {			kdebug("Rx Unknown Connection");			rxrpc_trans_immediate_abort(trans, msg, -EINVAL);			rxrpc_put_peer(peer);			goto finished_msg;		}		rxrpc_put_peer(peer);		/* deal with the first packet of a new call */		if (msg->hdr.flags & RXRPC_CLIENT_INITIATED &&		    msg->hdr.type == RXRPC_PACKET_TYPE_DATA &&		    ntohl(msg->hdr.seq) == 1		    ) {			_debug("Rx New server call");			rxrpc_trans_receive_new_call(trans, &msgq);			goto finished_msg;		}		/* deal with subsequent packet(s) of call */		_debug("Rx Call packet");		while (!list_empty(&msgq)) {			msg = list_entry(msgq.next, struct rxrpc_message, link);			list_del_init(&msg->link);			ret = rxrpc_conn_receive_call_packet(msg->conn, NULL, msg);			if (ret < 0) {				rxrpc_trans_immediate_abort(trans, msg, ret);				rxrpc_put_message(msg);				goto finished_msg;			}			rxrpc_put_message(msg);		}		goto finished_msg;		/* dispose of the packets */	finished_msg:		while (!list_empty(&msgq)) {			msg = list_entry(msgq.next, struct rxrpc_message, link);			list_del_init(&msg->link);			rxrpc_put_message(msg);		}		kfree_skb(pkt);	}	_leave("");} /* end rxrpc_trans_receive_packet() *//*****************************************************************************//* * accept a new call from a client trying to connect to one of my services * - called in process context */static int rxrpc_trans_receive_new_call(struct rxrpc_transport *trans,					struct list_head *msgq){	struct rxrpc_message *msg;	_enter("");	/* only bother with the first packet */	msg = list_entry(msgq->next, struct rxrpc_message, link);	list_del_init(&msg->link);	rxrpc_krxsecd_queue_incoming_call(msg);	rxrpc_put_message(msg);	_leave(" = 0");	return 0;} /* end rxrpc_trans_receive_new_call() *//*****************************************************************************//* * perform an immediate abort without connection or call structures */int rxrpc_trans_immediate_abort(struct rxrpc_transport *trans,				struct rxrpc_message *msg,				int error){	struct rxrpc_header ahdr;	struct sockaddr_in sin;	struct msghdr msghdr;	struct kvec iov[2];	__be32 _error;	int len, ret;	_enter("%p,%p,%d", trans, msg, error);	/* don't abort an abort packet */	if (msg->hdr.type == RXRPC_PACKET_TYPE_ABORT) {		_leave(" = 0");		return 0;	}	_error = htonl(-error);	/* set up the message to be transmitted */	memcpy(&ahdr, &msg->hdr, sizeof(ahdr));	ahdr.epoch	= msg->hdr.epoch;	ahdr.serial	= htonl(1);	ahdr.seq	= 0;	ahdr.type	= RXRPC_PACKET_TYPE_ABORT;	ahdr.flags	= RXRPC_LAST_PACKET;	ahdr.flags	|= ~msg->hdr.flags & RXRPC_CLIENT_INITIATED;	iov[0].iov_len	= sizeof(ahdr);	iov[0].iov_base	= &ahdr;	iov[1].iov_len	= sizeof(_error);	iov[1].iov_base	= &_error;	len = sizeof(ahdr) + sizeof(_error);	memset(&sin,0,sizeof(sin));	sin.sin_family		= AF_INET;	sin.sin_port		= msg->pkt->h.uh->source;	sin.sin_addr.s_addr	= msg->pkt->nh.iph->saddr;	msghdr.msg_name		= &sin;	msghdr.msg_namelen	= sizeof(sin);	msghdr.msg_control	= NULL;	msghdr.msg_controllen	= 0;	msghdr.msg_flags	= MSG_DONTWAIT;	_net("Sending message type %d of %d bytes to %08x:%d",	     ahdr.type,	     len,	     ntohl(sin.sin_addr.s_addr),	     ntohs(sin.sin_port));	/* send the message */	ret = kernel_sendmsg(trans->socket, &msghdr, iov, 2, len);	_leave(" = %d", ret);	return ret;} /* end rxrpc_trans_immediate_abort() *//*****************************************************************************//* * receive an ICMP error report and percolate it to all connections * heading to the affected host or port */static void rxrpc_trans_receive_error_report(struct rxrpc_transport *trans){	struct rxrpc_connection *conn;	struct sockaddr_in sin;	struct rxrpc_peer *peer;	struct list_head connq, *_p;	struct errormsg emsg;	struct msghdr msg;	__be16 port;	int local, err;	_enter("%p", trans);	for (;;) {		trans->error_rcvd = 0;		/* try and receive an error message */		msg.msg_name	= &sin;		msg.msg_namelen	= sizeof(sin);		msg.msg_control	= &emsg;		msg.msg_controllen = sizeof(emsg);		msg.msg_flags	= 0;		err = kernel_recvmsg(trans->socket, &msg, NULL, 0, 0,				   MSG_ERRQUEUE | MSG_DONTWAIT | MSG_TRUNC);		if (err == -EAGAIN) {			_leave("");			return;		}		if (err < 0) {			printk("%s: unable to recv an error report: %d\n",			       __FUNCTION__, err);			_leave("");			return;		}		msg.msg_controllen = (char *) msg.msg_control - (char *) &emsg;		if (msg.msg_controllen < sizeof(emsg.cmsg) ||		    msg.msg_namelen < sizeof(sin)) {			printk("%s: short control message"			       " (nlen=%u clen=%Zu fl=%x)\n",			       __FUNCTION__,			       msg.msg_namelen,			       msg.msg_controllen,			       msg.msg_flags);			continue;		}		_net("Rx Received control message"		     " { len=%Zu level=%u type=%u }",		     emsg.cmsg.cmsg_len,		     emsg.cmsg.cmsg_level,		     emsg.cmsg.cmsg_type);		if (sin.sin_family != AF_INET) {			printk("Rx Ignoring error report with non-INET address"			       " (fam=%u)",			       sin.sin_family);			continue;		}		_net("Rx Received message pertaining to host addr=%x port=%hu",		     ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port));		if (emsg.cmsg.cmsg_level != SOL_IP ||		    emsg.cmsg.cmsg_type != IP_RECVERR) {			printk("Rx Ignoring unknown error report"			       " { level=%u type=%u }",			       emsg.cmsg.cmsg_level,			       emsg.cmsg.cmsg_type);			continue;		}		if (msg.msg_controllen < sizeof(emsg.cmsg) + sizeof(emsg.ee)) {			printk("%s: short error message (%Zu)\n",			       __FUNCTION__, msg.msg_controllen);			_leave("");			return;		}		port = sin.sin_port;		switch (emsg.ee.ee_origin) {		case SO_EE_ORIGIN_ICMP:			local = 0;			switch (emsg.ee.ee_type) {			case ICMP_DEST_UNREACH:				switch (emsg.ee.ee_code) {				case ICMP_NET_UNREACH:					_net("Rx Received ICMP Network Unreachable");					port = 0;					err = -ENETUNREACH;					break;				case ICMP_HOST_UNREACH:					_net("Rx Received ICMP Host Unreachable");					port = 0;					err = -EHOSTUNREACH;					break;				case ICMP_PORT_UNREACH:					_net("Rx Received ICMP Port Unreachable");					err = -ECONNREFUSED;					break;				case ICMP_NET_UNKNOWN:					_net("Rx Received ICMP Unknown Network");					port = 0;					err = -ENETUNREACH;					break;				case ICMP_HOST_UNKNOWN:					_net("Rx Received ICMP Unknown Host");					port = 0;					err = -EHOSTUNREACH;					break;				default:					_net("Rx Received ICMP DestUnreach { code=%u }",					     emsg.ee.ee_code);					err = emsg.ee.ee_errno;					break;				}				break;			case ICMP_TIME_EXCEEDED:				_net("Rx Received ICMP TTL Exceeded");				err = emsg.ee.ee_errno;				break;			default:				_proto("Rx Received ICMP error { type=%u code=%u }",				       emsg.ee.ee_type, emsg.ee.ee_code);				err = emsg.ee.ee_errno;				break;			}			break;		case SO_EE_ORIGIN_LOCAL:			_proto("Rx Received local error { error=%d }",			       emsg.ee.ee_errno);			local = 1;			err = emsg.ee.ee_errno;			break;		case SO_EE_ORIGIN_NONE:		case SO_EE_ORIGIN_ICMP6:		default:			_proto("Rx Received error report { orig=%u }",			       emsg.ee.ee_origin);			local = 0;			err = emsg.ee.ee_errno;			break;		}		/* find all the connections between this transport and the		 * affected destination */		INIT_LIST_HEAD(&connq);		if (rxrpc_peer_lookup(trans, sin.sin_addr.s_addr,				      &peer) == 0) {			read_lock(&peer->conn_lock);			list_for_each(_p, &peer->conn_active) {				conn = list_entry(_p, struct rxrpc_connection,						  link);				if (port && conn->addr.sin_port != port)					continue;				if (!list_empty(&conn->err_link))					continue;				rxrpc_get_connection(conn);				list_add_tail(&conn->err_link, &connq);			}			read_unlock(&peer->conn_lock);			/* service all those connections */			while (!list_empty(&connq)) {				conn = list_entry(connq.next,						  struct rxrpc_connection,						  err_link);				list_del(&conn->err_link);				rxrpc_conn_handle_error(conn, local, err);				rxrpc_put_connection(conn);			}			rxrpc_put_peer(peer);		}	}	_leave("");	return;} /* end rxrpc_trans_receive_error_report() */

⌨️ 快捷键说明

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