summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2016-06-26 16:38:42 +0000
committertuexen <tuexen@FreeBSD.org>2016-06-26 16:38:42 +0000
commit5c0864eed07c61b722acd5d913db1d433b6fbfe9 (patch)
tree550b541311a526d24d31bc739e79ad579f9cb887 /sys/netinet/sctputil.c
parentbb60d9d56b5b703b57e4eda44e5c5197a368d2ef (diff)
downloadFreeBSD-src-5c0864eed07c61b722acd5d913db1d433b6fbfe9.zip
FreeBSD-src-5c0864eed07c61b722acd5d913db1d433b6fbfe9.tar.gz
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
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r--sys/netinet/sctputil.c87
1 files changed, 50 insertions, 37 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 5dbd741..15c2dd1 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;
OpenPOWER on IntegriCloud