162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* SCTP kernel implementation 362306a36Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 462306a36Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 562306a36Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 662306a36Sopenharmony_ci * Copyright (c) 2001-2003 Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file is part of the SCTP kernel implementation 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * These functions implement the sctp_outq class. The outqueue handles 1162306a36Sopenharmony_ci * bundling and queueing of outgoing SCTP chunks. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Please send any bug reports or fixes you make to the 1462306a36Sopenharmony_ci * email address(es): 1562306a36Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Written or modified by: 1862306a36Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 1962306a36Sopenharmony_ci * Karl Knutson <karl@athena.chicago.il.us> 2062306a36Sopenharmony_ci * Perry Melange <pmelange@null.cc.uic.edu> 2162306a36Sopenharmony_ci * Xingang Guo <xingang.guo@intel.com> 2262306a36Sopenharmony_ci * Hui Huang <hui.huang@nokia.com> 2362306a36Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 2462306a36Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/types.h> 3062306a36Sopenharmony_ci#include <linux/list.h> /* For struct list_head */ 3162306a36Sopenharmony_ci#include <linux/socket.h> 3262306a36Sopenharmony_ci#include <linux/ip.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci#include <net/sock.h> /* For skb_set_owner_w */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <net/sctp/sctp.h> 3762306a36Sopenharmony_ci#include <net/sctp/sm.h> 3862306a36Sopenharmony_ci#include <net/sctp/stream_sched.h> 3962306a36Sopenharmony_ci#include <trace/events/sctp.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Declare internal functions here. */ 4262306a36Sopenharmony_cistatic int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn); 4362306a36Sopenharmony_cistatic void sctp_check_transmitted(struct sctp_outq *q, 4462306a36Sopenharmony_ci struct list_head *transmitted_queue, 4562306a36Sopenharmony_ci struct sctp_transport *transport, 4662306a36Sopenharmony_ci union sctp_addr *saddr, 4762306a36Sopenharmony_ci struct sctp_sackhdr *sack, 4862306a36Sopenharmony_ci __u32 *highest_new_tsn); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic void sctp_mark_missing(struct sctp_outq *q, 5162306a36Sopenharmony_ci struct list_head *transmitted_queue, 5262306a36Sopenharmony_ci struct sctp_transport *transport, 5362306a36Sopenharmony_ci __u32 highest_new_tsn, 5462306a36Sopenharmony_ci int count_of_newacks); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* Add data to the front of the queue. */ 5962306a36Sopenharmony_cistatic inline void sctp_outq_head_data(struct sctp_outq *q, 6062306a36Sopenharmony_ci struct sctp_chunk *ch) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct sctp_stream_out_ext *oute; 6362306a36Sopenharmony_ci __u16 stream; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci list_add(&ch->list, &q->out_chunk_list); 6662306a36Sopenharmony_ci q->out_qlen += ch->skb->len; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci stream = sctp_chunk_stream_no(ch); 6962306a36Sopenharmony_ci oute = SCTP_SO(&q->asoc->stream, stream)->ext; 7062306a36Sopenharmony_ci list_add(&ch->stream_list, &oute->outq); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* Take data from the front of the queue. */ 7462306a36Sopenharmony_cistatic inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci return q->sched->dequeue(q); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* Add data chunk to the end of the queue. */ 8062306a36Sopenharmony_cistatic inline void sctp_outq_tail_data(struct sctp_outq *q, 8162306a36Sopenharmony_ci struct sctp_chunk *ch) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct sctp_stream_out_ext *oute; 8462306a36Sopenharmony_ci __u16 stream; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci list_add_tail(&ch->list, &q->out_chunk_list); 8762306a36Sopenharmony_ci q->out_qlen += ch->skb->len; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci stream = sctp_chunk_stream_no(ch); 9062306a36Sopenharmony_ci oute = SCTP_SO(&q->asoc->stream, stream)->ext; 9162306a36Sopenharmony_ci list_add_tail(&ch->stream_list, &oute->outq); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* 9562306a36Sopenharmony_ci * SFR-CACC algorithm: 9662306a36Sopenharmony_ci * D) If count_of_newacks is greater than or equal to 2 9762306a36Sopenharmony_ci * and t was not sent to the current primary then the 9862306a36Sopenharmony_ci * sender MUST NOT increment missing report count for t. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary, 10162306a36Sopenharmony_ci struct sctp_transport *transport, 10262306a36Sopenharmony_ci int count_of_newacks) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci if (count_of_newacks >= 2 && transport != primary) 10562306a36Sopenharmony_ci return 1; 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * SFR-CACC algorithm: 11162306a36Sopenharmony_ci * F) If count_of_newacks is less than 2, let d be the 11262306a36Sopenharmony_ci * destination to which t was sent. If cacc_saw_newack 11362306a36Sopenharmony_ci * is 0 for destination d, then the sender MUST NOT 11462306a36Sopenharmony_ci * increment missing report count for t. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport, 11762306a36Sopenharmony_ci int count_of_newacks) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci if (count_of_newacks < 2 && 12062306a36Sopenharmony_ci (transport && !transport->cacc.cacc_saw_newack)) 12162306a36Sopenharmony_ci return 1; 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* 12662306a36Sopenharmony_ci * SFR-CACC algorithm: 12762306a36Sopenharmony_ci * 3.1) If CYCLING_CHANGEOVER is 0, the sender SHOULD 12862306a36Sopenharmony_ci * execute steps C, D, F. 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * C has been implemented in sctp_outq_sack 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_cistatic inline int sctp_cacc_skip_3_1(struct sctp_transport *primary, 13362306a36Sopenharmony_ci struct sctp_transport *transport, 13462306a36Sopenharmony_ci int count_of_newacks) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci if (!primary->cacc.cycling_changeover) { 13762306a36Sopenharmony_ci if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks)) 13862306a36Sopenharmony_ci return 1; 13962306a36Sopenharmony_ci if (sctp_cacc_skip_3_1_f(transport, count_of_newacks)) 14062306a36Sopenharmony_ci return 1; 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * SFR-CACC algorithm: 14862306a36Sopenharmony_ci * 3.2) Else if CYCLING_CHANGEOVER is 1, and t is less 14962306a36Sopenharmony_ci * than next_tsn_at_change of the current primary, then 15062306a36Sopenharmony_ci * the sender MUST NOT increment missing report count 15162306a36Sopenharmony_ci * for t. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_cistatic inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci if (primary->cacc.cycling_changeover && 15662306a36Sopenharmony_ci TSN_lt(tsn, primary->cacc.next_tsn_at_change)) 15762306a36Sopenharmony_ci return 1; 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * SFR-CACC algorithm: 16362306a36Sopenharmony_ci * 3) If the missing report count for TSN t is to be 16462306a36Sopenharmony_ci * incremented according to [RFC2960] and 16562306a36Sopenharmony_ci * [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set, 16662306a36Sopenharmony_ci * then the sender MUST further execute steps 3.1 and 16762306a36Sopenharmony_ci * 3.2 to determine if the missing report count for 16862306a36Sopenharmony_ci * TSN t SHOULD NOT be incremented. 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * 3.3) If 3.1 and 3.2 do not dictate that the missing 17162306a36Sopenharmony_ci * report count for t should not be incremented, then 17262306a36Sopenharmony_ci * the sender SHOULD increment missing report count for 17362306a36Sopenharmony_ci * t (according to [RFC2960] and [SCTP_STEWART_2002]). 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_cistatic inline int sctp_cacc_skip(struct sctp_transport *primary, 17662306a36Sopenharmony_ci struct sctp_transport *transport, 17762306a36Sopenharmony_ci int count_of_newacks, 17862306a36Sopenharmony_ci __u32 tsn) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci if (primary->cacc.changeover_active && 18162306a36Sopenharmony_ci (sctp_cacc_skip_3_1(primary, transport, count_of_newacks) || 18262306a36Sopenharmony_ci sctp_cacc_skip_3_2(primary, tsn))) 18362306a36Sopenharmony_ci return 1; 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* Initialize an existing sctp_outq. This does the boring stuff. 18862306a36Sopenharmony_ci * You still need to define handlers if you really want to DO 18962306a36Sopenharmony_ci * something with this structure... 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_civoid sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci memset(q, 0, sizeof(struct sctp_outq)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci q->asoc = asoc; 19662306a36Sopenharmony_ci INIT_LIST_HEAD(&q->out_chunk_list); 19762306a36Sopenharmony_ci INIT_LIST_HEAD(&q->control_chunk_list); 19862306a36Sopenharmony_ci INIT_LIST_HEAD(&q->retransmit); 19962306a36Sopenharmony_ci INIT_LIST_HEAD(&q->sacked); 20062306a36Sopenharmony_ci INIT_LIST_HEAD(&q->abandoned); 20162306a36Sopenharmony_ci sctp_sched_set_sched(asoc, sctp_sk(asoc->base.sk)->default_ss); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* Free the outqueue structure and any related pending chunks. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistatic void __sctp_outq_teardown(struct sctp_outq *q) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct sctp_transport *transport; 20962306a36Sopenharmony_ci struct list_head *lchunk, *temp; 21062306a36Sopenharmony_ci struct sctp_chunk *chunk, *tmp; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Throw away unacknowledged chunks. */ 21362306a36Sopenharmony_ci list_for_each_entry(transport, &q->asoc->peer.transport_addr_list, 21462306a36Sopenharmony_ci transports) { 21562306a36Sopenharmony_ci while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) { 21662306a36Sopenharmony_ci chunk = list_entry(lchunk, struct sctp_chunk, 21762306a36Sopenharmony_ci transmitted_list); 21862306a36Sopenharmony_ci /* Mark as part of a failed message. */ 21962306a36Sopenharmony_ci sctp_chunk_fail(chunk, q->error); 22062306a36Sopenharmony_ci sctp_chunk_free(chunk); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Throw away chunks that have been gap ACKed. */ 22562306a36Sopenharmony_ci list_for_each_safe(lchunk, temp, &q->sacked) { 22662306a36Sopenharmony_ci list_del_init(lchunk); 22762306a36Sopenharmony_ci chunk = list_entry(lchunk, struct sctp_chunk, 22862306a36Sopenharmony_ci transmitted_list); 22962306a36Sopenharmony_ci sctp_chunk_fail(chunk, q->error); 23062306a36Sopenharmony_ci sctp_chunk_free(chunk); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Throw away any chunks in the retransmit queue. */ 23462306a36Sopenharmony_ci list_for_each_safe(lchunk, temp, &q->retransmit) { 23562306a36Sopenharmony_ci list_del_init(lchunk); 23662306a36Sopenharmony_ci chunk = list_entry(lchunk, struct sctp_chunk, 23762306a36Sopenharmony_ci transmitted_list); 23862306a36Sopenharmony_ci sctp_chunk_fail(chunk, q->error); 23962306a36Sopenharmony_ci sctp_chunk_free(chunk); 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* Throw away any chunks that are in the abandoned queue. */ 24362306a36Sopenharmony_ci list_for_each_safe(lchunk, temp, &q->abandoned) { 24462306a36Sopenharmony_ci list_del_init(lchunk); 24562306a36Sopenharmony_ci chunk = list_entry(lchunk, struct sctp_chunk, 24662306a36Sopenharmony_ci transmitted_list); 24762306a36Sopenharmony_ci sctp_chunk_fail(chunk, q->error); 24862306a36Sopenharmony_ci sctp_chunk_free(chunk); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Throw away any leftover data chunks. */ 25262306a36Sopenharmony_ci while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { 25362306a36Sopenharmony_ci sctp_sched_dequeue_done(q, chunk); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Mark as send failure. */ 25662306a36Sopenharmony_ci sctp_chunk_fail(chunk, q->error); 25762306a36Sopenharmony_ci sctp_chunk_free(chunk); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Throw away any leftover control chunks. */ 26162306a36Sopenharmony_ci list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { 26262306a36Sopenharmony_ci list_del_init(&chunk->list); 26362306a36Sopenharmony_ci sctp_chunk_free(chunk); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_civoid sctp_outq_teardown(struct sctp_outq *q) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci __sctp_outq_teardown(q); 27062306a36Sopenharmony_ci sctp_outq_init(q->asoc, q); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* Free the outqueue structure and any related pending chunks. */ 27462306a36Sopenharmony_civoid sctp_outq_free(struct sctp_outq *q) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci /* Throw away leftover chunks. */ 27762306a36Sopenharmony_ci __sctp_outq_teardown(q); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* Put a new chunk in an sctp_outq. */ 28162306a36Sopenharmony_civoid sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk, gfp_t gfp) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct net *net = q->asoc->base.net; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci pr_debug("%s: outq:%p, chunk:%p[%s]\n", __func__, q, chunk, 28662306a36Sopenharmony_ci chunk && chunk->chunk_hdr ? 28762306a36Sopenharmony_ci sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) : 28862306a36Sopenharmony_ci "illegal chunk"); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* If it is data, queue it up, otherwise, send it 29162306a36Sopenharmony_ci * immediately. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci if (sctp_chunk_is_data(chunk)) { 29462306a36Sopenharmony_ci pr_debug("%s: outqueueing: outq:%p, chunk:%p[%s])\n", 29562306a36Sopenharmony_ci __func__, q, chunk, chunk && chunk->chunk_hdr ? 29662306a36Sopenharmony_ci sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) : 29762306a36Sopenharmony_ci "illegal chunk"); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci sctp_outq_tail_data(q, chunk); 30062306a36Sopenharmony_ci if (chunk->asoc->peer.prsctp_capable && 30162306a36Sopenharmony_ci SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags)) 30262306a36Sopenharmony_ci chunk->asoc->sent_cnt_removable++; 30362306a36Sopenharmony_ci if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) 30462306a36Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS); 30562306a36Sopenharmony_ci else 30662306a36Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_OUTORDERCHUNKS); 30762306a36Sopenharmony_ci } else { 30862306a36Sopenharmony_ci list_add_tail(&chunk->list, &q->control_chunk_list); 30962306a36Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (!q->cork) 31362306a36Sopenharmony_ci sctp_outq_flush(q, 0, gfp); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* Insert a chunk into the sorted list based on the TSNs. The retransmit list 31762306a36Sopenharmony_ci * and the abandoned list are in ascending order. 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_cistatic void sctp_insert_list(struct list_head *head, struct list_head *new) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct list_head *pos; 32262306a36Sopenharmony_ci struct sctp_chunk *nchunk, *lchunk; 32362306a36Sopenharmony_ci __u32 ntsn, ltsn; 32462306a36Sopenharmony_ci int done = 0; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci nchunk = list_entry(new, struct sctp_chunk, transmitted_list); 32762306a36Sopenharmony_ci ntsn = ntohl(nchunk->subh.data_hdr->tsn); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci list_for_each(pos, head) { 33062306a36Sopenharmony_ci lchunk = list_entry(pos, struct sctp_chunk, transmitted_list); 33162306a36Sopenharmony_ci ltsn = ntohl(lchunk->subh.data_hdr->tsn); 33262306a36Sopenharmony_ci if (TSN_lt(ntsn, ltsn)) { 33362306a36Sopenharmony_ci list_add(new, pos->prev); 33462306a36Sopenharmony_ci done = 1; 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci if (!done) 33962306a36Sopenharmony_ci list_add_tail(new, head); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int sctp_prsctp_prune_sent(struct sctp_association *asoc, 34362306a36Sopenharmony_ci struct sctp_sndrcvinfo *sinfo, 34462306a36Sopenharmony_ci struct list_head *queue, int msg_len) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct sctp_chunk *chk, *temp; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci list_for_each_entry_safe(chk, temp, queue, transmitted_list) { 34962306a36Sopenharmony_ci struct sctp_stream_out *streamout; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (!chk->msg->abandoned && 35262306a36Sopenharmony_ci (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || 35362306a36Sopenharmony_ci chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive)) 35462306a36Sopenharmony_ci continue; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci chk->msg->abandoned = 1; 35762306a36Sopenharmony_ci list_del_init(&chk->transmitted_list); 35862306a36Sopenharmony_ci sctp_insert_list(&asoc->outqueue.abandoned, 35962306a36Sopenharmony_ci &chk->transmitted_list); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci streamout = SCTP_SO(&asoc->stream, chk->sinfo.sinfo_stream); 36262306a36Sopenharmony_ci asoc->sent_cnt_removable--; 36362306a36Sopenharmony_ci asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; 36462306a36Sopenharmony_ci streamout->ext->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (queue != &asoc->outqueue.retransmit && 36762306a36Sopenharmony_ci !chk->tsn_gap_acked) { 36862306a36Sopenharmony_ci if (chk->transport) 36962306a36Sopenharmony_ci chk->transport->flight_size -= 37062306a36Sopenharmony_ci sctp_data_size(chk); 37162306a36Sopenharmony_ci asoc->outqueue.outstanding_bytes -= sctp_data_size(chk); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci msg_len -= chk->skb->truesize + sizeof(struct sctp_chunk); 37562306a36Sopenharmony_ci if (msg_len <= 0) 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return msg_len; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int sctp_prsctp_prune_unsent(struct sctp_association *asoc, 38362306a36Sopenharmony_ci struct sctp_sndrcvinfo *sinfo, int msg_len) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct sctp_outq *q = &asoc->outqueue; 38662306a36Sopenharmony_ci struct sctp_chunk *chk, *temp; 38762306a36Sopenharmony_ci struct sctp_stream_out *sout; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci q->sched->unsched_all(&asoc->stream); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci list_for_each_entry_safe(chk, temp, &q->out_chunk_list, list) { 39262306a36Sopenharmony_ci if (!chk->msg->abandoned && 39362306a36Sopenharmony_ci (!(chk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG) || 39462306a36Sopenharmony_ci !SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || 39562306a36Sopenharmony_ci chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive)) 39662306a36Sopenharmony_ci continue; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci chk->msg->abandoned = 1; 39962306a36Sopenharmony_ci sctp_sched_dequeue_common(q, chk); 40062306a36Sopenharmony_ci asoc->sent_cnt_removable--; 40162306a36Sopenharmony_ci asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci sout = SCTP_SO(&asoc->stream, chk->sinfo.sinfo_stream); 40462306a36Sopenharmony_ci sout->ext->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* clear out_curr if all frag chunks are pruned */ 40762306a36Sopenharmony_ci if (asoc->stream.out_curr == sout && 40862306a36Sopenharmony_ci list_is_last(&chk->frag_list, &chk->msg->chunks)) 40962306a36Sopenharmony_ci asoc->stream.out_curr = NULL; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci msg_len -= chk->skb->truesize + sizeof(struct sctp_chunk); 41262306a36Sopenharmony_ci sctp_chunk_free(chk); 41362306a36Sopenharmony_ci if (msg_len <= 0) 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci q->sched->sched_all(&asoc->stream); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return msg_len; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/* Abandon the chunks according their priorities */ 42362306a36Sopenharmony_civoid sctp_prsctp_prune(struct sctp_association *asoc, 42462306a36Sopenharmony_ci struct sctp_sndrcvinfo *sinfo, int msg_len) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct sctp_transport *transport; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (!asoc->peer.prsctp_capable || !asoc->sent_cnt_removable) 42962306a36Sopenharmony_ci return; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci msg_len = sctp_prsctp_prune_sent(asoc, sinfo, 43262306a36Sopenharmony_ci &asoc->outqueue.retransmit, 43362306a36Sopenharmony_ci msg_len); 43462306a36Sopenharmony_ci if (msg_len <= 0) 43562306a36Sopenharmony_ci return; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci list_for_each_entry(transport, &asoc->peer.transport_addr_list, 43862306a36Sopenharmony_ci transports) { 43962306a36Sopenharmony_ci msg_len = sctp_prsctp_prune_sent(asoc, sinfo, 44062306a36Sopenharmony_ci &transport->transmitted, 44162306a36Sopenharmony_ci msg_len); 44262306a36Sopenharmony_ci if (msg_len <= 0) 44362306a36Sopenharmony_ci return; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci sctp_prsctp_prune_unsent(asoc, sinfo, msg_len); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci/* Mark all the eligible packets on a transport for retransmission. */ 45062306a36Sopenharmony_civoid sctp_retransmit_mark(struct sctp_outq *q, 45162306a36Sopenharmony_ci struct sctp_transport *transport, 45262306a36Sopenharmony_ci __u8 reason) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct list_head *lchunk, *ltemp; 45562306a36Sopenharmony_ci struct sctp_chunk *chunk; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* Walk through the specified transmitted queue. */ 45862306a36Sopenharmony_ci list_for_each_safe(lchunk, ltemp, &transport->transmitted) { 45962306a36Sopenharmony_ci chunk = list_entry(lchunk, struct sctp_chunk, 46062306a36Sopenharmony_ci transmitted_list); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* If the chunk is abandoned, move it to abandoned list. */ 46362306a36Sopenharmony_ci if (sctp_chunk_abandoned(chunk)) { 46462306a36Sopenharmony_ci list_del_init(lchunk); 46562306a36Sopenharmony_ci sctp_insert_list(&q->abandoned, lchunk); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* If this chunk has not been previousely acked, 46862306a36Sopenharmony_ci * stop considering it 'outstanding'. Our peer 46962306a36Sopenharmony_ci * will most likely never see it since it will 47062306a36Sopenharmony_ci * not be retransmitted 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci if (!chunk->tsn_gap_acked) { 47362306a36Sopenharmony_ci if (chunk->transport) 47462306a36Sopenharmony_ci chunk->transport->flight_size -= 47562306a36Sopenharmony_ci sctp_data_size(chunk); 47662306a36Sopenharmony_ci q->outstanding_bytes -= sctp_data_size(chunk); 47762306a36Sopenharmony_ci q->asoc->peer.rwnd += sctp_data_size(chunk); 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci continue; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* If we are doing retransmission due to a timeout or pmtu 48362306a36Sopenharmony_ci * discovery, only the chunks that are not yet acked should 48462306a36Sopenharmony_ci * be added to the retransmit queue. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci if ((reason == SCTP_RTXR_FAST_RTX && 48762306a36Sopenharmony_ci (chunk->fast_retransmit == SCTP_NEED_FRTX)) || 48862306a36Sopenharmony_ci (reason != SCTP_RTXR_FAST_RTX && !chunk->tsn_gap_acked)) { 48962306a36Sopenharmony_ci /* RFC 2960 6.2.1 Processing a Received SACK 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * C) Any time a DATA chunk is marked for 49262306a36Sopenharmony_ci * retransmission (via either T3-rtx timer expiration 49362306a36Sopenharmony_ci * (Section 6.3.3) or via fast retransmit 49462306a36Sopenharmony_ci * (Section 7.2.4)), add the data size of those 49562306a36Sopenharmony_ci * chunks to the rwnd. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ci q->asoc->peer.rwnd += sctp_data_size(chunk); 49862306a36Sopenharmony_ci q->outstanding_bytes -= sctp_data_size(chunk); 49962306a36Sopenharmony_ci if (chunk->transport) 50062306a36Sopenharmony_ci transport->flight_size -= sctp_data_size(chunk); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* sctpimpguide-05 Section 2.8.2 50362306a36Sopenharmony_ci * M5) If a T3-rtx timer expires, the 50462306a36Sopenharmony_ci * 'TSN.Missing.Report' of all affected TSNs is set 50562306a36Sopenharmony_ci * to 0. 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ci chunk->tsn_missing_report = 0; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* If a chunk that is being used for RTT measurement 51062306a36Sopenharmony_ci * has to be retransmitted, we cannot use this chunk 51162306a36Sopenharmony_ci * anymore for RTT measurements. Reset rto_pending so 51262306a36Sopenharmony_ci * that a new RTT measurement is started when a new 51362306a36Sopenharmony_ci * data chunk is sent. 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ci if (chunk->rtt_in_progress) { 51662306a36Sopenharmony_ci chunk->rtt_in_progress = 0; 51762306a36Sopenharmony_ci transport->rto_pending = 0; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Move the chunk to the retransmit queue. The chunks 52162306a36Sopenharmony_ci * on the retransmit queue are always kept in order. 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ci list_del_init(lchunk); 52462306a36Sopenharmony_ci sctp_insert_list(&q->retransmit, lchunk); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci pr_debug("%s: transport:%p, reason:%d, cwnd:%d, ssthresh:%d, " 52962306a36Sopenharmony_ci "flight_size:%d, pba:%d\n", __func__, transport, reason, 53062306a36Sopenharmony_ci transport->cwnd, transport->ssthresh, transport->flight_size, 53162306a36Sopenharmony_ci transport->partial_bytes_acked); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/* Mark all the eligible packets on a transport for retransmission and force 53562306a36Sopenharmony_ci * one packet out. 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_civoid sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, 53862306a36Sopenharmony_ci enum sctp_retransmit_reason reason) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct net *net = q->asoc->base.net; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci switch (reason) { 54362306a36Sopenharmony_ci case SCTP_RTXR_T3_RTX: 54462306a36Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_T3_RETRANSMITS); 54562306a36Sopenharmony_ci sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX); 54662306a36Sopenharmony_ci /* Update the retran path if the T3-rtx timer has expired for 54762306a36Sopenharmony_ci * the current retran path. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_ci if (transport == transport->asoc->peer.retran_path) 55062306a36Sopenharmony_ci sctp_assoc_update_retran_path(transport->asoc); 55162306a36Sopenharmony_ci transport->asoc->rtx_data_chunks += 55262306a36Sopenharmony_ci transport->asoc->unack_data; 55362306a36Sopenharmony_ci if (transport->pl.state == SCTP_PL_COMPLETE && 55462306a36Sopenharmony_ci transport->asoc->unack_data) 55562306a36Sopenharmony_ci sctp_transport_reset_probe_timer(transport); 55662306a36Sopenharmony_ci break; 55762306a36Sopenharmony_ci case SCTP_RTXR_FAST_RTX: 55862306a36Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_FAST_RETRANSMITS); 55962306a36Sopenharmony_ci sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); 56062306a36Sopenharmony_ci q->fast_rtx = 1; 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci case SCTP_RTXR_PMTUD: 56362306a36Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_PMTUD_RETRANSMITS); 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci case SCTP_RTXR_T1_RTX: 56662306a36Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_T1_RETRANSMITS); 56762306a36Sopenharmony_ci transport->asoc->init_retries++; 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci default: 57062306a36Sopenharmony_ci BUG(); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci sctp_retransmit_mark(q, transport, reason); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* PR-SCTP A5) Any time the T3-rtx timer expires, on any destination, 57662306a36Sopenharmony_ci * the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by 57762306a36Sopenharmony_ci * following the procedures outlined in C1 - C5. 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ci if (reason == SCTP_RTXR_T3_RTX) 58062306a36Sopenharmony_ci q->asoc->stream.si->generate_ftsn(q, q->asoc->ctsn_ack_point); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* Flush the queues only on timeout, since fast_rtx is only 58362306a36Sopenharmony_ci * triggered during sack processing and the queue 58462306a36Sopenharmony_ci * will be flushed at the end. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ci if (reason != SCTP_RTXR_FAST_RTX) 58762306a36Sopenharmony_ci sctp_outq_flush(q, /* rtx_timeout */ 1, GFP_ATOMIC); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci/* 59162306a36Sopenharmony_ci * Transmit DATA chunks on the retransmit queue. Upon return from 59262306a36Sopenharmony_ci * __sctp_outq_flush_rtx() the packet 'pkt' may contain chunks which 59362306a36Sopenharmony_ci * need to be transmitted by the caller. 59462306a36Sopenharmony_ci * We assume that pkt->transport has already been set. 59562306a36Sopenharmony_ci * 59662306a36Sopenharmony_ci * The return value is a normal kernel error return value. 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_cistatic int __sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, 59962306a36Sopenharmony_ci int rtx_timeout, int *start_timer, gfp_t gfp) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct sctp_transport *transport = pkt->transport; 60262306a36Sopenharmony_ci struct sctp_chunk *chunk, *chunk1; 60362306a36Sopenharmony_ci struct list_head *lqueue; 60462306a36Sopenharmony_ci enum sctp_xmit status; 60562306a36Sopenharmony_ci int error = 0; 60662306a36Sopenharmony_ci int timer = 0; 60762306a36Sopenharmony_ci int done = 0; 60862306a36Sopenharmony_ci int fast_rtx; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci lqueue = &q->retransmit; 61162306a36Sopenharmony_ci fast_rtx = q->fast_rtx; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* This loop handles time-out retransmissions, fast retransmissions, 61462306a36Sopenharmony_ci * and retransmissions due to opening of whindow. 61562306a36Sopenharmony_ci * 61662306a36Sopenharmony_ci * RFC 2960 6.3.3 Handle T3-rtx Expiration 61762306a36Sopenharmony_ci * 61862306a36Sopenharmony_ci * E3) Determine how many of the earliest (i.e., lowest TSN) 61962306a36Sopenharmony_ci * outstanding DATA chunks for the address for which the 62062306a36Sopenharmony_ci * T3-rtx has expired will fit into a single packet, subject 62162306a36Sopenharmony_ci * to the MTU constraint for the path corresponding to the 62262306a36Sopenharmony_ci * destination transport address to which the retransmission 62362306a36Sopenharmony_ci * is being sent (this may be different from the address for 62462306a36Sopenharmony_ci * which the timer expires [see Section 6.4]). Call this value 62562306a36Sopenharmony_ci * K. Bundle and retransmit those K DATA chunks in a single 62662306a36Sopenharmony_ci * packet to the destination endpoint. 62762306a36Sopenharmony_ci * 62862306a36Sopenharmony_ci * [Just to be painfully clear, if we are retransmitting 62962306a36Sopenharmony_ci * because a timeout just happened, we should send only ONE 63062306a36Sopenharmony_ci * packet of retransmitted data.] 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci * For fast retransmissions we also send only ONE packet. However, 63362306a36Sopenharmony_ci * if we are just flushing the queue due to open window, we'll 63462306a36Sopenharmony_ci * try to send as much as possible. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci list_for_each_entry_safe(chunk, chunk1, lqueue, transmitted_list) { 63762306a36Sopenharmony_ci /* If the chunk is abandoned, move it to abandoned list. */ 63862306a36Sopenharmony_ci if (sctp_chunk_abandoned(chunk)) { 63962306a36Sopenharmony_ci list_del_init(&chunk->transmitted_list); 64062306a36Sopenharmony_ci sctp_insert_list(&q->abandoned, 64162306a36Sopenharmony_ci &chunk->transmitted_list); 64262306a36Sopenharmony_ci continue; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* Make sure that Gap Acked TSNs are not retransmitted. A 64662306a36Sopenharmony_ci * simple approach is just to move such TSNs out of the 64762306a36Sopenharmony_ci * way and into a 'transmitted' queue and skip to the 64862306a36Sopenharmony_ci * next chunk. 64962306a36Sopenharmony_ci */ 65062306a36Sopenharmony_ci if (chunk->tsn_gap_acked) { 65162306a36Sopenharmony_ci list_move_tail(&chunk->transmitted_list, 65262306a36Sopenharmony_ci &transport->transmitted); 65362306a36Sopenharmony_ci continue; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* If we are doing fast retransmit, ignore non-fast_rtransmit 65762306a36Sopenharmony_ci * chunks 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_ci if (fast_rtx && !chunk->fast_retransmit) 66062306a36Sopenharmony_ci continue; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ciredo: 66362306a36Sopenharmony_ci /* Attempt to append this chunk to the packet. */ 66462306a36Sopenharmony_ci status = sctp_packet_append_chunk(pkt, chunk); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci switch (status) { 66762306a36Sopenharmony_ci case SCTP_XMIT_PMTU_FULL: 66862306a36Sopenharmony_ci if (!pkt->has_data && !pkt->has_cookie_echo) { 66962306a36Sopenharmony_ci /* If this packet did not contain DATA then 67062306a36Sopenharmony_ci * retransmission did not happen, so do it 67162306a36Sopenharmony_ci * again. We'll ignore the error here since 67262306a36Sopenharmony_ci * control chunks are already freed so there 67362306a36Sopenharmony_ci * is nothing we can do. 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_ci sctp_packet_transmit(pkt, gfp); 67662306a36Sopenharmony_ci goto redo; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* Send this packet. */ 68062306a36Sopenharmony_ci error = sctp_packet_transmit(pkt, gfp); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci /* If we are retransmitting, we should only 68362306a36Sopenharmony_ci * send a single packet. 68462306a36Sopenharmony_ci * Otherwise, try appending this chunk again. 68562306a36Sopenharmony_ci */ 68662306a36Sopenharmony_ci if (rtx_timeout || fast_rtx) 68762306a36Sopenharmony_ci done = 1; 68862306a36Sopenharmony_ci else 68962306a36Sopenharmony_ci goto redo; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* Bundle next chunk in the next round. */ 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci case SCTP_XMIT_RWND_FULL: 69562306a36Sopenharmony_ci /* Send this packet. */ 69662306a36Sopenharmony_ci error = sctp_packet_transmit(pkt, gfp); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* Stop sending DATA as there is no more room 69962306a36Sopenharmony_ci * at the receiver. 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_ci done = 1; 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci case SCTP_XMIT_DELAY: 70562306a36Sopenharmony_ci /* Send this packet. */ 70662306a36Sopenharmony_ci error = sctp_packet_transmit(pkt, gfp); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* Stop sending DATA because of nagle delay. */ 70962306a36Sopenharmony_ci done = 1; 71062306a36Sopenharmony_ci break; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci default: 71362306a36Sopenharmony_ci /* The append was successful, so add this chunk to 71462306a36Sopenharmony_ci * the transmitted list. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci list_move_tail(&chunk->transmitted_list, 71762306a36Sopenharmony_ci &transport->transmitted); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* Mark the chunk as ineligible for fast retransmit 72062306a36Sopenharmony_ci * after it is retransmitted. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ci if (chunk->fast_retransmit == SCTP_NEED_FRTX) 72362306a36Sopenharmony_ci chunk->fast_retransmit = SCTP_DONT_FRTX; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci q->asoc->stats.rtxchunks++; 72662306a36Sopenharmony_ci break; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* Set the timer if there were no errors */ 73062306a36Sopenharmony_ci if (!error && !timer) 73162306a36Sopenharmony_ci timer = 1; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (done) 73462306a36Sopenharmony_ci break; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* If we are here due to a retransmit timeout or a fast 73862306a36Sopenharmony_ci * retransmit and if there are any chunks left in the retransmit 73962306a36Sopenharmony_ci * queue that could not fit in the PMTU sized packet, they need 74062306a36Sopenharmony_ci * to be marked as ineligible for a subsequent fast retransmit. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci if (rtx_timeout || fast_rtx) { 74362306a36Sopenharmony_ci list_for_each_entry(chunk1, lqueue, transmitted_list) { 74462306a36Sopenharmony_ci if (chunk1->fast_retransmit == SCTP_NEED_FRTX) 74562306a36Sopenharmony_ci chunk1->fast_retransmit = SCTP_DONT_FRTX; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci *start_timer = timer; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Clear fast retransmit hint */ 75262306a36Sopenharmony_ci if (fast_rtx) 75362306a36Sopenharmony_ci q->fast_rtx = 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci return error; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci/* Cork the outqueue so queued chunks are really queued. */ 75962306a36Sopenharmony_civoid sctp_outq_uncork(struct sctp_outq *q, gfp_t gfp) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci if (q->cork) 76262306a36Sopenharmony_ci q->cork = 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci sctp_outq_flush(q, 0, gfp); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int sctp_packet_singleton(struct sctp_transport *transport, 76862306a36Sopenharmony_ci struct sctp_chunk *chunk, gfp_t gfp) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci const struct sctp_association *asoc = transport->asoc; 77162306a36Sopenharmony_ci const __u16 sport = asoc->base.bind_addr.port; 77262306a36Sopenharmony_ci const __u16 dport = asoc->peer.port; 77362306a36Sopenharmony_ci const __u32 vtag = asoc->peer.i.init_tag; 77462306a36Sopenharmony_ci struct sctp_packet singleton; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci sctp_packet_init(&singleton, transport, sport, dport); 77762306a36Sopenharmony_ci sctp_packet_config(&singleton, vtag, 0); 77862306a36Sopenharmony_ci if (sctp_packet_append_chunk(&singleton, chunk) != SCTP_XMIT_OK) { 77962306a36Sopenharmony_ci list_del_init(&chunk->list); 78062306a36Sopenharmony_ci sctp_chunk_free(chunk); 78162306a36Sopenharmony_ci return -ENOMEM; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci return sctp_packet_transmit(&singleton, gfp); 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/* Struct to hold the context during sctp outq flush */ 78762306a36Sopenharmony_cistruct sctp_flush_ctx { 78862306a36Sopenharmony_ci struct sctp_outq *q; 78962306a36Sopenharmony_ci /* Current transport being used. It's NOT the same as curr active one */ 79062306a36Sopenharmony_ci struct sctp_transport *transport; 79162306a36Sopenharmony_ci /* These transports have chunks to send. */ 79262306a36Sopenharmony_ci struct list_head transport_list; 79362306a36Sopenharmony_ci struct sctp_association *asoc; 79462306a36Sopenharmony_ci /* Packet on the current transport above */ 79562306a36Sopenharmony_ci struct sctp_packet *packet; 79662306a36Sopenharmony_ci gfp_t gfp; 79762306a36Sopenharmony_ci}; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci/* transport: current transport */ 80062306a36Sopenharmony_cistatic void sctp_outq_select_transport(struct sctp_flush_ctx *ctx, 80162306a36Sopenharmony_ci struct sctp_chunk *chunk) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci struct sctp_transport *new_transport = chunk->transport; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (!new_transport) { 80662306a36Sopenharmony_ci if (!sctp_chunk_is_data(chunk)) { 80762306a36Sopenharmony_ci /* If we have a prior transport pointer, see if 80862306a36Sopenharmony_ci * the destination address of the chunk 80962306a36Sopenharmony_ci * matches the destination address of the 81062306a36Sopenharmony_ci * current transport. If not a match, then 81162306a36Sopenharmony_ci * try to look up the transport with a given 81262306a36Sopenharmony_ci * destination address. We do this because 81362306a36Sopenharmony_ci * after processing ASCONFs, we may have new 81462306a36Sopenharmony_ci * transports created. 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_ci if (ctx->transport && sctp_cmp_addr_exact(&chunk->dest, 81762306a36Sopenharmony_ci &ctx->transport->ipaddr)) 81862306a36Sopenharmony_ci new_transport = ctx->transport; 81962306a36Sopenharmony_ci else 82062306a36Sopenharmony_ci new_transport = sctp_assoc_lookup_paddr(ctx->asoc, 82162306a36Sopenharmony_ci &chunk->dest); 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* if we still don't have a new transport, then 82562306a36Sopenharmony_ci * use the current active path. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci if (!new_transport) 82862306a36Sopenharmony_ci new_transport = ctx->asoc->peer.active_path; 82962306a36Sopenharmony_ci } else { 83062306a36Sopenharmony_ci __u8 type; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci switch (new_transport->state) { 83362306a36Sopenharmony_ci case SCTP_INACTIVE: 83462306a36Sopenharmony_ci case SCTP_UNCONFIRMED: 83562306a36Sopenharmony_ci case SCTP_PF: 83662306a36Sopenharmony_ci /* If the chunk is Heartbeat or Heartbeat Ack, 83762306a36Sopenharmony_ci * send it to chunk->transport, even if it's 83862306a36Sopenharmony_ci * inactive. 83962306a36Sopenharmony_ci * 84062306a36Sopenharmony_ci * 3.3.6 Heartbeat Acknowledgement: 84162306a36Sopenharmony_ci * ... 84262306a36Sopenharmony_ci * A HEARTBEAT ACK is always sent to the source IP 84362306a36Sopenharmony_ci * address of the IP datagram containing the 84462306a36Sopenharmony_ci * HEARTBEAT chunk to which this ack is responding. 84562306a36Sopenharmony_ci * ... 84662306a36Sopenharmony_ci * 84762306a36Sopenharmony_ci * ASCONF_ACKs also must be sent to the source. 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_ci type = chunk->chunk_hdr->type; 85062306a36Sopenharmony_ci if (type != SCTP_CID_HEARTBEAT && 85162306a36Sopenharmony_ci type != SCTP_CID_HEARTBEAT_ACK && 85262306a36Sopenharmony_ci type != SCTP_CID_ASCONF_ACK) 85362306a36Sopenharmony_ci new_transport = ctx->asoc->peer.active_path; 85462306a36Sopenharmony_ci break; 85562306a36Sopenharmony_ci default: 85662306a36Sopenharmony_ci break; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* Are we switching transports? Take care of transport locks. */ 86162306a36Sopenharmony_ci if (new_transport != ctx->transport) { 86262306a36Sopenharmony_ci ctx->transport = new_transport; 86362306a36Sopenharmony_ci ctx->packet = &ctx->transport->packet; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (list_empty(&ctx->transport->send_ready)) 86662306a36Sopenharmony_ci list_add_tail(&ctx->transport->send_ready, 86762306a36Sopenharmony_ci &ctx->transport_list); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci sctp_packet_config(ctx->packet, 87062306a36Sopenharmony_ci ctx->asoc->peer.i.init_tag, 87162306a36Sopenharmony_ci ctx->asoc->peer.ecn_capable); 87262306a36Sopenharmony_ci /* We've switched transports, so apply the 87362306a36Sopenharmony_ci * Burst limit to the new transport. 87462306a36Sopenharmony_ci */ 87562306a36Sopenharmony_ci sctp_transport_burst_limited(ctx->transport); 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct sctp_chunk *chunk, *tmp; 88262306a36Sopenharmony_ci enum sctp_xmit status; 88362306a36Sopenharmony_ci int one_packet, error; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci list_for_each_entry_safe(chunk, tmp, &ctx->q->control_chunk_list, list) { 88662306a36Sopenharmony_ci one_packet = 0; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* RFC 5061, 5.3 88962306a36Sopenharmony_ci * F1) This means that until such time as the ASCONF 89062306a36Sopenharmony_ci * containing the add is acknowledged, the sender MUST 89162306a36Sopenharmony_ci * NOT use the new IP address as a source for ANY SCTP 89262306a36Sopenharmony_ci * packet except on carrying an ASCONF Chunk. 89362306a36Sopenharmony_ci */ 89462306a36Sopenharmony_ci if (ctx->asoc->src_out_of_asoc_ok && 89562306a36Sopenharmony_ci chunk->chunk_hdr->type != SCTP_CID_ASCONF) 89662306a36Sopenharmony_ci continue; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci list_del_init(&chunk->list); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci /* Pick the right transport to use. Should always be true for 90162306a36Sopenharmony_ci * the first chunk as we don't have a transport by then. 90262306a36Sopenharmony_ci */ 90362306a36Sopenharmony_ci sctp_outq_select_transport(ctx, chunk); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci switch (chunk->chunk_hdr->type) { 90662306a36Sopenharmony_ci /* 6.10 Bundling 90762306a36Sopenharmony_ci * ... 90862306a36Sopenharmony_ci * An endpoint MUST NOT bundle INIT, INIT ACK or SHUTDOWN 90962306a36Sopenharmony_ci * COMPLETE with any other chunks. [Send them immediately.] 91062306a36Sopenharmony_ci */ 91162306a36Sopenharmony_ci case SCTP_CID_INIT: 91262306a36Sopenharmony_ci case SCTP_CID_INIT_ACK: 91362306a36Sopenharmony_ci case SCTP_CID_SHUTDOWN_COMPLETE: 91462306a36Sopenharmony_ci error = sctp_packet_singleton(ctx->transport, chunk, 91562306a36Sopenharmony_ci ctx->gfp); 91662306a36Sopenharmony_ci if (error < 0) { 91762306a36Sopenharmony_ci ctx->asoc->base.sk->sk_err = -error; 91862306a36Sopenharmony_ci return; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci ctx->asoc->stats.octrlchunks++; 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci case SCTP_CID_ABORT: 92462306a36Sopenharmony_ci if (sctp_test_T_bit(chunk)) 92562306a36Sopenharmony_ci ctx->packet->vtag = ctx->asoc->c.my_vtag; 92662306a36Sopenharmony_ci fallthrough; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* The following chunks are "response" chunks, i.e. 92962306a36Sopenharmony_ci * they are generated in response to something we 93062306a36Sopenharmony_ci * received. If we are sending these, then we can 93162306a36Sopenharmony_ci * send only 1 packet containing these chunks. 93262306a36Sopenharmony_ci */ 93362306a36Sopenharmony_ci case SCTP_CID_HEARTBEAT_ACK: 93462306a36Sopenharmony_ci case SCTP_CID_SHUTDOWN_ACK: 93562306a36Sopenharmony_ci case SCTP_CID_COOKIE_ACK: 93662306a36Sopenharmony_ci case SCTP_CID_COOKIE_ECHO: 93762306a36Sopenharmony_ci case SCTP_CID_ERROR: 93862306a36Sopenharmony_ci case SCTP_CID_ECN_CWR: 93962306a36Sopenharmony_ci case SCTP_CID_ASCONF_ACK: 94062306a36Sopenharmony_ci one_packet = 1; 94162306a36Sopenharmony_ci fallthrough; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci case SCTP_CID_HEARTBEAT: 94462306a36Sopenharmony_ci if (chunk->pmtu_probe) { 94562306a36Sopenharmony_ci error = sctp_packet_singleton(ctx->transport, 94662306a36Sopenharmony_ci chunk, ctx->gfp); 94762306a36Sopenharmony_ci if (!error) 94862306a36Sopenharmony_ci ctx->asoc->stats.octrlchunks++; 94962306a36Sopenharmony_ci break; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci fallthrough; 95262306a36Sopenharmony_ci case SCTP_CID_SACK: 95362306a36Sopenharmony_ci case SCTP_CID_SHUTDOWN: 95462306a36Sopenharmony_ci case SCTP_CID_ECN_ECNE: 95562306a36Sopenharmony_ci case SCTP_CID_ASCONF: 95662306a36Sopenharmony_ci case SCTP_CID_FWD_TSN: 95762306a36Sopenharmony_ci case SCTP_CID_I_FWD_TSN: 95862306a36Sopenharmony_ci case SCTP_CID_RECONF: 95962306a36Sopenharmony_ci status = sctp_packet_transmit_chunk(ctx->packet, chunk, 96062306a36Sopenharmony_ci one_packet, ctx->gfp); 96162306a36Sopenharmony_ci if (status != SCTP_XMIT_OK) { 96262306a36Sopenharmony_ci /* put the chunk back */ 96362306a36Sopenharmony_ci list_add(&chunk->list, &ctx->q->control_chunk_list); 96462306a36Sopenharmony_ci break; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci ctx->asoc->stats.octrlchunks++; 96862306a36Sopenharmony_ci /* PR-SCTP C5) If a FORWARD TSN is sent, the 96962306a36Sopenharmony_ci * sender MUST assure that at least one T3-rtx 97062306a36Sopenharmony_ci * timer is running. 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_ci if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN || 97362306a36Sopenharmony_ci chunk->chunk_hdr->type == SCTP_CID_I_FWD_TSN) { 97462306a36Sopenharmony_ci sctp_transport_reset_t3_rtx(ctx->transport); 97562306a36Sopenharmony_ci ctx->transport->last_time_sent = jiffies; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (chunk == ctx->asoc->strreset_chunk) 97962306a36Sopenharmony_ci sctp_transport_reset_reconf_timer(ctx->transport); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci default: 98462306a36Sopenharmony_ci /* We built a chunk with an illegal type! */ 98562306a36Sopenharmony_ci BUG(); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/* Returns false if new data shouldn't be sent */ 99162306a36Sopenharmony_cistatic bool sctp_outq_flush_rtx(struct sctp_flush_ctx *ctx, 99262306a36Sopenharmony_ci int rtx_timeout) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci int error, start_timer = 0; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (ctx->asoc->peer.retran_path->state == SCTP_UNCONFIRMED) 99762306a36Sopenharmony_ci return false; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (ctx->transport != ctx->asoc->peer.retran_path) { 100062306a36Sopenharmony_ci /* Switch transports & prepare the packet. */ 100162306a36Sopenharmony_ci ctx->transport = ctx->asoc->peer.retran_path; 100262306a36Sopenharmony_ci ctx->packet = &ctx->transport->packet; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (list_empty(&ctx->transport->send_ready)) 100562306a36Sopenharmony_ci list_add_tail(&ctx->transport->send_ready, 100662306a36Sopenharmony_ci &ctx->transport_list); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci sctp_packet_config(ctx->packet, ctx->asoc->peer.i.init_tag, 100962306a36Sopenharmony_ci ctx->asoc->peer.ecn_capable); 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci error = __sctp_outq_flush_rtx(ctx->q, ctx->packet, rtx_timeout, 101362306a36Sopenharmony_ci &start_timer, ctx->gfp); 101462306a36Sopenharmony_ci if (error < 0) 101562306a36Sopenharmony_ci ctx->asoc->base.sk->sk_err = -error; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (start_timer) { 101862306a36Sopenharmony_ci sctp_transport_reset_t3_rtx(ctx->transport); 101962306a36Sopenharmony_ci ctx->transport->last_time_sent = jiffies; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* This can happen on COOKIE-ECHO resend. Only 102362306a36Sopenharmony_ci * one chunk can get bundled with a COOKIE-ECHO. 102462306a36Sopenharmony_ci */ 102562306a36Sopenharmony_ci if (ctx->packet->has_cookie_echo) 102662306a36Sopenharmony_ci return false; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci /* Don't send new data if there is still data 102962306a36Sopenharmony_ci * waiting to retransmit. 103062306a36Sopenharmony_ci */ 103162306a36Sopenharmony_ci if (!list_empty(&ctx->q->retransmit)) 103262306a36Sopenharmony_ci return false; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci return true; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic void sctp_outq_flush_data(struct sctp_flush_ctx *ctx, 103862306a36Sopenharmony_ci int rtx_timeout) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci struct sctp_chunk *chunk; 104162306a36Sopenharmony_ci enum sctp_xmit status; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* Is it OK to send data chunks? */ 104462306a36Sopenharmony_ci switch (ctx->asoc->state) { 104562306a36Sopenharmony_ci case SCTP_STATE_COOKIE_ECHOED: 104662306a36Sopenharmony_ci /* Only allow bundling when this packet has a COOKIE-ECHO 104762306a36Sopenharmony_ci * chunk. 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_ci if (!ctx->packet || !ctx->packet->has_cookie_echo) 105062306a36Sopenharmony_ci return; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci fallthrough; 105362306a36Sopenharmony_ci case SCTP_STATE_ESTABLISHED: 105462306a36Sopenharmony_ci case SCTP_STATE_SHUTDOWN_PENDING: 105562306a36Sopenharmony_ci case SCTP_STATE_SHUTDOWN_RECEIVED: 105662306a36Sopenharmony_ci break; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci default: 105962306a36Sopenharmony_ci /* Do nothing. */ 106062306a36Sopenharmony_ci return; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* RFC 2960 6.1 Transmission of DATA Chunks 106462306a36Sopenharmony_ci * 106562306a36Sopenharmony_ci * C) When the time comes for the sender to transmit, 106662306a36Sopenharmony_ci * before sending new DATA chunks, the sender MUST 106762306a36Sopenharmony_ci * first transmit any outstanding DATA chunks which 106862306a36Sopenharmony_ci * are marked for retransmission (limited by the 106962306a36Sopenharmony_ci * current cwnd). 107062306a36Sopenharmony_ci */ 107162306a36Sopenharmony_ci if (!list_empty(&ctx->q->retransmit) && 107262306a36Sopenharmony_ci !sctp_outq_flush_rtx(ctx, rtx_timeout)) 107362306a36Sopenharmony_ci return; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* Apply Max.Burst limitation to the current transport in 107662306a36Sopenharmony_ci * case it will be used for new data. We are going to 107762306a36Sopenharmony_ci * rest it before we return, but we want to apply the limit 107862306a36Sopenharmony_ci * to the currently queued data. 107962306a36Sopenharmony_ci */ 108062306a36Sopenharmony_ci if (ctx->transport) 108162306a36Sopenharmony_ci sctp_transport_burst_limited(ctx->transport); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* Finally, transmit new packets. */ 108462306a36Sopenharmony_ci while ((chunk = sctp_outq_dequeue_data(ctx->q)) != NULL) { 108562306a36Sopenharmony_ci __u32 sid = ntohs(chunk->subh.data_hdr->stream); 108662306a36Sopenharmony_ci __u8 stream_state = SCTP_SO(&ctx->asoc->stream, sid)->state; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* Has this chunk expired? */ 108962306a36Sopenharmony_ci if (sctp_chunk_abandoned(chunk)) { 109062306a36Sopenharmony_ci sctp_sched_dequeue_done(ctx->q, chunk); 109162306a36Sopenharmony_ci sctp_chunk_fail(chunk, 0); 109262306a36Sopenharmony_ci sctp_chunk_free(chunk); 109362306a36Sopenharmony_ci continue; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (stream_state == SCTP_STREAM_CLOSED) { 109762306a36Sopenharmony_ci sctp_outq_head_data(ctx->q, chunk); 109862306a36Sopenharmony_ci break; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci sctp_outq_select_transport(ctx, chunk); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p skb->users:%d\n", 110462306a36Sopenharmony_ci __func__, ctx->q, chunk, chunk && chunk->chunk_hdr ? 110562306a36Sopenharmony_ci sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) : 110662306a36Sopenharmony_ci "illegal chunk", ntohl(chunk->subh.data_hdr->tsn), 110762306a36Sopenharmony_ci chunk->skb ? chunk->skb->head : NULL, chunk->skb ? 110862306a36Sopenharmony_ci refcount_read(&chunk->skb->users) : -1); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* Add the chunk to the packet. */ 111162306a36Sopenharmony_ci status = sctp_packet_transmit_chunk(ctx->packet, chunk, 0, 111262306a36Sopenharmony_ci ctx->gfp); 111362306a36Sopenharmony_ci if (status != SCTP_XMIT_OK) { 111462306a36Sopenharmony_ci /* We could not append this chunk, so put 111562306a36Sopenharmony_ci * the chunk back on the output queue. 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ci pr_debug("%s: could not transmit tsn:0x%x, status:%d\n", 111862306a36Sopenharmony_ci __func__, ntohl(chunk->subh.data_hdr->tsn), 111962306a36Sopenharmony_ci status); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci sctp_outq_head_data(ctx->q, chunk); 112262306a36Sopenharmony_ci break; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* The sender is in the SHUTDOWN-PENDING state, 112662306a36Sopenharmony_ci * The sender MAY set the I-bit in the DATA 112762306a36Sopenharmony_ci * chunk header. 112862306a36Sopenharmony_ci */ 112962306a36Sopenharmony_ci if (ctx->asoc->state == SCTP_STATE_SHUTDOWN_PENDING) 113062306a36Sopenharmony_ci chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM; 113162306a36Sopenharmony_ci if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) 113262306a36Sopenharmony_ci ctx->asoc->stats.ouodchunks++; 113362306a36Sopenharmony_ci else 113462306a36Sopenharmony_ci ctx->asoc->stats.oodchunks++; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* Only now it's safe to consider this 113762306a36Sopenharmony_ci * chunk as sent, sched-wise. 113862306a36Sopenharmony_ci */ 113962306a36Sopenharmony_ci sctp_sched_dequeue_done(ctx->q, chunk); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci list_add_tail(&chunk->transmitted_list, 114262306a36Sopenharmony_ci &ctx->transport->transmitted); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci sctp_transport_reset_t3_rtx(ctx->transport); 114562306a36Sopenharmony_ci ctx->transport->last_time_sent = jiffies; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci /* Only let one DATA chunk get bundled with a 114862306a36Sopenharmony_ci * COOKIE-ECHO chunk. 114962306a36Sopenharmony_ci */ 115062306a36Sopenharmony_ci if (ctx->packet->has_cookie_echo) 115162306a36Sopenharmony_ci break; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic void sctp_outq_flush_transports(struct sctp_flush_ctx *ctx) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci struct sock *sk = ctx->asoc->base.sk; 115862306a36Sopenharmony_ci struct list_head *ltransport; 115962306a36Sopenharmony_ci struct sctp_packet *packet; 116062306a36Sopenharmony_ci struct sctp_transport *t; 116162306a36Sopenharmony_ci int error = 0; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci while ((ltransport = sctp_list_dequeue(&ctx->transport_list)) != NULL) { 116462306a36Sopenharmony_ci t = list_entry(ltransport, struct sctp_transport, send_ready); 116562306a36Sopenharmony_ci packet = &t->packet; 116662306a36Sopenharmony_ci if (!sctp_packet_empty(packet)) { 116762306a36Sopenharmony_ci rcu_read_lock(); 116862306a36Sopenharmony_ci if (t->dst && __sk_dst_get(sk) != t->dst) { 116962306a36Sopenharmony_ci dst_hold(t->dst); 117062306a36Sopenharmony_ci sk_setup_caps(sk, t->dst); 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci rcu_read_unlock(); 117362306a36Sopenharmony_ci error = sctp_packet_transmit(packet, ctx->gfp); 117462306a36Sopenharmony_ci if (error < 0) 117562306a36Sopenharmony_ci ctx->q->asoc->base.sk->sk_err = -error; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci /* Clear the burst limited state, if any */ 117962306a36Sopenharmony_ci sctp_transport_burst_reset(t); 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci} 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci/* Try to flush an outqueue. 118462306a36Sopenharmony_ci * 118562306a36Sopenharmony_ci * Description: Send everything in q which we legally can, subject to 118662306a36Sopenharmony_ci * congestion limitations. 118762306a36Sopenharmony_ci * * Note: This function can be called from multiple contexts so appropriate 118862306a36Sopenharmony_ci * locking concerns must be made. Today we use the sock lock to protect 118962306a36Sopenharmony_ci * this function. 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct sctp_flush_ctx ctx = { 119562306a36Sopenharmony_ci .q = q, 119662306a36Sopenharmony_ci .transport = NULL, 119762306a36Sopenharmony_ci .transport_list = LIST_HEAD_INIT(ctx.transport_list), 119862306a36Sopenharmony_ci .asoc = q->asoc, 119962306a36Sopenharmony_ci .packet = NULL, 120062306a36Sopenharmony_ci .gfp = gfp, 120162306a36Sopenharmony_ci }; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* 6.10 Bundling 120462306a36Sopenharmony_ci * ... 120562306a36Sopenharmony_ci * When bundling control chunks with DATA chunks, an 120662306a36Sopenharmony_ci * endpoint MUST place control chunks first in the outbound 120762306a36Sopenharmony_ci * SCTP packet. The transmitter MUST transmit DATA chunks 120862306a36Sopenharmony_ci * within a SCTP packet in increasing order of TSN. 120962306a36Sopenharmony_ci * ... 121062306a36Sopenharmony_ci */ 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci sctp_outq_flush_ctrl(&ctx); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (q->asoc->src_out_of_asoc_ok) 121562306a36Sopenharmony_ci goto sctp_flush_out; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci sctp_outq_flush_data(&ctx, rtx_timeout); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cisctp_flush_out: 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci sctp_outq_flush_transports(&ctx); 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci/* Update unack_data based on the incoming SACK chunk */ 122562306a36Sopenharmony_cistatic void sctp_sack_update_unack_data(struct sctp_association *assoc, 122662306a36Sopenharmony_ci struct sctp_sackhdr *sack) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci union sctp_sack_variable *frags; 122962306a36Sopenharmony_ci __u16 unack_data; 123062306a36Sopenharmony_ci int i; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci unack_data = assoc->next_tsn - assoc->ctsn_ack_point - 1; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci frags = (union sctp_sack_variable *)(sack + 1); 123562306a36Sopenharmony_ci for (i = 0; i < ntohs(sack->num_gap_ack_blocks); i++) { 123662306a36Sopenharmony_ci unack_data -= ((ntohs(frags[i].gab.end) - 123762306a36Sopenharmony_ci ntohs(frags[i].gab.start) + 1)); 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci assoc->unack_data = unack_data; 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci/* This is where we REALLY process a SACK. 124462306a36Sopenharmony_ci * 124562306a36Sopenharmony_ci * Process the SACK against the outqueue. Mostly, this just frees 124662306a36Sopenharmony_ci * things off the transmitted queue. 124762306a36Sopenharmony_ci */ 124862306a36Sopenharmony_ciint sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci struct sctp_association *asoc = q->asoc; 125162306a36Sopenharmony_ci struct sctp_sackhdr *sack = chunk->subh.sack_hdr; 125262306a36Sopenharmony_ci struct sctp_transport *transport; 125362306a36Sopenharmony_ci struct sctp_chunk *tchunk = NULL; 125462306a36Sopenharmony_ci struct list_head *lchunk, *transport_list, *temp; 125562306a36Sopenharmony_ci __u32 sack_ctsn, ctsn, tsn; 125662306a36Sopenharmony_ci __u32 highest_tsn, highest_new_tsn; 125762306a36Sopenharmony_ci __u32 sack_a_rwnd; 125862306a36Sopenharmony_ci unsigned int outstanding; 125962306a36Sopenharmony_ci struct sctp_transport *primary = asoc->peer.primary_path; 126062306a36Sopenharmony_ci int count_of_newacks = 0; 126162306a36Sopenharmony_ci int gap_ack_blocks; 126262306a36Sopenharmony_ci u8 accum_moved = 0; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* Grab the association's destination address list. */ 126562306a36Sopenharmony_ci transport_list = &asoc->peer.transport_addr_list; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* SCTP path tracepoint for congestion control debugging. */ 126862306a36Sopenharmony_ci if (trace_sctp_probe_path_enabled()) { 126962306a36Sopenharmony_ci list_for_each_entry(transport, transport_list, transports) 127062306a36Sopenharmony_ci trace_sctp_probe_path(transport, asoc); 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci sack_ctsn = ntohl(sack->cum_tsn_ack); 127462306a36Sopenharmony_ci gap_ack_blocks = ntohs(sack->num_gap_ack_blocks); 127562306a36Sopenharmony_ci asoc->stats.gapcnt += gap_ack_blocks; 127662306a36Sopenharmony_ci /* 127762306a36Sopenharmony_ci * SFR-CACC algorithm: 127862306a36Sopenharmony_ci * On receipt of a SACK the sender SHOULD execute the 127962306a36Sopenharmony_ci * following statements. 128062306a36Sopenharmony_ci * 128162306a36Sopenharmony_ci * 1) If the cumulative ack in the SACK passes next tsn_at_change 128262306a36Sopenharmony_ci * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be 128362306a36Sopenharmony_ci * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for 128462306a36Sopenharmony_ci * all destinations. 128562306a36Sopenharmony_ci * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE 128662306a36Sopenharmony_ci * is set the receiver of the SACK MUST take the following actions: 128762306a36Sopenharmony_ci * 128862306a36Sopenharmony_ci * A) Initialize the cacc_saw_newack to 0 for all destination 128962306a36Sopenharmony_ci * addresses. 129062306a36Sopenharmony_ci * 129162306a36Sopenharmony_ci * Only bother if changeover_active is set. Otherwise, this is 129262306a36Sopenharmony_ci * totally suboptimal to do on every SACK. 129362306a36Sopenharmony_ci */ 129462306a36Sopenharmony_ci if (primary->cacc.changeover_active) { 129562306a36Sopenharmony_ci u8 clear_cycling = 0; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) { 129862306a36Sopenharmony_ci primary->cacc.changeover_active = 0; 129962306a36Sopenharmony_ci clear_cycling = 1; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (clear_cycling || gap_ack_blocks) { 130362306a36Sopenharmony_ci list_for_each_entry(transport, transport_list, 130462306a36Sopenharmony_ci transports) { 130562306a36Sopenharmony_ci if (clear_cycling) 130662306a36Sopenharmony_ci transport->cacc.cycling_changeover = 0; 130762306a36Sopenharmony_ci if (gap_ack_blocks) 130862306a36Sopenharmony_ci transport->cacc.cacc_saw_newack = 0; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci /* Get the highest TSN in the sack. */ 131462306a36Sopenharmony_ci highest_tsn = sack_ctsn; 131562306a36Sopenharmony_ci if (gap_ack_blocks) { 131662306a36Sopenharmony_ci union sctp_sack_variable *frags = 131762306a36Sopenharmony_ci (union sctp_sack_variable *)(sack + 1); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci highest_tsn += ntohs(frags[gap_ack_blocks - 1].gab.end); 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (TSN_lt(asoc->highest_sacked, highest_tsn)) 132362306a36Sopenharmony_ci asoc->highest_sacked = highest_tsn; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci highest_new_tsn = sack_ctsn; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci /* Run through the retransmit queue. Credit bytes received 132862306a36Sopenharmony_ci * and free those chunks that we can. 132962306a36Sopenharmony_ci */ 133062306a36Sopenharmony_ci sctp_check_transmitted(q, &q->retransmit, NULL, NULL, sack, &highest_new_tsn); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* Run through the transmitted queue. 133362306a36Sopenharmony_ci * Credit bytes received and free those chunks which we can. 133462306a36Sopenharmony_ci * 133562306a36Sopenharmony_ci * This is a MASSIVE candidate for optimization. 133662306a36Sopenharmony_ci */ 133762306a36Sopenharmony_ci list_for_each_entry(transport, transport_list, transports) { 133862306a36Sopenharmony_ci sctp_check_transmitted(q, &transport->transmitted, 133962306a36Sopenharmony_ci transport, &chunk->source, sack, 134062306a36Sopenharmony_ci &highest_new_tsn); 134162306a36Sopenharmony_ci /* 134262306a36Sopenharmony_ci * SFR-CACC algorithm: 134362306a36Sopenharmony_ci * C) Let count_of_newacks be the number of 134462306a36Sopenharmony_ci * destinations for which cacc_saw_newack is set. 134562306a36Sopenharmony_ci */ 134662306a36Sopenharmony_ci if (transport->cacc.cacc_saw_newack) 134762306a36Sopenharmony_ci count_of_newacks++; 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci /* Move the Cumulative TSN Ack Point if appropriate. */ 135162306a36Sopenharmony_ci if (TSN_lt(asoc->ctsn_ack_point, sack_ctsn)) { 135262306a36Sopenharmony_ci asoc->ctsn_ack_point = sack_ctsn; 135362306a36Sopenharmony_ci accum_moved = 1; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (gap_ack_blocks) { 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci if (asoc->fast_recovery && accum_moved) 135962306a36Sopenharmony_ci highest_new_tsn = highest_tsn; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci list_for_each_entry(transport, transport_list, transports) 136262306a36Sopenharmony_ci sctp_mark_missing(q, &transport->transmitted, transport, 136362306a36Sopenharmony_ci highest_new_tsn, count_of_newacks); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci /* Update unack_data field in the assoc. */ 136762306a36Sopenharmony_ci sctp_sack_update_unack_data(asoc, sack); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci ctsn = asoc->ctsn_ack_point; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci /* Throw away stuff rotting on the sack queue. */ 137262306a36Sopenharmony_ci list_for_each_safe(lchunk, temp, &q->sacked) { 137362306a36Sopenharmony_ci tchunk = list_entry(lchunk, struct sctp_chunk, 137462306a36Sopenharmony_ci transmitted_list); 137562306a36Sopenharmony_ci tsn = ntohl(tchunk->subh.data_hdr->tsn); 137662306a36Sopenharmony_ci if (TSN_lte(tsn, ctsn)) { 137762306a36Sopenharmony_ci list_del_init(&tchunk->transmitted_list); 137862306a36Sopenharmony_ci if (asoc->peer.prsctp_capable && 137962306a36Sopenharmony_ci SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags)) 138062306a36Sopenharmony_ci asoc->sent_cnt_removable--; 138162306a36Sopenharmony_ci sctp_chunk_free(tchunk); 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci /* ii) Set rwnd equal to the newly received a_rwnd minus the 138662306a36Sopenharmony_ci * number of bytes still outstanding after processing the 138762306a36Sopenharmony_ci * Cumulative TSN Ack and the Gap Ack Blocks. 138862306a36Sopenharmony_ci */ 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci sack_a_rwnd = ntohl(sack->a_rwnd); 139162306a36Sopenharmony_ci asoc->peer.zero_window_announced = !sack_a_rwnd; 139262306a36Sopenharmony_ci outstanding = q->outstanding_bytes; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci if (outstanding < sack_a_rwnd) 139562306a36Sopenharmony_ci sack_a_rwnd -= outstanding; 139662306a36Sopenharmony_ci else 139762306a36Sopenharmony_ci sack_a_rwnd = 0; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci asoc->peer.rwnd = sack_a_rwnd; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci asoc->stream.si->generate_ftsn(q, sack_ctsn); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci pr_debug("%s: sack cumulative tsn ack:0x%x\n", __func__, sack_ctsn); 140462306a36Sopenharmony_ci pr_debug("%s: cumulative tsn ack of assoc:%p is 0x%x, " 140562306a36Sopenharmony_ci "advertised peer ack point:0x%x\n", __func__, asoc, ctsn, 140662306a36Sopenharmony_ci asoc->adv_peer_ack_point); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci return sctp_outq_is_empty(q); 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci/* Is the outqueue empty? 141262306a36Sopenharmony_ci * The queue is empty when we have not pending data, no in-flight data 141362306a36Sopenharmony_ci * and nothing pending retransmissions. 141462306a36Sopenharmony_ci */ 141562306a36Sopenharmony_ciint sctp_outq_is_empty(const struct sctp_outq *q) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci return q->out_qlen == 0 && q->outstanding_bytes == 0 && 141862306a36Sopenharmony_ci list_empty(&q->retransmit); 141962306a36Sopenharmony_ci} 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci/******************************************************************** 142262306a36Sopenharmony_ci * 2nd Level Abstractions 142362306a36Sopenharmony_ci ********************************************************************/ 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci/* Go through a transport's transmitted list or the association's retransmit 142662306a36Sopenharmony_ci * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. 142762306a36Sopenharmony_ci * The retransmit list will not have an associated transport. 142862306a36Sopenharmony_ci * 142962306a36Sopenharmony_ci * I added coherent debug information output. --xguo 143062306a36Sopenharmony_ci * 143162306a36Sopenharmony_ci * Instead of printing 'sacked' or 'kept' for each TSN on the 143262306a36Sopenharmony_ci * transmitted_queue, we print a range: SACKED: TSN1-TSN2, TSN3, TSN4-TSN5. 143362306a36Sopenharmony_ci * KEPT TSN6-TSN7, etc. 143462306a36Sopenharmony_ci */ 143562306a36Sopenharmony_cistatic void sctp_check_transmitted(struct sctp_outq *q, 143662306a36Sopenharmony_ci struct list_head *transmitted_queue, 143762306a36Sopenharmony_ci struct sctp_transport *transport, 143862306a36Sopenharmony_ci union sctp_addr *saddr, 143962306a36Sopenharmony_ci struct sctp_sackhdr *sack, 144062306a36Sopenharmony_ci __u32 *highest_new_tsn_in_sack) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci struct list_head *lchunk; 144362306a36Sopenharmony_ci struct sctp_chunk *tchunk; 144462306a36Sopenharmony_ci struct list_head tlist; 144562306a36Sopenharmony_ci __u32 tsn; 144662306a36Sopenharmony_ci __u32 sack_ctsn; 144762306a36Sopenharmony_ci __u32 rtt; 144862306a36Sopenharmony_ci __u8 restart_timer = 0; 144962306a36Sopenharmony_ci int bytes_acked = 0; 145062306a36Sopenharmony_ci int migrate_bytes = 0; 145162306a36Sopenharmony_ci bool forward_progress = false; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci sack_ctsn = ntohl(sack->cum_tsn_ack); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci INIT_LIST_HEAD(&tlist); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* The while loop will skip empty transmitted queues. */ 145862306a36Sopenharmony_ci while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { 145962306a36Sopenharmony_ci tchunk = list_entry(lchunk, struct sctp_chunk, 146062306a36Sopenharmony_ci transmitted_list); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (sctp_chunk_abandoned(tchunk)) { 146362306a36Sopenharmony_ci /* Move the chunk to abandoned list. */ 146462306a36Sopenharmony_ci sctp_insert_list(&q->abandoned, lchunk); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci /* If this chunk has not been acked, stop 146762306a36Sopenharmony_ci * considering it as 'outstanding'. 146862306a36Sopenharmony_ci */ 146962306a36Sopenharmony_ci if (transmitted_queue != &q->retransmit && 147062306a36Sopenharmony_ci !tchunk->tsn_gap_acked) { 147162306a36Sopenharmony_ci if (tchunk->transport) 147262306a36Sopenharmony_ci tchunk->transport->flight_size -= 147362306a36Sopenharmony_ci sctp_data_size(tchunk); 147462306a36Sopenharmony_ci q->outstanding_bytes -= sctp_data_size(tchunk); 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci continue; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci tsn = ntohl(tchunk->subh.data_hdr->tsn); 148062306a36Sopenharmony_ci if (sctp_acked(sack, tsn)) { 148162306a36Sopenharmony_ci /* If this queue is the retransmit queue, the 148262306a36Sopenharmony_ci * retransmit timer has already reclaimed 148362306a36Sopenharmony_ci * the outstanding bytes for this chunk, so only 148462306a36Sopenharmony_ci * count bytes associated with a transport. 148562306a36Sopenharmony_ci */ 148662306a36Sopenharmony_ci if (transport && !tchunk->tsn_gap_acked) { 148762306a36Sopenharmony_ci /* If this chunk is being used for RTT 148862306a36Sopenharmony_ci * measurement, calculate the RTT and update 148962306a36Sopenharmony_ci * the RTO using this value. 149062306a36Sopenharmony_ci * 149162306a36Sopenharmony_ci * 6.3.1 C5) Karn's algorithm: RTT measurements 149262306a36Sopenharmony_ci * MUST NOT be made using packets that were 149362306a36Sopenharmony_ci * retransmitted (and thus for which it is 149462306a36Sopenharmony_ci * ambiguous whether the reply was for the 149562306a36Sopenharmony_ci * first instance of the packet or a later 149662306a36Sopenharmony_ci * instance). 149762306a36Sopenharmony_ci */ 149862306a36Sopenharmony_ci if (!sctp_chunk_retransmitted(tchunk) && 149962306a36Sopenharmony_ci tchunk->rtt_in_progress) { 150062306a36Sopenharmony_ci tchunk->rtt_in_progress = 0; 150162306a36Sopenharmony_ci rtt = jiffies - tchunk->sent_at; 150262306a36Sopenharmony_ci sctp_transport_update_rto(transport, 150362306a36Sopenharmony_ci rtt); 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci if (TSN_lte(tsn, sack_ctsn)) { 150762306a36Sopenharmony_ci /* 150862306a36Sopenharmony_ci * SFR-CACC algorithm: 150962306a36Sopenharmony_ci * 2) If the SACK contains gap acks 151062306a36Sopenharmony_ci * and the flag CHANGEOVER_ACTIVE is 151162306a36Sopenharmony_ci * set the receiver of the SACK MUST 151262306a36Sopenharmony_ci * take the following action: 151362306a36Sopenharmony_ci * 151462306a36Sopenharmony_ci * B) For each TSN t being acked that 151562306a36Sopenharmony_ci * has not been acked in any SACK so 151662306a36Sopenharmony_ci * far, set cacc_saw_newack to 1 for 151762306a36Sopenharmony_ci * the destination that the TSN was 151862306a36Sopenharmony_ci * sent to. 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_ci if (sack->num_gap_ack_blocks && 152162306a36Sopenharmony_ci q->asoc->peer.primary_path->cacc. 152262306a36Sopenharmony_ci changeover_active) 152362306a36Sopenharmony_ci transport->cacc.cacc_saw_newack 152462306a36Sopenharmony_ci = 1; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* If the chunk hasn't been marked as ACKED, 152962306a36Sopenharmony_ci * mark it and account bytes_acked if the 153062306a36Sopenharmony_ci * chunk had a valid transport (it will not 153162306a36Sopenharmony_ci * have a transport if ASCONF had deleted it 153262306a36Sopenharmony_ci * while DATA was outstanding). 153362306a36Sopenharmony_ci */ 153462306a36Sopenharmony_ci if (!tchunk->tsn_gap_acked) { 153562306a36Sopenharmony_ci tchunk->tsn_gap_acked = 1; 153662306a36Sopenharmony_ci if (TSN_lt(*highest_new_tsn_in_sack, tsn)) 153762306a36Sopenharmony_ci *highest_new_tsn_in_sack = tsn; 153862306a36Sopenharmony_ci bytes_acked += sctp_data_size(tchunk); 153962306a36Sopenharmony_ci if (!tchunk->transport) 154062306a36Sopenharmony_ci migrate_bytes += sctp_data_size(tchunk); 154162306a36Sopenharmony_ci forward_progress = true; 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci if (TSN_lte(tsn, sack_ctsn)) { 154562306a36Sopenharmony_ci /* RFC 2960 6.3.2 Retransmission Timer Rules 154662306a36Sopenharmony_ci * 154762306a36Sopenharmony_ci * R3) Whenever a SACK is received 154862306a36Sopenharmony_ci * that acknowledges the DATA chunk 154962306a36Sopenharmony_ci * with the earliest outstanding TSN 155062306a36Sopenharmony_ci * for that address, restart T3-rtx 155162306a36Sopenharmony_ci * timer for that address with its 155262306a36Sopenharmony_ci * current RTO. 155362306a36Sopenharmony_ci */ 155462306a36Sopenharmony_ci restart_timer = 1; 155562306a36Sopenharmony_ci forward_progress = true; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci list_add_tail(&tchunk->transmitted_list, 155862306a36Sopenharmony_ci &q->sacked); 155962306a36Sopenharmony_ci } else { 156062306a36Sopenharmony_ci /* RFC2960 7.2.4, sctpimpguide-05 2.8.2 156162306a36Sopenharmony_ci * M2) Each time a SACK arrives reporting 156262306a36Sopenharmony_ci * 'Stray DATA chunk(s)' record the highest TSN 156362306a36Sopenharmony_ci * reported as newly acknowledged, call this 156462306a36Sopenharmony_ci * value 'HighestTSNinSack'. A newly 156562306a36Sopenharmony_ci * acknowledged DATA chunk is one not 156662306a36Sopenharmony_ci * previously acknowledged in a SACK. 156762306a36Sopenharmony_ci * 156862306a36Sopenharmony_ci * When the SCTP sender of data receives a SACK 156962306a36Sopenharmony_ci * chunk that acknowledges, for the first time, 157062306a36Sopenharmony_ci * the receipt of a DATA chunk, all the still 157162306a36Sopenharmony_ci * unacknowledged DATA chunks whose TSN is 157262306a36Sopenharmony_ci * older than that newly acknowledged DATA 157362306a36Sopenharmony_ci * chunk, are qualified as 'Stray DATA chunks'. 157462306a36Sopenharmony_ci */ 157562306a36Sopenharmony_ci list_add_tail(lchunk, &tlist); 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci } else { 157862306a36Sopenharmony_ci if (tchunk->tsn_gap_acked) { 157962306a36Sopenharmony_ci pr_debug("%s: receiver reneged on data TSN:0x%x\n", 158062306a36Sopenharmony_ci __func__, tsn); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci tchunk->tsn_gap_acked = 0; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci if (tchunk->transport) 158562306a36Sopenharmony_ci bytes_acked -= sctp_data_size(tchunk); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci /* RFC 2960 6.3.2 Retransmission Timer Rules 158862306a36Sopenharmony_ci * 158962306a36Sopenharmony_ci * R4) Whenever a SACK is received missing a 159062306a36Sopenharmony_ci * TSN that was previously acknowledged via a 159162306a36Sopenharmony_ci * Gap Ack Block, start T3-rtx for the 159262306a36Sopenharmony_ci * destination address to which the DATA 159362306a36Sopenharmony_ci * chunk was originally 159462306a36Sopenharmony_ci * transmitted if it is not already running. 159562306a36Sopenharmony_ci */ 159662306a36Sopenharmony_ci restart_timer = 1; 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci list_add_tail(lchunk, &tlist); 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci if (transport) { 160462306a36Sopenharmony_ci if (bytes_acked) { 160562306a36Sopenharmony_ci struct sctp_association *asoc = transport->asoc; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci /* We may have counted DATA that was migrated 160862306a36Sopenharmony_ci * to this transport due to DEL-IP operation. 160962306a36Sopenharmony_ci * Subtract those bytes, since the were never 161062306a36Sopenharmony_ci * send on this transport and shouldn't be 161162306a36Sopenharmony_ci * credited to this transport. 161262306a36Sopenharmony_ci */ 161362306a36Sopenharmony_ci bytes_acked -= migrate_bytes; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci /* 8.2. When an outstanding TSN is acknowledged, 161662306a36Sopenharmony_ci * the endpoint shall clear the error counter of 161762306a36Sopenharmony_ci * the destination transport address to which the 161862306a36Sopenharmony_ci * DATA chunk was last sent. 161962306a36Sopenharmony_ci * The association's overall error counter is 162062306a36Sopenharmony_ci * also cleared. 162162306a36Sopenharmony_ci */ 162262306a36Sopenharmony_ci transport->error_count = 0; 162362306a36Sopenharmony_ci transport->asoc->overall_error_count = 0; 162462306a36Sopenharmony_ci forward_progress = true; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* 162762306a36Sopenharmony_ci * While in SHUTDOWN PENDING, we may have started 162862306a36Sopenharmony_ci * the T5 shutdown guard timer after reaching the 162962306a36Sopenharmony_ci * retransmission limit. Stop that timer as soon 163062306a36Sopenharmony_ci * as the receiver acknowledged any data. 163162306a36Sopenharmony_ci */ 163262306a36Sopenharmony_ci if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING && 163362306a36Sopenharmony_ci del_timer(&asoc->timers 163462306a36Sopenharmony_ci [SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD])) 163562306a36Sopenharmony_ci sctp_association_put(asoc); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci /* Mark the destination transport address as 163862306a36Sopenharmony_ci * active if it is not so marked. 163962306a36Sopenharmony_ci */ 164062306a36Sopenharmony_ci if ((transport->state == SCTP_INACTIVE || 164162306a36Sopenharmony_ci transport->state == SCTP_UNCONFIRMED) && 164262306a36Sopenharmony_ci sctp_cmp_addr_exact(&transport->ipaddr, saddr)) { 164362306a36Sopenharmony_ci sctp_assoc_control_transport( 164462306a36Sopenharmony_ci transport->asoc, 164562306a36Sopenharmony_ci transport, 164662306a36Sopenharmony_ci SCTP_TRANSPORT_UP, 164762306a36Sopenharmony_ci SCTP_RECEIVED_SACK); 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci sctp_transport_raise_cwnd(transport, sack_ctsn, 165162306a36Sopenharmony_ci bytes_acked); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci transport->flight_size -= bytes_acked; 165462306a36Sopenharmony_ci if (transport->flight_size == 0) 165562306a36Sopenharmony_ci transport->partial_bytes_acked = 0; 165662306a36Sopenharmony_ci q->outstanding_bytes -= bytes_acked + migrate_bytes; 165762306a36Sopenharmony_ci } else { 165862306a36Sopenharmony_ci /* RFC 2960 6.1, sctpimpguide-06 2.15.2 165962306a36Sopenharmony_ci * When a sender is doing zero window probing, it 166062306a36Sopenharmony_ci * should not timeout the association if it continues 166162306a36Sopenharmony_ci * to receive new packets from the receiver. The 166262306a36Sopenharmony_ci * reason is that the receiver MAY keep its window 166362306a36Sopenharmony_ci * closed for an indefinite time. 166462306a36Sopenharmony_ci * A sender is doing zero window probing when the 166562306a36Sopenharmony_ci * receiver's advertised window is zero, and there is 166662306a36Sopenharmony_ci * only one data chunk in flight to the receiver. 166762306a36Sopenharmony_ci * 166862306a36Sopenharmony_ci * Allow the association to timeout while in SHUTDOWN 166962306a36Sopenharmony_ci * PENDING or SHUTDOWN RECEIVED in case the receiver 167062306a36Sopenharmony_ci * stays in zero window mode forever. 167162306a36Sopenharmony_ci */ 167262306a36Sopenharmony_ci if (!q->asoc->peer.rwnd && 167362306a36Sopenharmony_ci !list_empty(&tlist) && 167462306a36Sopenharmony_ci (sack_ctsn+2 == q->asoc->next_tsn) && 167562306a36Sopenharmony_ci q->asoc->state < SCTP_STATE_SHUTDOWN_PENDING) { 167662306a36Sopenharmony_ci pr_debug("%s: sack received for zero window " 167762306a36Sopenharmony_ci "probe:%u\n", __func__, sack_ctsn); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci q->asoc->overall_error_count = 0; 168062306a36Sopenharmony_ci transport->error_count = 0; 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci /* RFC 2960 6.3.2 Retransmission Timer Rules 168562306a36Sopenharmony_ci * 168662306a36Sopenharmony_ci * R2) Whenever all outstanding data sent to an address have 168762306a36Sopenharmony_ci * been acknowledged, turn off the T3-rtx timer of that 168862306a36Sopenharmony_ci * address. 168962306a36Sopenharmony_ci */ 169062306a36Sopenharmony_ci if (!transport->flight_size) { 169162306a36Sopenharmony_ci if (del_timer(&transport->T3_rtx_timer)) 169262306a36Sopenharmony_ci sctp_transport_put(transport); 169362306a36Sopenharmony_ci } else if (restart_timer) { 169462306a36Sopenharmony_ci if (!mod_timer(&transport->T3_rtx_timer, 169562306a36Sopenharmony_ci jiffies + transport->rto)) 169662306a36Sopenharmony_ci sctp_transport_hold(transport); 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci if (forward_progress) { 170062306a36Sopenharmony_ci if (transport->dst) 170162306a36Sopenharmony_ci sctp_transport_dst_confirm(transport); 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci list_splice(&tlist, transmitted_queue); 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci/* Mark chunks as missing and consequently may get retransmitted. */ 170962306a36Sopenharmony_cistatic void sctp_mark_missing(struct sctp_outq *q, 171062306a36Sopenharmony_ci struct list_head *transmitted_queue, 171162306a36Sopenharmony_ci struct sctp_transport *transport, 171262306a36Sopenharmony_ci __u32 highest_new_tsn_in_sack, 171362306a36Sopenharmony_ci int count_of_newacks) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci struct sctp_chunk *chunk; 171662306a36Sopenharmony_ci __u32 tsn; 171762306a36Sopenharmony_ci char do_fast_retransmit = 0; 171862306a36Sopenharmony_ci struct sctp_association *asoc = q->asoc; 171962306a36Sopenharmony_ci struct sctp_transport *primary = asoc->peer.primary_path; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci list_for_each_entry(chunk, transmitted_queue, transmitted_list) { 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci tsn = ntohl(chunk->subh.data_hdr->tsn); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all 172662306a36Sopenharmony_ci * 'Unacknowledged TSN's', if the TSN number of an 172762306a36Sopenharmony_ci * 'Unacknowledged TSN' is smaller than the 'HighestTSNinSack' 172862306a36Sopenharmony_ci * value, increment the 'TSN.Missing.Report' count on that 172962306a36Sopenharmony_ci * chunk if it has NOT been fast retransmitted or marked for 173062306a36Sopenharmony_ci * fast retransmit already. 173162306a36Sopenharmony_ci */ 173262306a36Sopenharmony_ci if (chunk->fast_retransmit == SCTP_CAN_FRTX && 173362306a36Sopenharmony_ci !chunk->tsn_gap_acked && 173462306a36Sopenharmony_ci TSN_lt(tsn, highest_new_tsn_in_sack)) { 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci /* SFR-CACC may require us to skip marking 173762306a36Sopenharmony_ci * this chunk as missing. 173862306a36Sopenharmony_ci */ 173962306a36Sopenharmony_ci if (!transport || !sctp_cacc_skip(primary, 174062306a36Sopenharmony_ci chunk->transport, 174162306a36Sopenharmony_ci count_of_newacks, tsn)) { 174262306a36Sopenharmony_ci chunk->tsn_missing_report++; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci pr_debug("%s: tsn:0x%x missing counter:%d\n", 174562306a36Sopenharmony_ci __func__, tsn, chunk->tsn_missing_report); 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci /* 174962306a36Sopenharmony_ci * M4) If any DATA chunk is found to have a 175062306a36Sopenharmony_ci * 'TSN.Missing.Report' 175162306a36Sopenharmony_ci * value larger than or equal to 3, mark that chunk for 175262306a36Sopenharmony_ci * retransmission and start the fast retransmit procedure. 175362306a36Sopenharmony_ci */ 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (chunk->tsn_missing_report >= 3) { 175662306a36Sopenharmony_ci chunk->fast_retransmit = SCTP_NEED_FRTX; 175762306a36Sopenharmony_ci do_fast_retransmit = 1; 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci if (transport) { 176262306a36Sopenharmony_ci if (do_fast_retransmit) 176362306a36Sopenharmony_ci sctp_retransmit(q, transport, SCTP_RTXR_FAST_RTX); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci pr_debug("%s: transport:%p, cwnd:%d, ssthresh:%d, " 176662306a36Sopenharmony_ci "flight_size:%d, pba:%d\n", __func__, transport, 176762306a36Sopenharmony_ci transport->cwnd, transport->ssthresh, 176862306a36Sopenharmony_ci transport->flight_size, transport->partial_bytes_acked); 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci/* Is the given TSN acked by this packet? */ 177362306a36Sopenharmony_cistatic int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn) 177462306a36Sopenharmony_ci{ 177562306a36Sopenharmony_ci __u32 ctsn = ntohl(sack->cum_tsn_ack); 177662306a36Sopenharmony_ci union sctp_sack_variable *frags; 177762306a36Sopenharmony_ci __u16 tsn_offset, blocks; 177862306a36Sopenharmony_ci int i; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci if (TSN_lte(tsn, ctsn)) 178162306a36Sopenharmony_ci goto pass; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci /* 3.3.4 Selective Acknowledgment (SACK) (3): 178462306a36Sopenharmony_ci * 178562306a36Sopenharmony_ci * Gap Ack Blocks: 178662306a36Sopenharmony_ci * These fields contain the Gap Ack Blocks. They are repeated 178762306a36Sopenharmony_ci * for each Gap Ack Block up to the number of Gap Ack Blocks 178862306a36Sopenharmony_ci * defined in the Number of Gap Ack Blocks field. All DATA 178962306a36Sopenharmony_ci * chunks with TSNs greater than or equal to (Cumulative TSN 179062306a36Sopenharmony_ci * Ack + Gap Ack Block Start) and less than or equal to 179162306a36Sopenharmony_ci * (Cumulative TSN Ack + Gap Ack Block End) of each Gap Ack 179262306a36Sopenharmony_ci * Block are assumed to have been received correctly. 179362306a36Sopenharmony_ci */ 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci frags = (union sctp_sack_variable *)(sack + 1); 179662306a36Sopenharmony_ci blocks = ntohs(sack->num_gap_ack_blocks); 179762306a36Sopenharmony_ci tsn_offset = tsn - ctsn; 179862306a36Sopenharmony_ci for (i = 0; i < blocks; ++i) { 179962306a36Sopenharmony_ci if (tsn_offset >= ntohs(frags[i].gab.start) && 180062306a36Sopenharmony_ci tsn_offset <= ntohs(frags[i].gab.end)) 180162306a36Sopenharmony_ci goto pass; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci return 0; 180562306a36Sopenharmony_cipass: 180662306a36Sopenharmony_ci return 1; 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_cistatic inline int sctp_get_skip_pos(struct sctp_fwdtsn_skip *skiplist, 181062306a36Sopenharmony_ci int nskips, __be16 stream) 181162306a36Sopenharmony_ci{ 181262306a36Sopenharmony_ci int i; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci for (i = 0; i < nskips; i++) { 181562306a36Sopenharmony_ci if (skiplist[i].stream == stream) 181662306a36Sopenharmony_ci return i; 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci return i; 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci/* Create and add a fwdtsn chunk to the outq's control queue if needed. */ 182262306a36Sopenharmony_civoid sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci struct sctp_association *asoc = q->asoc; 182562306a36Sopenharmony_ci struct sctp_chunk *ftsn_chunk = NULL; 182662306a36Sopenharmony_ci struct sctp_fwdtsn_skip ftsn_skip_arr[10]; 182762306a36Sopenharmony_ci int nskips = 0; 182862306a36Sopenharmony_ci int skip_pos = 0; 182962306a36Sopenharmony_ci __u32 tsn; 183062306a36Sopenharmony_ci struct sctp_chunk *chunk; 183162306a36Sopenharmony_ci struct list_head *lchunk, *temp; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci if (!asoc->peer.prsctp_capable) 183462306a36Sopenharmony_ci return; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci /* PR-SCTP C1) Let SackCumAck be the Cumulative TSN ACK carried in the 183762306a36Sopenharmony_ci * received SACK. 183862306a36Sopenharmony_ci * 183962306a36Sopenharmony_ci * If (Advanced.Peer.Ack.Point < SackCumAck), then update 184062306a36Sopenharmony_ci * Advanced.Peer.Ack.Point to be equal to SackCumAck. 184162306a36Sopenharmony_ci */ 184262306a36Sopenharmony_ci if (TSN_lt(asoc->adv_peer_ack_point, ctsn)) 184362306a36Sopenharmony_ci asoc->adv_peer_ack_point = ctsn; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci /* PR-SCTP C2) Try to further advance the "Advanced.Peer.Ack.Point" 184662306a36Sopenharmony_ci * locally, that is, to move "Advanced.Peer.Ack.Point" up as long as 184762306a36Sopenharmony_ci * the chunk next in the out-queue space is marked as "abandoned" as 184862306a36Sopenharmony_ci * shown in the following example: 184962306a36Sopenharmony_ci * 185062306a36Sopenharmony_ci * Assuming that a SACK arrived with the Cumulative TSN ACK 102 185162306a36Sopenharmony_ci * and the Advanced.Peer.Ack.Point is updated to this value: 185262306a36Sopenharmony_ci * 185362306a36Sopenharmony_ci * out-queue at the end of ==> out-queue after Adv.Ack.Point 185462306a36Sopenharmony_ci * normal SACK processing local advancement 185562306a36Sopenharmony_ci * ... ... 185662306a36Sopenharmony_ci * Adv.Ack.Pt-> 102 acked 102 acked 185762306a36Sopenharmony_ci * 103 abandoned 103 abandoned 185862306a36Sopenharmony_ci * 104 abandoned Adv.Ack.P-> 104 abandoned 185962306a36Sopenharmony_ci * 105 105 186062306a36Sopenharmony_ci * 106 acked 106 acked 186162306a36Sopenharmony_ci * ... ... 186262306a36Sopenharmony_ci * 186362306a36Sopenharmony_ci * In this example, the data sender successfully advanced the 186462306a36Sopenharmony_ci * "Advanced.Peer.Ack.Point" from 102 to 104 locally. 186562306a36Sopenharmony_ci */ 186662306a36Sopenharmony_ci list_for_each_safe(lchunk, temp, &q->abandoned) { 186762306a36Sopenharmony_ci chunk = list_entry(lchunk, struct sctp_chunk, 186862306a36Sopenharmony_ci transmitted_list); 186962306a36Sopenharmony_ci tsn = ntohl(chunk->subh.data_hdr->tsn); 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci /* Remove any chunks in the abandoned queue that are acked by 187262306a36Sopenharmony_ci * the ctsn. 187362306a36Sopenharmony_ci */ 187462306a36Sopenharmony_ci if (TSN_lte(tsn, ctsn)) { 187562306a36Sopenharmony_ci list_del_init(lchunk); 187662306a36Sopenharmony_ci sctp_chunk_free(chunk); 187762306a36Sopenharmony_ci } else { 187862306a36Sopenharmony_ci if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) { 187962306a36Sopenharmony_ci asoc->adv_peer_ack_point = tsn; 188062306a36Sopenharmony_ci if (chunk->chunk_hdr->flags & 188162306a36Sopenharmony_ci SCTP_DATA_UNORDERED) 188262306a36Sopenharmony_ci continue; 188362306a36Sopenharmony_ci skip_pos = sctp_get_skip_pos(&ftsn_skip_arr[0], 188462306a36Sopenharmony_ci nskips, 188562306a36Sopenharmony_ci chunk->subh.data_hdr->stream); 188662306a36Sopenharmony_ci ftsn_skip_arr[skip_pos].stream = 188762306a36Sopenharmony_ci chunk->subh.data_hdr->stream; 188862306a36Sopenharmony_ci ftsn_skip_arr[skip_pos].ssn = 188962306a36Sopenharmony_ci chunk->subh.data_hdr->ssn; 189062306a36Sopenharmony_ci if (skip_pos == nskips) 189162306a36Sopenharmony_ci nskips++; 189262306a36Sopenharmony_ci if (nskips == 10) 189362306a36Sopenharmony_ci break; 189462306a36Sopenharmony_ci } else 189562306a36Sopenharmony_ci break; 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci /* PR-SCTP C3) If, after step C1 and C2, the "Advanced.Peer.Ack.Point" 190062306a36Sopenharmony_ci * is greater than the Cumulative TSN ACK carried in the received 190162306a36Sopenharmony_ci * SACK, the data sender MUST send the data receiver a FORWARD TSN 190262306a36Sopenharmony_ci * chunk containing the latest value of the 190362306a36Sopenharmony_ci * "Advanced.Peer.Ack.Point". 190462306a36Sopenharmony_ci * 190562306a36Sopenharmony_ci * C4) For each "abandoned" TSN the sender of the FORWARD TSN SHOULD 190662306a36Sopenharmony_ci * list each stream and sequence number in the forwarded TSN. This 190762306a36Sopenharmony_ci * information will enable the receiver to easily find any 190862306a36Sopenharmony_ci * stranded TSN's waiting on stream reorder queues. Each stream 190962306a36Sopenharmony_ci * SHOULD only be reported once; this means that if multiple 191062306a36Sopenharmony_ci * abandoned messages occur in the same stream then only the 191162306a36Sopenharmony_ci * highest abandoned stream sequence number is reported. If the 191262306a36Sopenharmony_ci * total size of the FORWARD TSN does NOT fit in a single MTU then 191362306a36Sopenharmony_ci * the sender of the FORWARD TSN SHOULD lower the 191462306a36Sopenharmony_ci * Advanced.Peer.Ack.Point to the last TSN that will fit in a 191562306a36Sopenharmony_ci * single MTU. 191662306a36Sopenharmony_ci */ 191762306a36Sopenharmony_ci if (asoc->adv_peer_ack_point > ctsn) 191862306a36Sopenharmony_ci ftsn_chunk = sctp_make_fwdtsn(asoc, asoc->adv_peer_ack_point, 191962306a36Sopenharmony_ci nskips, &ftsn_skip_arr[0]); 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci if (ftsn_chunk) { 192262306a36Sopenharmony_ci list_add_tail(&ftsn_chunk->list, &q->control_chunk_list); 192362306a36Sopenharmony_ci SCTP_INC_STATS(asoc->base.net, SCTP_MIB_OUTCTRLCHUNKS); 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci} 1926