Support SCTP_REMOTE_ERROR notification.

MFC after: 3 days
This commit is contained in:
Michael Tuexen 2012-05-13 22:27:54 +00:00
parent 1edc9dbae5
commit 389b1b118c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=235418
3 changed files with 68 additions and 1 deletions

View File

@ -765,6 +765,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_NOTIFY_AUTH_FREE_KEY 24
#define SCTP_NOTIFY_NO_PEER_AUTH 25
#define SCTP_NOTIFY_SENDER_DRY 26
#define SCTP_NOTIFY_REMOTE_ERROR 27
/* This is the value for messages that are NOT completely
* copied down where we will start to split the message.

View File

@ -1111,7 +1111,7 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
{
int chklen;
struct sctp_paramhdr *phdr;
uint16_t error_type;
uint16_t error, error_type;
uint16_t error_len;
struct sctp_association *asoc;
int adjust;
@ -1126,6 +1126,7 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
phdr = (struct sctp_paramhdr *)((caddr_t)ch +
sizeof(struct sctp_chunkhdr));
chklen = ntohs(ch->chunk_length) - sizeof(struct sctp_chunkhdr);
error = 0;
while ((size_t)chklen >= sizeof(struct sctp_paramhdr)) {
/* Process an Error Cause */
error_type = ntohs(phdr->param_type);
@ -1136,6 +1137,10 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
chklen, error_len);
return (0);
}
if (error == 0) {
/* report the first error cause */
error = error_type;
}
switch (error_type) {
case SCTP_CAUSE_INVALID_STREAM:
case SCTP_CAUSE_MISSING_PARAM:
@ -1252,6 +1257,7 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
chklen -= adjust;
phdr = (struct sctp_paramhdr *)((caddr_t)phdr + adjust);
}
sctp_ulp_notify(SCTP_NOTIFY_REMOTE_ERROR, stcb, error, ch, SCTP_SO_NOT_LOCKED);
return (0);
}

View File

@ -3464,6 +3464,63 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
}
static void
sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk)
{
struct mbuf *m_notify;
struct sctp_remote_error *sre;
struct sctp_queued_to_read *control;
size_t notif_len, chunk_len;
if ((stcb == NULL) ||
sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) {
return;
}
if (chunk != NULL) {
chunk_len = htons(chunk->ch.chunk_length);
} else {
chunk_len = 0;
}
notif_len = sizeof(struct sctp_remote_error) + chunk_len;
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
if (m_notify == NULL) {
/* Retry with smaller value. */
notif_len = sizeof(struct sctp_remote_error);
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
if (m_notify == NULL) {
return;
}
}
SCTP_BUF_NEXT(m_notify) = NULL;
sre = mtod(m_notify, struct sctp_remote_error *);
sre->sre_type = SCTP_REMOTE_ERROR;
sre->sre_flags = 0;
sre->sre_length = sizeof(struct sctp_remote_error);
sre->sre_error = error;
sre->sre_assoc_id = sctp_get_associd(stcb);
if (notif_len > sizeof(struct sctp_remote_error)) {
memcpy(sre->sre_data, chunk, chunk_len);
sre->sre_length += chunk_len;
}
SCTP_BUF_LEN(m_notify) = sre->sre_length;
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control != NULL) {
control->length = SCTP_BUF_LEN(m_notify);
/* not that we need this */
control->tail_mbuf = m_notify;
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1,
SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
} else {
sctp_m_freem(m_notify);
}
}
void
sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
uint32_t error, void *data, int so_locked
@ -3634,6 +3691,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
case SCTP_NOTIFY_SENDER_DRY:
sctp_notify_sender_dry_event(stcb, so_locked);
break;
case SCTP_NOTIFY_REMOTE_ERROR:
sctp_notify_remote_error(stcb, error, data);
break;
default:
SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n",
__FUNCTION__, notification, notification);