* Queue the chunk either right into the socket buffer if it is the next one * to go OR put it in the correct place in the delivery queue. If we do * append to the so_buf, keep doing so until we are out of order as * long as the control's entered are non-fragmented. */
| 478 | * long as the control's entered are non-fragmented. |
| 479 | */ |
| 480 | static void |
| 481 | sctp_queue_data_to_stream(struct sctp_tcb *stcb, |
| 482 | struct sctp_association *asoc, |
| 483 | struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm) |
| 484 | { |
| 485 | /* |
| 486 | * FIX-ME maybe? What happens when the ssn wraps? If we are getting |
| 487 | * all the data in one stream this could happen quite rapidly. One |
| 488 | * could use the TSN to keep track of things, but this scheme breaks |
| 489 | * down in the other type of stream usage that could occur. Send a |
| 490 | * single msg to stream 0, send 4Billion messages to stream 1, now |
| 491 | * send a message to stream 0. You have a situation where the TSN |
| 492 | * has wrapped but not in the stream. Is this worth worrying about |
| 493 | * or should we just change our queue sort at the bottom to be by |
| 494 | * TSN. |
| 495 | * |
| 496 | * Could it also be legal for a peer to send ssn 1 with TSN 2 and |
| 497 | * ssn 2 with TSN 1? If the peer is doing some sort of funky TSN/SSN |
| 498 | * assignment this could happen... and I don't see how this would be |
| 499 | * a violation. So for now I am undecided an will leave the sort by |
| 500 | * SSN alone. Maybe a hybred approach is the answer |
| 501 | * |
| 502 | */ |
| 503 | struct sctp_queued_to_read *at; |
| 504 | int queue_needed; |
| 505 | uint32_t nxt_todel; |
| 506 | struct mbuf *op_err; |
| 507 | struct sctp_stream_in *strm; |
| 508 | char msg[SCTP_DIAG_INFO_LEN]; |
| 509 | |
| 510 | strm = &asoc->strmin[control->sinfo_stream]; |
| 511 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { |
| 512 | sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD); |
| 513 | } |
| 514 | if (SCTP_MID_GT((asoc->idata_supported), strm->last_mid_delivered, control->mid)) { |
| 515 | /* The incoming sseq is behind where we last delivered? */ |
| 516 | SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n", |
| 517 | strm->last_mid_delivered, control->mid); |
| 518 | /* |
| 519 | * throw it in the stream so it gets cleaned up in |
| 520 | * association destruction |
| 521 | */ |
| 522 | TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm); |
| 523 | if (asoc->idata_supported) { |
| 524 | SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x", |
| 525 | strm->last_mid_delivered, control->sinfo_tsn, |
| 526 | control->sinfo_stream, control->mid); |
| 527 | } else { |
| 528 | SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", |
| 529 | (uint16_t)strm->last_mid_delivered, |
| 530 | control->sinfo_tsn, |
| 531 | control->sinfo_stream, |
| 532 | (uint16_t)control->mid); |
| 533 | } |
| 534 | op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); |
| 535 | stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2; |
| 536 | sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); |
| 537 | *abort_flag = 1; |
no test coverage detected