From ab3373140d5a523ba15561ba7b5f115972228ef2 Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Sun, 26 Jun 2016 16:38:42 +0000 Subject: [PATCH] This patch fixes two bugs related to the SCTP message recovery for messages which have been put on the send queue: * Do not report any DATA or I-DATA chunk padding. * Correctly deal with the I-DATA chunk header instead of the DATA chunk header when the I-DATA extension is used. Approved by: re (kib) MFC after: 1 week --- sys/netinet/sctputil.c | 87 ++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 5dbd741ebf3..15c2dd18a88 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -2933,7 +2933,8 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, struct sctp_send_failed *ssf; struct sctp_send_failed_event *ssfe; struct sctp_queued_to_read *control; - int length; + struct sctp_chunkhdr *chkhdr; + int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len; if ((stcb == NULL) || (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && @@ -2942,27 +2943,49 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, return; } if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { - length = sizeof(struct sctp_send_failed_event); + notifhdr_len = sizeof(struct sctp_send_failed_event); } else { - length = sizeof(struct sctp_send_failed); + notifhdr_len = sizeof(struct sctp_send_failed); } - m_notify = sctp_get_mbuf_for_msg(length, 0, M_NOWAIT, 1, MT_DATA); + m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) /* no space left */ return; - SCTP_BUF_LEN(m_notify) = 0; + SCTP_BUF_LEN(m_notify) = notifhdr_len; + if (stcb->asoc.idata_supported) { + chkhdr_len = sizeof(struct sctp_idata_chunk); + } else { + chkhdr_len = sizeof(struct sctp_data_chunk); + } + /* Use some defaults in case we can't access the chunk header */ + if (chk->send_size >= chkhdr_len) { + payload_len = chk->send_size - chkhdr_len; + } else { + payload_len = 0; + } + padding_len = 0; + if (chk->data != NULL) { + chkhdr = mtod(chk->data, struct sctp_chunkhdr *); + if (chkhdr != NULL) { + chk_len = ntohs(chkhdr->chunk_length); + if ((chk_len >= chkhdr_len) && + (chk->send_size >= chk_len) && + (chk->send_size - chk_len < 4)) { + padding_len = chk->send_size - chk_len; + payload_len = chk->send_size - chkhdr_len - padding_len; + } + } + } if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { ssfe = mtod(m_notify, struct sctp_send_failed_event *); - memset(ssfe, 0, length); + memset(ssfe, 0, notifhdr_len); ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; if (sent) { ssfe->ssfe_flags = SCTP_DATA_SENT; } else { ssfe->ssfe_flags = SCTP_DATA_UNSENT; } - length += chk->send_size; - length -= sizeof(struct sctp_data_chunk); - ssfe->ssfe_length = length; + ssfe->ssfe_length = (uint32_t) (notifhdr_len + payload_len); ssfe->ssfe_error = error; /* not exactly what the user sent in, but should be close :) */ ssfe->ssfe_info.snd_sid = chk->rec.data.stream_number; @@ -2971,39 +2994,33 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, ssfe->ssfe_info.snd_context = chk->rec.data.context; ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); ssfe->ssfe_assoc_id = sctp_get_associd(stcb); - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event); } else { ssf = mtod(m_notify, struct sctp_send_failed *); - memset(ssf, 0, length); + memset(ssf, 0, notifhdr_len); ssf->ssf_type = SCTP_SEND_FAILED; if (sent) { ssf->ssf_flags = SCTP_DATA_SENT; } else { ssf->ssf_flags = SCTP_DATA_UNSENT; } - length += chk->send_size; - length -= sizeof(struct sctp_data_chunk); - ssf->ssf_length = length; + ssf->ssf_length = (uint32_t) (notifhdr_len + payload_len); ssf->ssf_error = error; /* not exactly what the user sent in, but should be close :) */ - bzero(&ssf->ssf_info, sizeof(ssf->ssf_info)); ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number; - ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq; + ssf->ssf_info.sinfo_ssn = (uint16_t) chk->rec.data.stream_seq; ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags; ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype; ssf->ssf_info.sinfo_context = chk->rec.data.context; ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); ssf->ssf_assoc_id = sctp_get_associd(stcb); - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed); } - if (chk->data) { - /* - * trim off the sctp chunk header(it should be there) - */ - if (chk->send_size >= sizeof(struct sctp_data_chunk)) { - m_adj(chk->data, sizeof(struct sctp_data_chunk)); + if (chk->data != NULL) { + /* Trim off the sctp chunk header (it should be there) */ + if (chk->send_size == chkhdr_len + payload_len + padding_len) { + m_adj(chk->data, chkhdr_len); + m_adj(chk->data, -padding_len); sctp_mbuf_crush(chk->data); - chk->send_size -= sizeof(struct sctp_data_chunk); + chk->send_size -= (chkhdr_len + padding_len); } } SCTP_BUF_NEXT(m_notify) = chk->data; @@ -3048,7 +3065,7 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, struct sctp_send_failed *ssf; struct sctp_send_failed_event *ssfe; struct sctp_queued_to_read *control; - int length; + int notifhdr_len; if ((stcb == NULL) || (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && @@ -3057,23 +3074,22 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, return; } if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { - length = sizeof(struct sctp_send_failed_event); + notifhdr_len = sizeof(struct sctp_send_failed_event); } else { - length = sizeof(struct sctp_send_failed); + notifhdr_len = sizeof(struct sctp_send_failed); } - m_notify = sctp_get_mbuf_for_msg(length, 0, M_NOWAIT, 1, MT_DATA); + m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) { /* no space left */ return; } - SCTP_BUF_LEN(m_notify) = 0; + SCTP_BUF_LEN(m_notify) = notifhdr_len; if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { ssfe = mtod(m_notify, struct sctp_send_failed_event *); - memset(ssfe, 0, length); + memset(ssfe, 0, notifhdr_len); ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; ssfe->ssfe_flags = SCTP_DATA_UNSENT; - length += sp->length; - ssfe->ssfe_length = length; + ssfe->ssfe_length = (uint32_t) (notifhdr_len + sp->length); ssfe->ssfe_error = error; /* not exactly what the user sent in, but should be close :) */ ssfe->ssfe_info.snd_sid = sp->stream; @@ -3086,14 +3102,12 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, ssfe->ssfe_info.snd_context = sp->context; ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); ssfe->ssfe_assoc_id = sctp_get_associd(stcb); - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event); } else { ssf = mtod(m_notify, struct sctp_send_failed *); - memset(ssf, 0, length); + memset(ssf, 0, notifhdr_len); ssf->ssf_type = SCTP_SEND_FAILED; ssf->ssf_flags = SCTP_DATA_UNSENT; - length += sp->length; - ssf->ssf_length = length; + ssf->ssf_length = (uint32_t) (notifhdr_len + sp->length); ssf->ssf_error = error; /* not exactly what the user sent in, but should be close :) */ ssf->ssf_info.sinfo_stream = sp->stream; @@ -3107,7 +3121,6 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, ssf->ssf_info.sinfo_context = sp->context; ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); ssf->ssf_assoc_id = sctp_get_associd(stcb); - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed); } SCTP_BUF_NEXT(m_notify) = sp->data; -- 2.45.2