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

📄 outqueue.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
					if (transport &&					    sack->num_gap_ack_blocks &&					    q->asoc->peer.primary_path->cacc.					    changeover_active)						transport->cacc.cacc_saw_newack							= 1;				}				list_add_tail(&tchunk->transmitted_list,					      &q->sacked);			} else {				/* RFC2960 7.2.4, sctpimpguide-05 2.8.2				 * M2) Each time a SACK arrives reporting				 * 'Stray DATA chunk(s)' record the highest TSN				 * reported as newly acknowledged, call this				 * value 'HighestTSNinSack'. A newly				 * acknowledged DATA chunk is one not				 * previously acknowledged in a SACK.				 *				 * When the SCTP sender of data receives a SACK				 * chunk that acknowledges, for the first time,				 * the receipt of a DATA chunk, all the still				 * unacknowledged DATA chunks whose TSN is				 * older than that newly acknowledged DATA				 * chunk, are qualified as 'Stray DATA chunks'.				 */				if (!tchunk->tsn_gap_acked) {					tchunk->tsn_gap_acked = 1;					bytes_acked += sctp_data_size(tchunk);				}				list_add_tail(lchunk, &tlist);			}#if SCTP_DEBUG			switch (dbg_prt_state) {			case 0:	/* last TSN was ACKed */				if (dbg_last_ack_tsn + 1 == tsn) {					/* This TSN belongs to the					 * current ACK range.					 */					break;				}				if (dbg_last_ack_tsn != dbg_ack_tsn) {					/* Display the end of the					 * current range.					 */					SCTP_DEBUG_PRINTK("-%08x",							  dbg_last_ack_tsn);				}				/* Start a new range.  */				SCTP_DEBUG_PRINTK(",%08x", tsn);				dbg_ack_tsn = tsn;				break;			case 1:	/* The last TSN was NOT ACKed. */				if (dbg_last_kept_tsn != dbg_kept_tsn) {					/* Display the end of current range. */					SCTP_DEBUG_PRINTK("-%08x",							  dbg_last_kept_tsn);				}				SCTP_DEBUG_PRINTK("\n");				/* FALL THROUGH... */			default:				/* This is the first-ever TSN we examined.  */				/* Start a new range of ACK-ed TSNs.  */				SCTP_DEBUG_PRINTK("ACKed: %08x", tsn);				dbg_prt_state = 0;				dbg_ack_tsn = tsn;			}			dbg_last_ack_tsn = tsn;#endif /* SCTP_DEBUG */		} else {			if (tchunk->tsn_gap_acked) {				SCTP_DEBUG_PRINTK("%s: Receiver reneged on "						  "data TSN: 0x%x\n",						  __FUNCTION__,						  tsn);				tchunk->tsn_gap_acked = 0;				bytes_acked -= sctp_data_size(tchunk);				/* RFC 2960 6.3.2 Retransmission Timer Rules				 *				 * R4) Whenever a SACK is received missing a				 * TSN that was previously acknowledged via a				 * Gap Ack Block, start T3-rtx for the				 * destination address to which the DATA				 * chunk was originally				 * transmitted if it is not already running.				 */				restart_timer = 1;			}			list_add_tail(lchunk, &tlist);#if SCTP_DEBUG			/* See the above comments on ACK-ed TSNs. */			switch (dbg_prt_state) {			case 1:				if (dbg_last_kept_tsn + 1 == tsn)					break;				if (dbg_last_kept_tsn != dbg_kept_tsn)					SCTP_DEBUG_PRINTK("-%08x",							  dbg_last_kept_tsn);				SCTP_DEBUG_PRINTK(",%08x", tsn);				dbg_kept_tsn = tsn;				break;			case 0:				if (dbg_last_ack_tsn != dbg_ack_tsn)					SCTP_DEBUG_PRINTK("-%08x",							  dbg_last_ack_tsn);				SCTP_DEBUG_PRINTK("\n");				/* FALL THROUGH... */			default:				SCTP_DEBUG_PRINTK("KEPT: %08x",tsn);				dbg_prt_state = 1;				dbg_kept_tsn = tsn;			}			dbg_last_kept_tsn = tsn;#endif /* SCTP_DEBUG */		}	}#if SCTP_DEBUG	/* Finish off the last range, displaying its ending TSN.  */	switch (dbg_prt_state) {	case 0:		if (dbg_last_ack_tsn != dbg_ack_tsn) {			SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_ack_tsn);		} else {			SCTP_DEBUG_PRINTK("\n");		}	break;	case 1:		if (dbg_last_kept_tsn != dbg_kept_tsn) {			SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_kept_tsn);		} else {			SCTP_DEBUG_PRINTK("\n");		}	}#endif /* SCTP_DEBUG */	if (transport) {		if (bytes_acked) {			/* 8.2. When an outstanding TSN is acknowledged,			 * the endpoint shall clear the error counter of			 * the destination transport address to which the			 * DATA chunk was last sent.			 * The association's overall error counter is			 * also cleared.			 */			transport->error_count = 0;			transport->asoc->overall_error_count = 0;			/* Mark the destination transport address as			 * active if it is not so marked.			 */			if ((transport->state == SCTP_INACTIVE) ||			    (transport->state == SCTP_UNCONFIRMED)) {				sctp_assoc_control_transport(					transport->asoc,					transport,					SCTP_TRANSPORT_UP,					SCTP_RECEIVED_SACK);			}			sctp_transport_raise_cwnd(transport, sack_ctsn,						  bytes_acked);			transport->flight_size -= bytes_acked;			q->outstanding_bytes -= bytes_acked;		} else {			/* RFC 2960 6.1, sctpimpguide-06 2.15.2			 * When a sender is doing zero window probing, it			 * should not timeout the association if it continues			 * to receive new packets from the receiver. The			 * reason is that the receiver MAY keep its window			 * closed for an indefinite time.			 * A sender is doing zero window probing when the			 * receiver's advertised window is zero, and there is			 * only one data chunk in flight to the receiver.			 */			if (!q->asoc->peer.rwnd &&			    !list_empty(&tlist) &&			    (sack_ctsn+2 == q->asoc->next_tsn)) {				SCTP_DEBUG_PRINTK("%s: SACK received for zero "						  "window probe: %u\n",						  __FUNCTION__, sack_ctsn);				q->asoc->overall_error_count = 0;				transport->error_count = 0;			}		}		/* RFC 2960 6.3.2 Retransmission Timer Rules		 *		 * R2) Whenever all outstanding data sent to an address have		 * been acknowledged, turn off the T3-rtx timer of that		 * address.		 */		if (!transport->flight_size) {			if (timer_pending(&transport->T3_rtx_timer) &&			    del_timer(&transport->T3_rtx_timer)) {				sctp_transport_put(transport);			}		} else if (restart_timer) {			if (!mod_timer(&transport->T3_rtx_timer,				       jiffies + transport->rto))				sctp_transport_hold(transport);		}	}	list_splice(&tlist, transmitted_queue);}/* Mark chunks as missing and consequently may get retransmitted. */static void sctp_mark_missing(struct sctp_outq *q,			      struct list_head *transmitted_queue,			      struct sctp_transport *transport,			      __u32 highest_new_tsn_in_sack,			      int count_of_newacks){	struct sctp_chunk *chunk;	struct list_head *pos;	__u32 tsn;	char do_fast_retransmit = 0;	struct sctp_transport *primary = q->asoc->peer.primary_path;	list_for_each(pos, transmitted_queue) {		chunk = list_entry(pos, struct sctp_chunk, transmitted_list);		tsn = ntohl(chunk->subh.data_hdr->tsn);		/* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all		 * 'Unacknowledged TSN's', if the TSN number of an		 * 'Unacknowledged TSN' is smaller than the 'HighestTSNinSack'		 * value, increment the 'TSN.Missing.Report' count on that		 * chunk if it has NOT been fast retransmitted or marked for		 * fast retransmit already.		 */		if (!chunk->fast_retransmit &&		    !chunk->tsn_gap_acked &&		    TSN_lt(tsn, highest_new_tsn_in_sack)) {			/* SFR-CACC may require us to skip marking			 * this chunk as missing.			 */			if (!transport || !sctp_cacc_skip(primary, transport,					    count_of_newacks, tsn)) {				chunk->tsn_missing_report++;				SCTP_DEBUG_PRINTK(					"%s: TSN 0x%x missing counter: %d\n",					__FUNCTION__, tsn,					chunk->tsn_missing_report);			}		}		/*		 * M4) If any DATA chunk is found to have a		 * 'TSN.Missing.Report'		 * value larger than or equal to 3, mark that chunk for		 * retransmission and start the fast retransmit procedure.		 */		if (chunk->tsn_missing_report >= 3) {			chunk->fast_retransmit = 1;			do_fast_retransmit = 1;		}	}	if (transport) {		if (do_fast_retransmit)			sctp_retransmit(q, transport, SCTP_RTXR_FAST_RTX);		SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "				  "ssthresh: %d, flight_size: %d, pba: %d\n",				  __FUNCTION__, transport, transport->cwnd,				  transport->ssthresh, transport->flight_size,				  transport->partial_bytes_acked);	}}/* Is the given TSN acked by this packet?  */static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn){	int i;	sctp_sack_variable_t *frags;	__u16 gap;	__u32 ctsn = ntohl(sack->cum_tsn_ack);	if (TSN_lte(tsn, ctsn))		goto pass;	/* 3.3.4 Selective Acknowledgement (SACK) (3):	 *	 * Gap Ack Blocks:	 *  These fields contain the Gap Ack Blocks. They are repeated	 *  for each Gap Ack Block up to the number of Gap Ack Blocks	 *  defined in the Number of Gap Ack Blocks field. All DATA	 *  chunks with TSNs greater than or equal to (Cumulative TSN	 *  Ack + Gap Ack Block Start) and less than or equal to	 *  (Cumulative TSN Ack + Gap Ack Block End) of each Gap Ack	 *  Block are assumed to have been received correctly.	 */	frags = sack->variable;	gap = tsn - ctsn;	for (i = 0; i < ntohs(sack->num_gap_ack_blocks); ++i) {		if (TSN_lte(ntohs(frags[i].gab.start), gap) &&		    TSN_lte(gap, ntohs(frags[i].gab.end)))			goto pass;	}	return 0;pass:	return 1;}static inline int sctp_get_skip_pos(struct sctp_fwdtsn_skip *skiplist,				    int nskips, __be16 stream){	int i;	for (i = 0; i < nskips; i++) {		if (skiplist[i].stream == stream)			return i;	}	return i;}/* Create and add a fwdtsn chunk to the outq's control queue if needed. */static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn){	struct sctp_association *asoc = q->asoc;	struct sctp_chunk *ftsn_chunk = NULL;	struct sctp_fwdtsn_skip ftsn_skip_arr[10];	int nskips = 0;	int skip_pos = 0;	__u32 tsn;	struct sctp_chunk *chunk;	struct list_head *lchunk, *temp;	/* PR-SCTP C1) Let SackCumAck be the Cumulative TSN ACK carried in the	 * received SACK.	 *	 * If (Advanced.Peer.Ack.Point < SackCumAck), then update	 * Advanced.Peer.Ack.Point to be equal to SackCumAck.	 */	if (TSN_lt(asoc->adv_peer_ack_point, ctsn))		asoc->adv_peer_ack_point = ctsn;	/* PR-SCTP C2) Try to further advance the "Advanced.Peer.Ack.Point"	 * locally, that is, to move "Advanced.Peer.Ack.Point" up as long as	 * the chunk next in the out-queue space is marked as "abandoned" as	 * shown in the following example:	 *	 * Assuming that a SACK arrived with the Cumulative TSN ACK 102	 * and the Advanced.Peer.Ack.Point is updated to this value:	 *	 *   out-queue at the end of  ==>   out-queue after Adv.Ack.Point	 *   normal SACK processing           local advancement	 *                ...                           ...	 *   Adv.Ack.Pt-> 102 acked                     102 acked	 *                103 abandoned                 103 abandoned	 *                104 abandoned     Adv.Ack.P-> 104 abandoned	 *                105                           105	 *                106 acked                     106 acked	 *                ...                           ...	 *	 * In this example, the data sender successfully advanced the	 * "Advanced.Peer.Ack.Point" from 102 to 104 locally.	 */	list_for_each_safe(lchunk, temp, &q->abandoned) {		chunk = list_entry(lchunk, struct sctp_chunk,					transmitted_list);		tsn = ntohl(chunk->subh.data_hdr->tsn);		/* Remove any chunks in the abandoned queue that are acked by		 * the ctsn.		 */		if (TSN_lte(tsn, ctsn)) {			list_del_init(lchunk);			sctp_chunk_free(chunk);		} else {			if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) {				asoc->adv_peer_ack_point = tsn;				if (chunk->chunk_hdr->flags &					 SCTP_DATA_UNORDERED)					continue;				skip_pos = sctp_get_skip_pos(&ftsn_skip_arr[0],						nskips,						chunk->subh.data_hdr->stream);				ftsn_skip_arr[skip_pos].stream =					chunk->subh.data_hdr->stream;				ftsn_skip_arr[skip_pos].ssn =					 chunk->subh.data_hdr->ssn;				if (skip_pos == nskips)					nskips++;				if (nskips == 10)					break;			} else				break;		}	}	/* PR-SCTP C3) If, after step C1 and C2, the "Advanced.Peer.Ack.Point"	 * is greater than the Cumulative TSN ACK carried in the received	 * SACK, the data sender MUST send the data receiver a FORWARD TSN	 * chunk containing the latest value of the	 * "Advanced.Peer.Ack.Point".	 *	 * C4) For each "abandoned" TSN the sender of the FORWARD TSN SHOULD	 * list each stream and sequence number in the forwarded TSN. This	 * information will enable the receiver to easily find any	 * stranded TSN's waiting on stream reorder queues. Each stream	 * SHOULD only be reported once; this means that if multiple	 * abandoned messages occur in the same stream then only the	 * highest abandoned stream sequence number is reported. If the	 * total size of the FORWARD TSN does NOT fit in a single MTU then	 * the sender of the FORWARD TSN SHOULD lower the	 * Advanced.Peer.Ack.Point to the last TSN that will fit in a	 * single MTU.	 */	if (asoc->adv_peer_ack_point > ctsn)		ftsn_chunk = sctp_make_fwdtsn(asoc, asoc->adv_peer_ack_point,					      nskips, &ftsn_skip_arr[0]);	if (ftsn_chunk) {		list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);		SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);	}}

⌨️ 快捷键说明

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