diff options
Diffstat (limited to 'sys/netinet/sctp_indata.c')
-rw-r--r-- | sys/netinet/sctp_indata.c | 167 |
1 files changed, 89 insertions, 78 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 50a6628..75c1ac5 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -223,9 +223,9 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo) } seinfo = (struct sctp_extrcvinfo *)sinfo; if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) && - (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) { + (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) { provide_nxt = 1; - len += CMSG_SPACE(sizeof(struct sctp_rcvinfo)); + len += CMSG_SPACE(sizeof(struct sctp_nxtinfo)); } else { provide_nxt = 0; } @@ -276,20 +276,20 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo) cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_nxtinfo)); cmh->cmsg_type = SCTP_NXTINFO; nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmh); - nxtinfo->nxt_sid = seinfo->sreinfo_next_stream; + nxtinfo->nxt_sid = seinfo->serinfo_next_stream; nxtinfo->nxt_flags = 0; - if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) { + if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) { nxtinfo->nxt_flags |= SCTP_UNORDERED; } - if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) { + if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) { nxtinfo->nxt_flags |= SCTP_NOTIFICATION; } - if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) { + if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) { nxtinfo->nxt_flags |= SCTP_COMPLETE; } - nxtinfo->nxt_ppid = seinfo->sreinfo_next_ppid; - nxtinfo->nxt_length = seinfo->sreinfo_next_length; - nxtinfo->nxt_assoc_id = seinfo->sreinfo_next_aid; + nxtinfo->nxt_ppid = seinfo->serinfo_next_ppid; + nxtinfo->nxt_length = seinfo->serinfo_next_length; + nxtinfo->nxt_assoc_id = seinfo->serinfo_next_aid; cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo))); SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_nxtinfo)); } @@ -578,10 +578,10 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD); } SCTPDBG(SCTP_DEBUG_INDATA1, - "queue to stream called for ssn:%u lastdel:%u nxt:%u\n", - (uint32_t) control->sinfo_stream, - (uint32_t) strm->last_sequence_delivered, - (uint32_t) nxt_todel); + "queue to stream called for sid:%u ssn:%u tsn:%u lastdel:%u nxt:%u\n", + (uint32_t) control->sinfo_stream, (uint32_t) control->sinfo_ssn, + (uint32_t) control->sinfo_tsn, + (uint32_t) strm->last_sequence_delivered, (uint32_t) nxt_todel); if (SCTP_SSN_GE(strm->last_sequence_delivered, control->sinfo_ssn)) { /* The incoming sseq is behind where we last delivered? */ SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ:%d delivered:%d from peer, Abort association\n", @@ -602,6 +602,20 @@ protocol_error: return; } +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + struct socket *so; + + so = SCTP_INP_SO(stcb->sctp_ep); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_SOCKET_LOCK(so, 1); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { + SCTP_SOCKET_UNLOCK(so, 1); + return; + } +#endif if (nxt_todel == control->sinfo_ssn) { /* can be delivered right away? */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { @@ -617,7 +631,7 @@ protocol_error: sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); + SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED); TAILQ_FOREACH_SAFE(control, &strm->inqueue, next, at) { /* all delivered */ nxt_todel = strm->last_sequence_delivered + 1; @@ -641,7 +655,7 @@ protocol_error: control, &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, - SCTP_SO_NOT_LOCKED); + SCTP_SO_LOCKED); continue; } break; @@ -653,6 +667,9 @@ protocol_error: * to put it on the queue. */ if (SCTP_TSN_GE(asoc->cumulative_tsn, control->sinfo_tsn)) { +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + SCTP_SOCKET_UNLOCK(so, 1); +#endif goto protocol_error; } if (TAILQ_EMPTY(&strm->inqueue)) { @@ -699,6 +716,9 @@ protocol_error: control->whoFrom = NULL; } sctp_free_a_readq(stcb, control); +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + SCTP_SOCKET_UNLOCK(so, 1); +#endif return; } else { if (TAILQ_NEXT(at, next) == NULL) { @@ -718,6 +738,9 @@ protocol_error: } } } +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + SCTP_SOCKET_UNLOCK(so, 1); +#endif } /* @@ -1403,30 +1426,25 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, } strmno = ntohs(ch->dp.stream_id); if (strmno >= asoc->streamincnt) { - struct sctp_paramhdr *phdr; - struct mbuf *mb; + struct sctp_error_invalid_stream *cause; - mb = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) * 2), + op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream), 0, M_NOWAIT, 1, MT_DATA); - if (mb != NULL) { + if (op_err != NULL) { /* add some space up front so prepend will work well */ - SCTP_BUF_RESV_UF(mb, sizeof(struct sctp_chunkhdr)); - phdr = mtod(mb, struct sctp_paramhdr *); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); + cause = mtod(op_err, struct sctp_error_invalid_stream *); /* * Error causes are just param's and this one has * two back to back phdr, one with the error type * and size, the other with the streamid and a rsvd */ - SCTP_BUF_LEN(mb) = (sizeof(struct sctp_paramhdr) * 2); - phdr->param_type = htons(SCTP_CAUSE_INVALID_STREAM); - phdr->param_length = - htons(sizeof(struct sctp_paramhdr) * 2); - phdr++; - /* We insert the stream in the type field */ - phdr->param_type = ch->dp.stream_id; - /* And set the length to 0 for the rsvd field */ - phdr->param_length = 0; - sctp_queue_op_err(stcb, mb); + SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream); + cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM); + cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream)); + cause->stream_id = ch->dp.stream_id; + cause->reserved = htons(0); + sctp_queue_op_err(stcb, op_err); } SCTP_STAT_INCR(sctps_badsid); SCTP_TCB_LOCK_ASSERT(stcb); @@ -1886,6 +1904,7 @@ finish_express_del: sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams); TAILQ_REMOVE(&asoc->resetHead, liste, next_resp); + sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED); SCTP_FREE(liste, SCTP_M_STRESET); /* sa_ignore FREED_MEMORY */ liste = TAILQ_FIRST(&asoc->resetHead); @@ -2288,11 +2307,8 @@ doit_again: int sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_inpcb *inp, - struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t * high_tsn, - uint8_t mflowtype, uint32_t mflowid, - uint32_t vrf_id, uint16_t port) + struct sctp_inpcb *inp, struct sctp_tcb *stcb, + struct sctp_nets *net, uint32_t * high_tsn) { struct sctp_data_chunk *ch, chunk_buf; struct sctp_association *asoc; @@ -2384,10 +2400,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, chk_length); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21; - sctp_abort_association(inp, stcb, m, iphlen, - src, dst, sh, op_err, - mflowtype, mflowid, - vrf_id, port); + sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (2); } if ((size_t)chk_length == sizeof(struct sctp_data_chunk)) { @@ -2399,10 +2412,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, op_err = sctp_generate_no_user_data_cause(ch->dp.tsn); stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22; - sctp_abort_association(inp, stcb, m, iphlen, - src, dst, sh, op_err, - mflowtype, mflowid, - vrf_id, port); + sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (2); } #ifdef SCTP_AUDITING_ENABLED @@ -2464,14 +2474,12 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, */ if (SCTP_BASE_SYSCTL(sctp_strict_data_order)) { struct mbuf *op_err; + char msg[SCTP_DIAG_INFO_LEN]; - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, ""); - sctp_abort_association(inp, stcb, - m, iphlen, - src, dst, - sh, op_err, - mflowtype, mflowid, - vrf_id, port); + snprintf(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x", + ch->ch.chunk_type); + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (2); } break; @@ -2479,34 +2487,21 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, /* unknown chunk type, use bit rules */ if (ch->ch.chunk_type & 0x40) { /* Add a error report to the queue */ - struct mbuf *merr; - struct sctp_paramhdr *phd; - - merr = sctp_get_mbuf_for_msg(sizeof(*phd), 0, M_NOWAIT, 1, MT_DATA); - if (merr) { - phd = mtod(merr, struct sctp_paramhdr *); - /* - * We cheat and use param - * type since we did not - * bother to define a error - * cause struct. They are - * the same basic format - * with different names. - */ - phd->param_type = - htons(SCTP_CAUSE_UNRECOG_CHUNK); - phd->param_length = - htons(chk_length + sizeof(*phd)); - SCTP_BUF_LEN(merr) = sizeof(*phd); - SCTP_BUF_NEXT(merr) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT); - if (SCTP_BUF_NEXT(merr)) { - if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(merr), SCTP_SIZE32(chk_length) - chk_length, NULL) == NULL) { - sctp_m_freem(merr); - } else { - sctp_queue_op_err(stcb, merr); - } + struct mbuf *op_err; + struct sctp_gen_error_cause *cause; + + op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause), + 0, M_NOWAIT, 1, MT_DATA); + if (op_err != NULL) { + cause = mtod(op_err, struct sctp_gen_error_cause *); + cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK); + cause->length = htons(chk_length + sizeof(struct sctp_gen_error_cause)); + SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause); + SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT); + if (SCTP_BUF_NEXT(op_err) != NULL) { + sctp_queue_op_err(stcb, op_err); } else { - sctp_m_freem(merr); + sctp_m_freem(op_err); } } } @@ -2768,6 +2763,11 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1 panic("No chunks on the queues for sid %u.", tp1->rec.data.stream_number); #endif } + if ((stcb->asoc.strmout[tp1->rec.data.stream_number].chunks_on_queues == 0) && + (stcb->asoc.strmout[tp1->rec.data.stream_number].state == SCTP_STREAM_RESET_PENDING) && + TAILQ_EMPTY(&stcb->asoc.strmout[tp1->rec.data.stream_number].outqueue)) { + stcb->asoc.trigger_reset = 1; + } tp1->sent = SCTP_DATAGRAM_NR_ACKED; if (tp1->data) { /* @@ -3741,6 +3741,11 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, #endif } } + if ((asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues == 0) && + (asoc->strmout[tp1->rec.data.stream_number].state == SCTP_STREAM_RESET_PENDING) && + TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.stream_number].outqueue)) { + asoc->trigger_reset = 1; + } TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); if (tp1->data) { /* sa_ignore NO_NULL_CHK */ @@ -3989,6 +3994,7 @@ again: op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_26; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + return; } else { struct sctp_nets *netp; @@ -4466,6 +4472,11 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, #endif } } + if ((asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues == 0) && + (asoc->strmout[tp1->rec.data.stream_number].state == SCTP_STREAM_RESET_PENDING) && + TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.stream_number].outqueue)) { + asoc->trigger_reset = 1; + } TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); if (PR_SCTP_ENABLED(tp1->flags)) { if (asoc->pr_sctp_cnt != 0) |