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

📄 ar-input.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* RxRPC packet reception * * 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/errqueue.h>#include <linux/udp.h>#include <linux/in.h>#include <linux/in6.h>#include <linux/icmp.h>#include <net/sock.h>#include <net/af_rxrpc.h>#include <net/ip.h>#include "ar-internal.h"unsigned long rxrpc_ack_timeout = 1;const char *rxrpc_pkts[] = {	"?00",	"DATA", "ACK", "BUSY", "ABORT", "ACKALL", "CHALL", "RESP", "DEBUG",	"?09", "?10", "?11", "?12", "?13", "?14", "?15"};/* * queue a packet for recvmsg to pass to userspace * - the caller must hold a lock on call->lock * - must not be called with interrupts disabled (sk_filter() disables BH's) * - eats the packet whether successful or not * - there must be just one reference to the packet, which the caller passes to *   this function */int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,			bool force, bool terminal){	struct rxrpc_skb_priv *sp;	struct rxrpc_sock *rx = call->socket;	struct sock *sk;	int skb_len, ret;	_enter(",,%d,%d", force, terminal);	ASSERT(!irqs_disabled());	sp = rxrpc_skb(skb);	ASSERTCMP(sp->call, ==, call);	/* if we've already posted the terminal message for a call, then we	 * don't post any more */	if (test_bit(RXRPC_CALL_TERMINAL_MSG, &call->flags)) {		_debug("already terminated");		ASSERTCMP(call->state, >=, RXRPC_CALL_COMPLETE);		skb->destructor = NULL;		sp->call = NULL;		rxrpc_put_call(call);		rxrpc_free_skb(skb);		return 0;	}	sk = &rx->sk;	if (!force) {		/* cast skb->rcvbuf to unsigned...  It's pointless, but		 * reduces number of warnings when compiling with -W		 * --ANK *///		ret = -ENOBUFS;//		if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=//		    (unsigned) sk->sk_rcvbuf)//			goto out;		ret = sk_filter(sk, skb);		if (ret < 0)			goto out;	}	spin_lock_bh(&sk->sk_receive_queue.lock);	if (!test_bit(RXRPC_CALL_TERMINAL_MSG, &call->flags) &&	    !test_bit(RXRPC_CALL_RELEASED, &call->flags) &&	    call->socket->sk.sk_state != RXRPC_CLOSE) {		skb->destructor = rxrpc_packet_destructor;		skb->dev = NULL;		skb->sk = sk;		atomic_add(skb->truesize, &sk->sk_rmem_alloc);		if (terminal) {			_debug("<<<< TERMINAL MESSAGE >>>>");			set_bit(RXRPC_CALL_TERMINAL_MSG, &call->flags);		}		/* allow interception by a kernel service */		if (rx->interceptor) {			rx->interceptor(sk, call->user_call_ID, skb);			spin_unlock_bh(&sk->sk_receive_queue.lock);		} else {			/* Cache the SKB length before we tack it onto the			 * receive queue.  Once it is added it no longer			 * belongs to us and may be freed by other threads of			 * control pulling packets from the queue */			skb_len = skb->len;			_net("post skb %p", skb);			__skb_queue_tail(&sk->sk_receive_queue, skb);			spin_unlock_bh(&sk->sk_receive_queue.lock);			if (!sock_flag(sk, SOCK_DEAD))				sk->sk_data_ready(sk, skb_len);		}		skb = NULL;	} else {		spin_unlock_bh(&sk->sk_receive_queue.lock);	}	ret = 0;out:	/* release the socket buffer */	if (skb) {		skb->destructor = NULL;		sp->call = NULL;		rxrpc_put_call(call);		rxrpc_free_skb(skb);	}	_leave(" = %d", ret);	return ret;}/* * process a DATA packet, posting the packet to the appropriate queue * - eats the packet if successful */static int rxrpc_fast_process_data(struct rxrpc_call *call,				   struct sk_buff *skb, u32 seq){	struct rxrpc_skb_priv *sp;	bool terminal;	int ret, ackbit, ack;	_enter("{%u,%u},,{%u}", call->rx_data_post, call->rx_first_oos, seq);	sp = rxrpc_skb(skb);	ASSERTCMP(sp->call, ==, NULL);	spin_lock(&call->lock);	if (call->state > RXRPC_CALL_COMPLETE)		goto discard;	ASSERTCMP(call->rx_data_expect, >=, call->rx_data_post);	ASSERTCMP(call->rx_data_post, >=, call->rx_data_recv);	ASSERTCMP(call->rx_data_recv, >=, call->rx_data_eaten);	if (seq < call->rx_data_post) {		_debug("dup #%u [-%u]", seq, call->rx_data_post);		ack = RXRPC_ACK_DUPLICATE;		ret = -ENOBUFS;		goto discard_and_ack;	}	/* we may already have the packet in the out of sequence queue */	ackbit = seq - (call->rx_data_eaten + 1);	ASSERTCMP(ackbit, >=, 0);	if (__test_and_set_bit(ackbit, call->ackr_window)) {		_debug("dup oos #%u [%u,%u]",		       seq, call->rx_data_eaten, call->rx_data_post);		ack = RXRPC_ACK_DUPLICATE;		goto discard_and_ack;	}	if (seq >= call->ackr_win_top) {		_debug("exceed #%u [%u]", seq, call->ackr_win_top);		__clear_bit(ackbit, call->ackr_window);		ack = RXRPC_ACK_EXCEEDS_WINDOW;		goto discard_and_ack;	}	if (seq == call->rx_data_expect) {		clear_bit(RXRPC_CALL_EXPECT_OOS, &call->flags);		call->rx_data_expect++;	} else if (seq > call->rx_data_expect) {		_debug("oos #%u [%u]", seq, call->rx_data_expect);		call->rx_data_expect = seq + 1;		if (test_and_set_bit(RXRPC_CALL_EXPECT_OOS, &call->flags)) {			ack = RXRPC_ACK_OUT_OF_SEQUENCE;			goto enqueue_and_ack;		}		goto enqueue_packet;	}	if (seq != call->rx_data_post) {		_debug("ahead #%u [%u]", seq, call->rx_data_post);		goto enqueue_packet;	}	if (test_bit(RXRPC_CALL_RCVD_LAST, &call->flags))		goto protocol_error;	/* if the packet need security things doing to it, then it goes down	 * the slow path */	if (call->conn->security)		goto enqueue_packet;	sp->call = call;	rxrpc_get_call(call);	terminal = ((sp->hdr.flags & RXRPC_LAST_PACKET) &&		    !(sp->hdr.flags & RXRPC_CLIENT_INITIATED));	ret = rxrpc_queue_rcv_skb(call, skb, false, terminal);	if (ret < 0) {		if (ret == -ENOMEM || ret == -ENOBUFS) {			__clear_bit(ackbit, call->ackr_window);			ack = RXRPC_ACK_NOSPACE;			goto discard_and_ack;		}		goto out;	}	skb = NULL;	_debug("post #%u", seq);	ASSERTCMP(call->rx_data_post, ==, seq);	call->rx_data_post++;	if (sp->hdr.flags & RXRPC_LAST_PACKET)		set_bit(RXRPC_CALL_RCVD_LAST, &call->flags);	/* if we've reached an out of sequence packet then we need to drain	 * that queue into the socket Rx queue now */	if (call->rx_data_post == call->rx_first_oos) {		_debug("drain rx oos now");		read_lock(&call->state_lock);		if (call->state < RXRPC_CALL_COMPLETE &&		    !test_and_set_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events))			rxrpc_queue_call(call);		read_unlock(&call->state_lock);	}	spin_unlock(&call->lock);	atomic_inc(&call->ackr_not_idle);	rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, sp->hdr.serial, false);	_leave(" = 0 [posted]");	return 0;protocol_error:	ret = -EBADMSG;out:	spin_unlock(&call->lock);	_leave(" = %d", ret);	return ret;discard_and_ack:	_debug("discard and ACK packet %p", skb);	__rxrpc_propose_ACK(call, ack, sp->hdr.serial, true);discard:	spin_unlock(&call->lock);	rxrpc_free_skb(skb);	_leave(" = 0 [discarded]");	return 0;enqueue_and_ack:	__rxrpc_propose_ACK(call, ack, sp->hdr.serial, true);enqueue_packet:	_net("defer skb %p", skb);	spin_unlock(&call->lock);	skb_queue_tail(&call->rx_queue, skb);	atomic_inc(&call->ackr_not_idle);	read_lock(&call->state_lock);	if (call->state < RXRPC_CALL_DEAD)		rxrpc_queue_call(call);	read_unlock(&call->state_lock);	_leave(" = 0 [queued]");	return 0;}/* * assume an implicit ACKALL of the transmission phase of a client socket upon * reception of the first reply packet */static void rxrpc_assume_implicit_ackall(struct rxrpc_call *call, u32 serial){	write_lock_bh(&call->state_lock);	switch (call->state) {	case RXRPC_CALL_CLIENT_AWAIT_REPLY:		call->state = RXRPC_CALL_CLIENT_RECV_REPLY;		call->acks_latest = serial;		_debug("implicit ACKALL %%%u", call->acks_latest);		set_bit(RXRPC_CALL_RCVD_ACKALL, &call->events);		write_unlock_bh(&call->state_lock);		if (try_to_del_timer_sync(&call->resend_timer) >= 0) {			clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);			clear_bit(RXRPC_CALL_RESEND, &call->events);			clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);		}		break;	default:		write_unlock_bh(&call->state_lock);		break;	}}/* * post an incoming packet to the nominated call to deal with * - must get rid of the sk_buff, either by freeing it or by queuing it */void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb){	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);	__be32 _abort_code;	u32 serial, hi_serial, seq, abort_code;	_enter("%p,%p", call, skb);	ASSERT(!irqs_disabled());#if 0 // INJECT RX ERROR	if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA) {		static int skip = 0;		if (++skip == 3) {			printk("DROPPED 3RD PACKET!!!!!!!!!!!!!\n");			skip = 0;			goto free_packet;		}	}#endif	/* track the latest serial number on this connection for ACK packet	 * information */	serial = ntohl(sp->hdr.serial);	hi_serial = atomic_read(&call->conn->hi_serial);	while (serial > hi_serial)		hi_serial = atomic_cmpxchg(&call->conn->hi_serial, hi_serial,					   serial);	/* request ACK generation for any ACK or DATA packet that requests	 * it */	if (sp->hdr.flags & RXRPC_REQUEST_ACK) {		_proto("ACK Requested on %%%u", serial);		rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial,				  !(sp->hdr.flags & RXRPC_MORE_PACKETS));	}	switch (sp->hdr.type) {	case RXRPC_PACKET_TYPE_ABORT:		_debug("abort");		if (skb_copy_bits(skb, 0, &_abort_code,				  sizeof(_abort_code)) < 0)			goto protocol_error;		abort_code = ntohl(_abort_code);		_proto("Rx ABORT %%%u { %x }", serial, abort_code);		write_lock_bh(&call->state_lock);		if (call->state < RXRPC_CALL_COMPLETE) {			call->state = RXRPC_CALL_REMOTELY_ABORTED;			call->abort_code = abort_code;			set_bit(RXRPC_CALL_RCVD_ABORT, &call->events);			rxrpc_queue_call(call);		}		goto free_packet_unlock;	case RXRPC_PACKET_TYPE_BUSY:		_proto("Rx BUSY %%%u", serial);		if (call->conn->out_clientflag)			goto protocol_error;		write_lock_bh(&call->state_lock);		switch (call->state) {		case RXRPC_CALL_CLIENT_SEND_REQUEST:			call->state = RXRPC_CALL_SERVER_BUSY;			set_bit(RXRPC_CALL_RCVD_BUSY, &call->events);			rxrpc_queue_call(call);		case RXRPC_CALL_SERVER_BUSY:			goto free_packet_unlock;		default:			goto protocol_error_locked;		}	default:		_proto("Rx %s %%%u", rxrpc_pkts[sp->hdr.type], serial);		goto protocol_error;	case RXRPC_PACKET_TYPE_DATA:		seq = ntohl(sp->hdr.seq);		_proto("Rx DATA %%%u { #%u }", serial, seq);

⌨️ 快捷键说明

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