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
This commit is contained in:
Michael Tuexen 2016-06-26 16:38:42 +00:00
parent 6ee52c658c
commit ab3373140d

View File

@ -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;