Add support for SCTP_SEND_FAILED_EVENT as required by RFC 6458.
MFC after: 3 days
This commit is contained in:
parent
ffbec96825
commit
9935403ae1
@ -526,7 +526,7 @@ struct sctp_error_unrecognized_chunk {
|
||||
#define SCTP_PCB_FLAGS_RECVASSOCEVNT 0x00000800
|
||||
#define SCTP_PCB_FLAGS_RECVPADDREVNT 0x00001000
|
||||
#define SCTP_PCB_FLAGS_RECVPEERERR 0x00002000
|
||||
#define SCTP_PCB_FLAGS_RECVSENDFAILEVNT 0x00004000
|
||||
#define SCTP_PCB_FLAGS_RECVSENDFAILEVNT 0x00004000 /* deprecated */
|
||||
#define SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT 0x00008000
|
||||
#define SCTP_PCB_FLAGS_ADAPTATIONEVNT 0x00010000
|
||||
#define SCTP_PCB_FLAGS_PDAPIEVNT 0x00020000
|
||||
@ -542,6 +542,7 @@ struct sctp_error_unrecognized_chunk {
|
||||
#define SCTP_PCB_FLAGS_RECVNXTINFO 0x10000000
|
||||
#define SCTP_PCB_FLAGS_ASSOC_RESETEVNT 0x20000000
|
||||
#define SCTP_PCB_FLAGS_STREAM_CHANGEEVNT 0x40000000
|
||||
#define SCTP_PCB_FLAGS_RECVNSENDFAILEVNT 0x80000000
|
||||
|
||||
/*-
|
||||
* mobility_features parameters (by micchie).Note
|
||||
|
@ -343,7 +343,7 @@ struct sctp_remote_error {
|
||||
uint8_t sre_data[4];
|
||||
};
|
||||
|
||||
/* data send failure event */
|
||||
/* data send failure event (deprecated) */
|
||||
struct sctp_send_failed {
|
||||
uint16_t ssf_type;
|
||||
uint16_t ssf_flags;
|
||||
@ -354,6 +354,17 @@ struct sctp_send_failed {
|
||||
uint8_t ssf_data[];
|
||||
};
|
||||
|
||||
/* data send failure event (not deprecated) */
|
||||
struct sctp_send_failed_event {
|
||||
uint16_t ssfe_type;
|
||||
uint16_t ssfe_flags;
|
||||
uint32_t ssfe_length;
|
||||
uint32_t ssfe_error;
|
||||
struct sctp_sndinfo ssfe_info;
|
||||
sctp_assoc_t ssfe_assoc_id;
|
||||
uint8_t ssfe_data[];
|
||||
};
|
||||
|
||||
/* flag that indicates state of data */
|
||||
#define SCTP_DATA_UNSENT 0x0001 /* inqueue never on wire */
|
||||
#define SCTP_DATA_SENT 0x0002 /* on wire at failure */
|
||||
@ -513,22 +524,22 @@ union sctp_notification {
|
||||
};
|
||||
|
||||
/* notification types */
|
||||
#define SCTP_ASSOC_CHANGE 0x0001
|
||||
#define SCTP_PEER_ADDR_CHANGE 0x0002
|
||||
#define SCTP_REMOTE_ERROR 0x0003
|
||||
#define SCTP_SEND_FAILED 0x0004
|
||||
#define SCTP_SHUTDOWN_EVENT 0x0005
|
||||
#define SCTP_ADAPTATION_INDICATION 0x0006
|
||||
#define SCTP_ASSOC_CHANGE 0x0001
|
||||
#define SCTP_PEER_ADDR_CHANGE 0x0002
|
||||
#define SCTP_REMOTE_ERROR 0x0003
|
||||
#define SCTP_SEND_FAILED 0x0004
|
||||
#define SCTP_SHUTDOWN_EVENT 0x0005
|
||||
#define SCTP_ADAPTATION_INDICATION 0x0006
|
||||
/* same as above */
|
||||
#define SCTP_ADAPTION_INDICATION 0x0006
|
||||
#define SCTP_PARTIAL_DELIVERY_EVENT 0x0007
|
||||
#define SCTP_AUTHENTICATION_EVENT 0x0008
|
||||
#define SCTP_STREAM_RESET_EVENT 0x0009
|
||||
#define SCTP_SENDER_DRY_EVENT 0x000a
|
||||
#define SCTP_NOTIFICATIONS_STOPPED_EVENT 0x000b /* we don't send this */
|
||||
#define SCTP_ASSOC_RESET_EVENT 0x000c
|
||||
#define SCTP_STREAM_CHANGE_EVENT 0x000d
|
||||
|
||||
#define SCTP_ADAPTION_INDICATION 0x0006
|
||||
#define SCTP_PARTIAL_DELIVERY_EVENT 0x0007
|
||||
#define SCTP_AUTHENTICATION_EVENT 0x0008
|
||||
#define SCTP_STREAM_RESET_EVENT 0x0009
|
||||
#define SCTP_SENDER_DRY_EVENT 0x000a
|
||||
#define SCTP_NOTIFICATIONS_STOPPED_EVENT 0x000b /* we don't send this */
|
||||
#define SCTP_ASSOC_RESET_EVENT 0x000c
|
||||
#define SCTP_STREAM_CHANGE_EVENT 0x000d
|
||||
#define SCTP_SEND_FAILED_EVENT 0x000e
|
||||
/*
|
||||
* socket option structs
|
||||
*/
|
||||
|
@ -2989,6 +2989,9 @@ flags_out:
|
||||
case SCTP_STREAM_CHANGE_EVENT:
|
||||
event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
|
||||
break;
|
||||
case SCTP_SEND_FAILED_EVENT:
|
||||
event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
|
||||
break;
|
||||
default:
|
||||
event_type = 0;
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
@ -5412,6 +5415,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
case SCTP_STREAM_CHANGE_EVENT:
|
||||
event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
|
||||
break;
|
||||
case SCTP_SEND_FAILED_EVENT:
|
||||
event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
|
||||
break;
|
||||
default:
|
||||
event_type = 0;
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
|
@ -2798,39 +2798,66 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
|
||||
{
|
||||
struct mbuf *m_notify;
|
||||
struct sctp_send_failed *ssf;
|
||||
struct sctp_send_failed_event *ssfe;
|
||||
struct sctp_queued_to_read *control;
|
||||
int length;
|
||||
|
||||
if ((stcb == NULL) ||
|
||||
sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
|
||||
(sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
|
||||
sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_send_failed), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
|
||||
length = sizeof(struct sctp_send_failed_event);
|
||||
} else {
|
||||
length = sizeof(struct sctp_send_failed);
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(length, 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
/* no space left */
|
||||
return;
|
||||
length = sizeof(struct sctp_send_failed) + chk->send_size;
|
||||
length += chk->send_size;
|
||||
length -= sizeof(struct sctp_data_chunk);
|
||||
SCTP_BUF_LEN(m_notify) = 0;
|
||||
ssf = mtod(m_notify, struct sctp_send_failed *);
|
||||
ssf->ssf_type = SCTP_SEND_FAILED;
|
||||
if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
|
||||
ssf->ssf_flags = SCTP_DATA_UNSENT;
|
||||
else
|
||||
ssf->ssf_flags = SCTP_DATA_SENT;
|
||||
ssf->ssf_length = length;
|
||||
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_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);
|
||||
|
||||
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
|
||||
ssfe = mtod(m_notify, struct sctp_send_failed_event *);
|
||||
ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
|
||||
if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
|
||||
ssfe->ssfe_flags = SCTP_DATA_UNSENT;
|
||||
else
|
||||
ssfe->ssfe_flags = SCTP_DATA_SENT;
|
||||
ssfe->ssfe_length = length;
|
||||
ssfe->ssfe_error = error;
|
||||
/* not exactly what the user sent in, but should be close :) */
|
||||
bzero(&ssfe->ssfe_info, sizeof(ssfe->ssfe_info));
|
||||
ssfe->ssfe_info.snd_sid = chk->rec.data.stream_number;
|
||||
ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags;
|
||||
ssfe->ssfe_info.snd_ppid = chk->rec.data.payloadtype;
|
||||
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 *);
|
||||
ssf->ssf_type = SCTP_SEND_FAILED;
|
||||
if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
|
||||
ssf->ssf_flags = SCTP_DATA_UNSENT;
|
||||
else
|
||||
ssf->ssf_flags = SCTP_DATA_SENT;
|
||||
ssf->ssf_length = length;
|
||||
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_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)
|
||||
@ -2842,7 +2869,6 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
|
||||
}
|
||||
}
|
||||
SCTP_BUF_NEXT(m_notify) = chk->data;
|
||||
SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
|
||||
/* Steal off the mbuf */
|
||||
chk->data = NULL;
|
||||
/*
|
||||
@ -2882,43 +2908,75 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
|
||||
{
|
||||
struct mbuf *m_notify;
|
||||
struct sctp_send_failed *ssf;
|
||||
struct sctp_send_failed_event *ssfe;
|
||||
struct sctp_queued_to_read *control;
|
||||
int length;
|
||||
|
||||
if ((stcb == NULL) ||
|
||||
sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
|
||||
(sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
|
||||
sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
}
|
||||
length = sizeof(struct sctp_send_failed) + sp->length;
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_send_failed), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
|
||||
length = sizeof(struct sctp_send_failed_event);
|
||||
} else {
|
||||
length = sizeof(struct sctp_send_failed);
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(length, 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL) {
|
||||
/* no space left */
|
||||
return;
|
||||
SCTP_BUF_LEN(m_notify) = 0;
|
||||
ssf = mtod(m_notify, struct sctp_send_failed *);
|
||||
ssf->ssf_type = SCTP_SEND_FAILED;
|
||||
if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
|
||||
ssf->ssf_flags = SCTP_DATA_UNSENT;
|
||||
else
|
||||
ssf->ssf_flags = SCTP_DATA_SENT;
|
||||
ssf->ssf_length = length;
|
||||
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 = sp->stream;
|
||||
ssf->ssf_info.sinfo_ssn = sp->strseq;
|
||||
if (sp->some_taken) {
|
||||
ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG;
|
||||
} else {
|
||||
ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG;
|
||||
}
|
||||
ssf->ssf_info.sinfo_ppid = sp->ppid;
|
||||
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);
|
||||
length += sp->length;
|
||||
SCTP_BUF_LEN(m_notify) = 0;
|
||||
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
|
||||
ssfe = mtod(m_notify, struct sctp_send_failed_event *);
|
||||
ssfe->ssfe_type = SCTP_SEND_FAILED;
|
||||
if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
|
||||
ssfe->ssfe_flags = SCTP_DATA_UNSENT;
|
||||
else
|
||||
ssfe->ssfe_flags = SCTP_DATA_SENT;
|
||||
ssfe->ssfe_length = length;
|
||||
ssfe->ssfe_error = error;
|
||||
/* not exactly what the user sent in, but should be close :) */
|
||||
bzero(&ssfe->ssfe_info, sizeof(ssfe->ssfe_info));
|
||||
ssfe->ssfe_info.snd_sid = sp->stream;
|
||||
if (sp->some_taken) {
|
||||
ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG;
|
||||
} else {
|
||||
ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG;
|
||||
}
|
||||
ssfe->ssfe_info.snd_ppid = sp->ppid;
|
||||
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 *);
|
||||
ssf->ssf_type = SCTP_SEND_FAILED;
|
||||
if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
|
||||
ssf->ssf_flags = SCTP_DATA_UNSENT;
|
||||
else
|
||||
ssf->ssf_flags = SCTP_DATA_SENT;
|
||||
ssf->ssf_length = length;
|
||||
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 = sp->stream;
|
||||
ssf->ssf_info.sinfo_ssn = sp->strseq;
|
||||
if (sp->some_taken) {
|
||||
ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG;
|
||||
} else {
|
||||
ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG;
|
||||
}
|
||||
ssf->ssf_info.sinfo_ppid = sp->ppid;
|
||||
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;
|
||||
SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
|
||||
|
||||
/* Steal off the mbuf */
|
||||
sp->data = NULL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user