SCTP: Assign stream sequence numbers to the entire message

Currently we only assign the sequence number to a packet that
we are about to transmit. This however breaks the Partial
Reliability extensions, because it's possible for us to
never transmit a packet, i.e. it expires before we get to send
it. In such cases, if the message contained multiple SCTP
fragments, and we did manage to send the first part of the
message, the Stream sequence numbers would get into invalid
state and cause receiver to stall.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>

+23 -12
+23 -12
net/sctp/sm_make_chunk.c
··· 1174 1174 */ 1175 1175 void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) 1176 1176 { 1177 + struct sctp_datamsg *msg; 1178 + struct sctp_chunk *lchunk; 1179 + struct sctp_stream *stream; 1177 1180 __u16 ssn; 1178 1181 __u16 sid; 1179 1182 1180 1183 if (chunk->has_ssn) 1181 1184 return; 1182 1185 1183 - /* This is the last possible instant to assign a SSN. */ 1184 - if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { 1185 - ssn = 0; 1186 - } else { 1187 - sid = ntohs(chunk->subh.data_hdr->stream); 1188 - if (chunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG) 1189 - ssn = sctp_ssn_next(&chunk->asoc->ssnmap->out, sid); 1190 - else 1191 - ssn = sctp_ssn_peek(&chunk->asoc->ssnmap->out, sid); 1192 - } 1186 + /* All fragments will be on the same stream */ 1187 + sid = ntohs(chunk->subh.data_hdr->stream); 1188 + stream = &chunk->asoc->ssnmap->out; 1193 1189 1194 - chunk->subh.data_hdr->ssn = htons(ssn); 1195 - chunk->has_ssn = 1; 1190 + /* Now assign the sequence number to the entire message. 1191 + * All fragments must have the same stream sequence number. 1192 + */ 1193 + msg = chunk->msg; 1194 + list_for_each_entry(lchunk, &msg->chunks, frag_list) { 1195 + if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { 1196 + ssn = 0; 1197 + } else { 1198 + if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG) 1199 + ssn = sctp_ssn_next(stream, sid); 1200 + else 1201 + ssn = sctp_ssn_peek(stream, sid); 1202 + } 1203 + 1204 + lchunk->subh.data_hdr->ssn = htons(ssn); 1205 + lchunk->has_ssn = 1; 1206 + } 1196 1207 } 1197 1208 1198 1209 /* Helper function to assign a TSN if needed. This assumes that both