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

📄 outqueue.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 Intel Corp. * * This file is part of the SCTP kernel implementation * * These functions implement the sctp_outq class.   The outqueue handles * bundling and queueing of outgoing SCTP chunks. * * This SCTP implementation 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, or (at your option) * any later version. * * This SCTP implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied *                 ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING.  If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Please send any bug reports or fixes you make to the * email address(es): *    lksctp developers <lksctp-developers@lists.sourceforge.net> * * Or submit a bug report through the following website: *    http://www.sf.net/projects/lksctp * * Written or modified by: *    La Monte H.P. Yarroll <piggy@acm.org> *    Karl Knutson          <karl@athena.chicago.il.us> *    Perry Melange         <pmelange@null.cc.uic.edu> *    Xingang Guo           <xingang.guo@intel.com> *    Hui Huang 	    <hui.huang@nokia.com> *    Sridhar Samudrala     <sri@us.ibm.com> *    Jon Grimm             <jgrimm@us.ibm.com> * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */#include <linux/types.h>#include <linux/list.h>   /* For struct list_head */#include <linux/socket.h>#include <linux/ip.h>#include <net/sock.h>	  /* For skb_set_owner_w */#include <net/sctp/sctp.h>#include <net/sctp/sm.h>/* Declare internal functions here.  */static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn);static void sctp_check_transmitted(struct sctp_outq *q,				   struct list_head *transmitted_queue,				   struct sctp_transport *transport,				   struct sctp_sackhdr *sack,				   __u32 highest_new_tsn);static void sctp_mark_missing(struct sctp_outq *q,			      struct list_head *transmitted_queue,			      struct sctp_transport *transport,			      __u32 highest_new_tsn,			      int count_of_newacks);static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);/* Add data to the front of the queue. */static inline void sctp_outq_head_data(struct sctp_outq *q,					struct sctp_chunk *ch){	list_add(&ch->list, &q->out_chunk_list);	q->out_qlen += ch->skb->len;	return;}/* Take data from the front of the queue. */static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q){	struct sctp_chunk *ch = NULL;	if (!list_empty(&q->out_chunk_list)) {		struct list_head *entry = q->out_chunk_list.next;		ch = list_entry(entry, struct sctp_chunk, list);		list_del_init(entry);		q->out_qlen -= ch->skb->len;	}	return ch;}/* Add data chunk to the end of the queue. */static inline void sctp_outq_tail_data(struct sctp_outq *q,				       struct sctp_chunk *ch){	list_add_tail(&ch->list, &q->out_chunk_list);	q->out_qlen += ch->skb->len;	return;}/* * SFR-CACC algorithm: * D) If count_of_newacks is greater than or equal to 2 * and t was not sent to the current primary then the * sender MUST NOT increment missing report count for t. */static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary,				       struct sctp_transport *transport,				       int count_of_newacks){	if (count_of_newacks >=2 && transport != primary)		return 1;	return 0;}/* * SFR-CACC algorithm: * F) If count_of_newacks is less than 2, let d be the * destination to which t was sent. If cacc_saw_newack * is 0 for destination d, then the sender MUST NOT * increment missing report count for t. */static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport,				       int count_of_newacks){	if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack)		return 1;	return 0;}/* * SFR-CACC algorithm: * 3.1) If CYCLING_CHANGEOVER is 0, the sender SHOULD * execute steps C, D, F. * * C has been implemented in sctp_outq_sack */static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary,				     struct sctp_transport *transport,				     int count_of_newacks){	if (!primary->cacc.cycling_changeover) {		if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks))			return 1;		if (sctp_cacc_skip_3_1_f(transport, count_of_newacks))			return 1;		return 0;	}	return 0;}/* * SFR-CACC algorithm: * 3.2) Else if CYCLING_CHANGEOVER is 1, and t is less * than next_tsn_at_change of the current primary, then * the sender MUST NOT increment missing report count * for t. */static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn){	if (primary->cacc.cycling_changeover &&	    TSN_lt(tsn, primary->cacc.next_tsn_at_change))		return 1;	return 0;}/* * SFR-CACC algorithm: * 3) If the missing report count for TSN t is to be * incremented according to [RFC2960] and * [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set, * then the sender MUST futher execute steps 3.1 and * 3.2 to determine if the missing report count for * TSN t SHOULD NOT be incremented. * * 3.3) If 3.1 and 3.2 do not dictate that the missing * report count for t should not be incremented, then * the sender SOULD increment missing report count for * t (according to [RFC2960] and [SCTP_STEWART_2002]). */static inline int sctp_cacc_skip(struct sctp_transport *primary,				 struct sctp_transport *transport,				 int count_of_newacks,				 __u32 tsn){	if (primary->cacc.changeover_active &&	    (sctp_cacc_skip_3_1(primary, transport, count_of_newacks)	     || sctp_cacc_skip_3_2(primary, tsn)))		return 1;	return 0;}/* Initialize an existing sctp_outq.  This does the boring stuff. * You still need to define handlers if you really want to DO * something with this structure... */void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q){	q->asoc = asoc;	INIT_LIST_HEAD(&q->out_chunk_list);	INIT_LIST_HEAD(&q->control_chunk_list);	INIT_LIST_HEAD(&q->retransmit);	INIT_LIST_HEAD(&q->sacked);	INIT_LIST_HEAD(&q->abandoned);	q->outstanding_bytes = 0;	q->empty = 1;	q->cork  = 0;	q->malloced = 0;	q->out_qlen = 0;}/* Free the outqueue structure and any related pending chunks. */void sctp_outq_teardown(struct sctp_outq *q){	struct sctp_transport *transport;	struct list_head *lchunk, *pos, *temp;	struct sctp_chunk *chunk, *tmp;	/* Throw away unacknowledged chunks. */	list_for_each(pos, &q->asoc->peer.transport_addr_list) {		transport = list_entry(pos, struct sctp_transport, transports);		while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) {			chunk = list_entry(lchunk, struct sctp_chunk,					   transmitted_list);			/* Mark as part of a failed message. */			sctp_chunk_fail(chunk, q->error);			sctp_chunk_free(chunk);		}	}	/* Throw away chunks that have been gap ACKed.  */	list_for_each_safe(lchunk, temp, &q->sacked) {		list_del_init(lchunk);		chunk = list_entry(lchunk, struct sctp_chunk,				   transmitted_list);		sctp_chunk_fail(chunk, q->error);		sctp_chunk_free(chunk);	}	/* Throw away any chunks in the retransmit queue. */	list_for_each_safe(lchunk, temp, &q->retransmit) {		list_del_init(lchunk);		chunk = list_entry(lchunk, struct sctp_chunk,				   transmitted_list);		sctp_chunk_fail(chunk, q->error);		sctp_chunk_free(chunk);	}	/* Throw away any chunks that are in the abandoned queue. */	list_for_each_safe(lchunk, temp, &q->abandoned) {		list_del_init(lchunk);		chunk = list_entry(lchunk, struct sctp_chunk,				   transmitted_list);		sctp_chunk_fail(chunk, q->error);		sctp_chunk_free(chunk);	}	/* Throw away any leftover data chunks. */	while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {		/* Mark as send failure. */		sctp_chunk_fail(chunk, q->error);		sctp_chunk_free(chunk);	}	q->error = 0;	/* Throw away any leftover control chunks. */	list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {		list_del_init(&chunk->list);		sctp_chunk_free(chunk);	}}/* Free the outqueue structure and any related pending chunks.  */void sctp_outq_free(struct sctp_outq *q){	/* Throw away leftover chunks. */	sctp_outq_teardown(q);	/* If we were kmalloc()'d, free the memory.  */	if (q->malloced)		kfree(q);}/* Put a new chunk in an sctp_outq.  */int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk){	int error = 0;	SCTP_DEBUG_PRINTK("sctp_outq_tail(%p, %p[%s])\n",			  q, chunk, chunk && chunk->chunk_hdr ?			  sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type))			  : "Illegal Chunk");	/* If it is data, queue it up, otherwise, send it	 * immediately.	 */	if (SCTP_CID_DATA == chunk->chunk_hdr->type) {		/* Is it OK to queue data chunks?  */		/* From 9. Termination of Association		 *		 * When either endpoint performs a shutdown, the		 * association on each peer will stop accepting new		 * data from its user and only deliver data in queue		 * at the time of sending or receiving the SHUTDOWN		 * chunk.		 */		switch (q->asoc->state) {		case SCTP_STATE_EMPTY:		case SCTP_STATE_CLOSED:		case SCTP_STATE_SHUTDOWN_PENDING:		case SCTP_STATE_SHUTDOWN_SENT:		case SCTP_STATE_SHUTDOWN_RECEIVED:		case SCTP_STATE_SHUTDOWN_ACK_SENT:			/* Cannot send after transport endpoint shutdown */			error = -ESHUTDOWN;			break;		default:			SCTP_DEBUG_PRINTK("outqueueing (%p, %p[%s])\n",			  q, chunk, chunk && chunk->chunk_hdr ?			  sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type))			  : "Illegal Chunk");			sctp_outq_tail_data(q, chunk);			if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)				SCTP_INC_STATS(SCTP_MIB_OUTUNORDERCHUNKS);			else				SCTP_INC_STATS(SCTP_MIB_OUTORDERCHUNKS);			q->empty = 0;			break;		}	} else {		list_add_tail(&chunk->list, &q->control_chunk_list);		SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);	}	if (error < 0)		return error;	if (!q->cork)		error = sctp_outq_flush(q, 0);	return error;}/* Insert a chunk into the sorted list based on the TSNs.  The retransmit list * and the abandoned list are in ascending order. */static void sctp_insert_list(struct list_head *head, struct list_head *new){	struct list_head *pos;	struct sctp_chunk *nchunk, *lchunk;	__u32 ntsn, ltsn;	int done = 0;	nchunk = list_entry(new, struct sctp_chunk, transmitted_list);	ntsn = ntohl(nchunk->subh.data_hdr->tsn);	list_for_each(pos, head) {		lchunk = list_entry(pos, struct sctp_chunk, transmitted_list);		ltsn = ntohl(lchunk->subh.data_hdr->tsn);		if (TSN_lt(ntsn, ltsn)) {			list_add(new, pos->prev);			done = 1;			break;		}	}	if (!done)		list_add_tail(new, head);}/* Mark all the eligible packets on a transport for retransmission.  */void sctp_retransmit_mark(struct sctp_outq *q,			  struct sctp_transport *transport,			  __u8 reason){	struct list_head *lchunk, *ltemp;	struct sctp_chunk *chunk;	/* Walk through the specified transmitted queue.  */	list_for_each_safe(lchunk, ltemp, &transport->transmitted) {		chunk = list_entry(lchunk, struct sctp_chunk,				   transmitted_list);		/* If the chunk is abandoned, move it to abandoned list. */		if (sctp_chunk_abandoned(chunk)) {			list_del_init(lchunk);			sctp_insert_list(&q->abandoned, lchunk);			/* If this chunk has not been previousely acked,			 * stop considering it 'outstanding'.  Our peer			 * will most likely never see it since it will			 * not be retransmitted			 */			if (!chunk->tsn_gap_acked) {				chunk->transport->flight_size -=						sctp_data_size(chunk);				q->outstanding_bytes -= sctp_data_size(chunk);				q->asoc->peer.rwnd += (sctp_data_size(chunk) +							sizeof(struct sk_buff));			}			continue;		}		/* If we are doing  retransmission due to a timeout or pmtu		 * discovery, only the  chunks that are not yet acked should		 * be added to the retransmit queue.		 */		if ((reason == SCTP_RTXR_FAST_RTX  &&			    (chunk->fast_retransmit > 0)) ||		    (reason != SCTP_RTXR_FAST_RTX  && !chunk->tsn_gap_acked)) {			/* If this chunk was sent less then 1 rto ago, do not			 * retransmit this chunk, but give the peer time			 * to acknowlege it.  Do this only when			 * retransmitting due to T3 timeout.			 */			if (reason == SCTP_RTXR_T3_RTX &&			    (jiffies - chunk->sent_at) < transport->last_rto)				continue;			/* RFC 2960 6.2.1 Processing a Received SACK			 *			 * C) Any time a DATA chunk is marked for			 * retransmission (via either T3-rtx timer expiration			 * (Section 6.3.3) or via fast retransmit			 * (Section 7.2.4)), add the data size of those			 * chunks to the rwnd.			 */			q->asoc->peer.rwnd += (sctp_data_size(chunk) +						sizeof(struct sk_buff));			q->outstanding_bytes -= sctp_data_size(chunk);			transport->flight_size -= sctp_data_size(chunk);			/* sctpimpguide-05 Section 2.8.2			 * M5) If a T3-rtx timer expires, the			 * 'TSN.Missing.Report' of all affected TSNs is set			 * to 0.			 */			chunk->tsn_missing_report = 0;			/* If a chunk that is being used for RTT measurement			 * has to be retransmitted, we cannot use this chunk

⌨️ 快捷键说明

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