diff options
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r-- | sys/netinet/sctp_output.c | 131 |
1 files changed, 97 insertions, 34 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index e1ee546..304d299 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3587,6 +3587,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, SCTP_STAT_INCR_COUNTER64(sctps_outpackets); if (ret) SCTP_STAT_INCR(sctps_senderrors); + #ifdef SCTP_DEBUG if (sctp_debug_on & SCTP_DEBUG_OUTPUT3) { printf("Ip output returns %d\n", ret); @@ -5371,7 +5372,6 @@ sctp_msg_append(struct sctp_tcb *stcb, error = ENOMEM; goto out_now; } - SCTP_INCR_STRMOQ_COUNT(); sp->sinfo_flags = srcv->sinfo_flags; sp->timetolive = srcv->sinfo_timetolive; sp->ppid = srcv->sinfo_ppid; @@ -6084,15 +6084,16 @@ sctp_can_we_split_this(struct sctp_tcb *stcb, * If we have data outstanding, * we get another chance when the sack * arrives to transmit - wait for more data - * - * Could this be optimized to be aware of - * two packets? - * */ - if (stcb->asoc.total_flight > 0) - return (0); - else + if (stcb->asoc.total_flight == 0) { + /* + * If nothing is in flight, we zero the + * packet counter. + */ return (sp->length); + } + return (0); + } else { /* You can fill the rest */ return (goal_mtu); @@ -6132,7 +6133,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, int to_move; uint8_t rcv_flags = 0; uint8_t some_taken; - uint8_t took_all = 0; uint8_t send_lock_up = 0; SCTP_TCB_LOCK_ASSERT(stcb); @@ -6159,12 +6159,23 @@ one_more_time: if (sp->length == 0) { if (sp->sender_all_done) { /* - * We are doing deffered cleanup. Last time + * We are doing differed cleanup. Last time * through when we took all the data the * sender_all_done was not set. */ - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; + if (sp->put_last_out == 0) { + printf("Gak, put out entire msg with NO end!-1\n"); + printf("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n", + sp->sender_all_done, + sp->length, + sp->msg_is_complete, + sp->put_last_out, + send_lock_up); + } + if (TAILQ_NEXT(sp, next) == NULL) { + SCTP_TCB_SEND_LOCK(stcb); + send_lock_up = 1; + } atomic_subtract_int(&asoc->stream_queue_cnt, 1); TAILQ_REMOVE(&strq->outqueue, sp, next); sctp_free_remote_addr(sp->net); @@ -6206,6 +6217,7 @@ one_more_time: if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { sp->msg_is_complete = 1; } +re_look: if (sp->msg_is_complete) { /* The message is complete */ to_move = min(sp->length, frag_point); @@ -6213,8 +6225,10 @@ one_more_time: /* All of it fits in the MTU */ if (sp->some_taken) { rcv_flags |= SCTP_DATA_LAST_FRAG; + sp->put_last_out = 1; } else { rcv_flags |= SCTP_DATA_NOT_FRAG; + sp->put_last_out = 1; } } else { /* Not all of it fits, we fragment */ @@ -6227,14 +6241,37 @@ one_more_time: to_move = sctp_can_we_split_this(stcb, sp, goal_mtu, frag_point, eeor_mode); if (to_move) { - if (to_move >= sp->length) { - to_move = sp->length; + /*- + * We use a snapshot of length in case it + * is expanding during the compare. + */ + uint32_t llen; + + llen = sp->length; + if (to_move >= llen) { + to_move = llen; + if (send_lock_up == 0) { + /*- + * We are taking all of an incomplete msg + * thus we need a send lock. + */ + SCTP_TCB_SEND_LOCK(stcb); + send_lock_up = 1; + if (sp->msg_is_complete) { + /* + * the sender finished the + * msg + */ + goto re_look; + } + } } if (sp->some_taken == 0) { rcv_flags |= SCTP_DATA_FIRST_FRAG; + sp->some_taken = 1; } - sp->some_taken = 1; } else { + /* Nothing to take. */ if (sp->some_taken) { *locked = 1; } @@ -6270,21 +6307,12 @@ out_gu: } else { chk->copy_by_ref = 0; } - if ((sp->msg_is_complete == 0) && - (to_move >= sp->length)) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } else { - send_lock_up = 0; - } - if (to_move >= sp->length) { /* we can steal the whole thing */ chk->data = sp->data; chk->last_mbuf = sp->tail_mbuf; /* register the stealing */ sp->data = sp->tail_mbuf = NULL; - took_all = 1; } else { struct mbuf *m; @@ -6303,16 +6331,35 @@ out_gu: sp->data = SCTP_BUF_NEXT(m); SCTP_BUF_NEXT(m) = NULL; if (sp->tail_mbuf == m) { - /* freeing tail */ + /*- + * Freeing tail? TSNH since + * we supposedly were taking less + * than the sp->length. + */ +#ifdef INVARIANTS + panic("Huh, freing tail? - TSNH"); +#else printf("Huh, freeing tail? - TSNH\n"); - sp->tail_mbuf = sp->data; + sp->tail_mbuf = sp->data = NULL; + sp->length = 0; +#endif + } sctp_m_free(m); m = sp->data; } } if (to_move > sp->length) { + /*- This should not happen either + * since we always lower to_move to the size + * of sp->length if its larger. + */ +#ifdef INVARIANTS panic("Huh, how can to_move be larger?"); +#else + printf("Huh, how can to_move be larger?\n"); + sp->length = 0; +#endif } else { atomic_subtract_int(&sp->length, to_move); } @@ -6331,7 +6378,7 @@ out_gu: SCTP_TCB_SEND_LOCK(stcb); send_lock_up = 1; } - if (took_all) { + if (chk->data == NULL) { /* unsteal the data */ sp->data = chk->data; sp->tail_mbuf = chk->last_mbuf; @@ -6344,7 +6391,7 @@ out_gu: SCTP_BUF_NEXT(sp->data) = m; } sp->some_taken = some_taken; - sp->length += to_move; + atomic_add_int(&sp->length, to_move); chk->data = NULL; sctp_free_a_chunk(stcb, chk); goto out_gu; @@ -6357,9 +6404,13 @@ out_gu: } SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_DONTWAIT); if (chk->data == NULL) { - /* HELP */ + /* HELP, TSNH since we assured it would not above? */ +#ifdef INVARIANTS + panic("prepend failes HELP?"); +#else printf("prepend fails HELP?\n"); sctp_free_a_chunk(stcb, chk); +#endif goto out_gu; } sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk)); @@ -6414,9 +6465,12 @@ out_gu: asoc->out_tsnlog[asoc->tsn_out_at].tsn = chk->rec.data.TSN_seq; asoc->out_tsnlog[asoc->tsn_out_at].strm = chk->rec.data.stream_number; asoc->out_tsnlog[asoc->tsn_out_at].seq = chk->rec.data.stream_seq; + asoc->out_tsnlog[asoc->tsn_out_at].sz = chk->send_size; + asoc->out_tsnlog[asoc->tsn_out_at].flgs = chk->rec.data.rcv_flags; asoc->tsn_out_at++; if (asoc->tsn_out_at >= SCTP_TSN_LOG_SIZE) { asoc->tsn_out_at = 0; + asoc->tsn_out_wrapped = 1; } #endif @@ -6450,7 +6504,16 @@ out_gu: if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) { /* All done pull and kill the message */ atomic_subtract_int(&asoc->stream_queue_cnt, 1); - if (send_lock_up == 0) { + if (sp->put_last_out == 0) { + printf("Gak, put out entire msg with NO end!-2\n"); + printf("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n", + sp->sender_all_done, + sp->length, + sp->msg_is_complete, + sp->put_last_out, + send_lock_up); + } + if ((send_lock_up == 0) && (TAILQ_NEXT(sp, next) == NULL)) { SCTP_TCB_SEND_LOCK(stcb); send_lock_up = 1; } @@ -10422,7 +10485,6 @@ sctp_copy_it_in(struct sctp_tcb *stcb, *error = ENOMEM; goto out_now; } - SCTP_INCR_STRMOQ_COUNT(); sp->act_flags = 0; sp->sender_all_done = 0; sp->sinfo_flags = srcv->sinfo_flags; @@ -10445,6 +10507,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb, } sp->sender_all_done = 0; sp->some_taken = 0; + sp->put_last_out = 0; resv_in_first = sizeof(struct sctp_data_chunk); sp->data = sp->tail_mbuf = NULL; *error = sctp_copy_one(sp, uio, resv_in_first); @@ -11105,9 +11168,7 @@ sctp_lower_sosend(struct socket *so, sp->sender_all_done = 0; } sctp_snd_sb_alloc(stcb, sp->length); - atomic_add_int(&asoc->stream_queue_cnt, 1); - TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); if ((srcv->sinfo_flags & SCTP_UNORDERED) == 0) { sp->strseq = strm->next_sequence_sent; #ifdef SCTP_LOG_SENDING_STR @@ -11119,7 +11180,7 @@ sctp_lower_sosend(struct socket *so, } else { SCTP_STAT_INCR(sctps_sends_with_unord); } - + TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); if ((strm->next_spoke.tqe_next == NULL) && (strm->next_spoke.tqe_prev == NULL)) { /* Not on wheel, insert */ @@ -11195,6 +11256,7 @@ sctp_lower_sosend(struct socket *so, /* Did we reach EOR? */ if ((uio->uio_resid == 0) && ((user_marks_eor == 0) || + (srcv->sinfo_flags & SCTP_EOF) || (user_marks_eor && (srcv->sinfo_flags & SCTP_EOR))) ) { sp->msg_is_complete = 1; @@ -11384,6 +11446,7 @@ sctp_lower_sosend(struct socket *so, asoc->stream_locked = 0; } } else { + printf("Huh no sp TSNH?\n"); strm->last_msg_incomplete = 0; asoc->stream_locked = 0; |