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 */ 1175 void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) 1176 { 1177 __u16 ssn; 1178 __u16 sid; 1179 1180 if (chunk->has_ssn) 1181 return; 1182 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 - } 1193 1194 - chunk->subh.data_hdr->ssn = htons(ssn); 1195 - chunk->has_ssn = 1; 1196 } 1197 1198 /* Helper function to assign a TSN if needed. This assumes that both
··· 1174 */ 1175 void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) 1176 { 1177 + struct sctp_datamsg *msg; 1178 + struct sctp_chunk *lchunk; 1179 + struct sctp_stream *stream; 1180 __u16 ssn; 1181 __u16 sid; 1182 1183 if (chunk->has_ssn) 1184 return; 1185 1186 + /* All fragments will be on the same stream */ 1187 + sid = ntohs(chunk->subh.data_hdr->stream); 1188 + stream = &chunk->asoc->ssnmap->out; 1189 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 + } 1207 } 1208 1209 /* Helper function to assign a TSN if needed. This assumes that both