mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
sctp: add SCTP_SEND_FAILED_EVENT event
This patch is to add a new event SCTP_SEND_FAILED_EVENT described in rfc6458#section-6.1.11. It's a update of SCTP_SEND_FAILED event: struct sctp_sndrcvinfo ssf_info is replaced with struct sctp_sndinfo ssfe_info in struct sctp_send_failed_event. SCTP_SEND_FAILED is being deprecated, but we don't remove it in this patch. Both are being processed in sctp_datamsg_destroy() when the corresp event flag is set. Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
This commit is contained in:
parent
5cd0b91733
commit
b6e6b5f1da
@ -95,6 +95,13 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
|
||||
__u32 error,
|
||||
gfp_t gfp);
|
||||
|
||||
struct sctp_ulpevent *sctp_ulpevent_make_send_failed_event(
|
||||
const struct sctp_association *asoc,
|
||||
struct sctp_chunk *chunk,
|
||||
__u16 flags,
|
||||
__u32 error,
|
||||
gfp_t gfp);
|
||||
|
||||
struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
|
||||
const struct sctp_association *asoc,
|
||||
__u16 flags,
|
||||
|
@ -449,6 +449,16 @@ struct sctp_send_failed {
|
||||
__u8 ssf_data[0];
|
||||
};
|
||||
|
||||
struct sctp_send_failed_event {
|
||||
__u16 ssf_type;
|
||||
__u16 ssf_flags;
|
||||
__u32 ssf_length;
|
||||
__u32 ssf_error;
|
||||
struct sctp_sndinfo ssfe_info;
|
||||
sctp_assoc_t ssf_assoc_id;
|
||||
__u8 ssf_data[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* ssf_flags: 16 bits (unsigned integer)
|
||||
*
|
||||
@ -605,6 +615,7 @@ struct sctp_event_subscribe {
|
||||
__u8 sctp_stream_reset_event;
|
||||
__u8 sctp_assoc_reset_event;
|
||||
__u8 sctp_stream_change_event;
|
||||
__u8 sctp_send_failure_event_event;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -632,6 +643,7 @@ union sctp_notification {
|
||||
struct sctp_stream_reset_event sn_strreset_event;
|
||||
struct sctp_assoc_reset_event sn_assocreset_event;
|
||||
struct sctp_stream_change_event sn_strchange_event;
|
||||
struct sctp_send_failed_event sn_send_failed_event;
|
||||
};
|
||||
|
||||
/* Section 5.3.1
|
||||
@ -667,7 +679,9 @@ enum sctp_sn_type {
|
||||
#define SCTP_ASSOC_RESET_EVENT SCTP_ASSOC_RESET_EVENT
|
||||
SCTP_STREAM_CHANGE_EVENT,
|
||||
#define SCTP_STREAM_CHANGE_EVENT SCTP_STREAM_CHANGE_EVENT
|
||||
SCTP_SN_TYPE_MAX = SCTP_STREAM_CHANGE_EVENT,
|
||||
SCTP_SEND_FAILED_EVENT,
|
||||
#define SCTP_SEND_FAILED_EVENT SCTP_SEND_FAILED_EVENT
|
||||
SCTP_SN_TYPE_MAX = SCTP_SEND_FAILED_EVENT,
|
||||
#define SCTP_SN_TYPE_MAX SCTP_SN_TYPE_MAX
|
||||
};
|
||||
|
||||
|
@ -75,41 +75,39 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
|
||||
struct list_head *pos, *temp;
|
||||
struct sctp_chunk *chunk;
|
||||
struct sctp_ulpevent *ev;
|
||||
int error = 0, notify;
|
||||
|
||||
/* If we failed, we may need to notify. */
|
||||
notify = msg->send_failed ? -1 : 0;
|
||||
int error, sent;
|
||||
|
||||
/* Release all references. */
|
||||
list_for_each_safe(pos, temp, &msg->chunks) {
|
||||
list_del_init(pos);
|
||||
chunk = list_entry(pos, struct sctp_chunk, frag_list);
|
||||
/* Check whether we _really_ need to notify. */
|
||||
if (notify < 0) {
|
||||
asoc = chunk->asoc;
|
||||
if (msg->send_error)
|
||||
error = msg->send_error;
|
||||
else
|
||||
error = asoc->outqueue.error;
|
||||
|
||||
notify = sctp_ulpevent_type_enabled(asoc->subscribe,
|
||||
SCTP_SEND_FAILED);
|
||||
if (!msg->send_failed) {
|
||||
sctp_chunk_put(chunk);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Generate a SEND FAILED event only if enabled. */
|
||||
if (notify > 0) {
|
||||
int sent;
|
||||
if (chunk->has_tsn)
|
||||
sent = SCTP_DATA_SENT;
|
||||
else
|
||||
sent = SCTP_DATA_UNSENT;
|
||||
asoc = chunk->asoc;
|
||||
error = msg->send_error ?: asoc->outqueue.error;
|
||||
sent = chunk->has_tsn ? SCTP_DATA_SENT : SCTP_DATA_UNSENT;
|
||||
|
||||
if (sctp_ulpevent_type_enabled(asoc->subscribe,
|
||||
SCTP_SEND_FAILED)) {
|
||||
ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent,
|
||||
error, GFP_ATOMIC);
|
||||
if (ev)
|
||||
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
|
||||
}
|
||||
|
||||
if (sctp_ulpevent_type_enabled(asoc->subscribe,
|
||||
SCTP_SEND_FAILED_EVENT)) {
|
||||
ev = sctp_ulpevent_make_send_failed_event(asoc, chunk,
|
||||
sent, error,
|
||||
GFP_ATOMIC);
|
||||
if (ev)
|
||||
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
|
||||
}
|
||||
|
||||
sctp_chunk_put(chunk);
|
||||
}
|
||||
|
||||
|
@ -527,6 +527,45 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sctp_ulpevent *sctp_ulpevent_make_send_failed_event(
|
||||
const struct sctp_association *asoc, struct sctp_chunk *chunk,
|
||||
__u16 flags, __u32 error, gfp_t gfp)
|
||||
{
|
||||
struct sctp_send_failed_event *ssf;
|
||||
struct sctp_ulpevent *event;
|
||||
struct sk_buff *skb;
|
||||
int len;
|
||||
|
||||
skb = skb_copy_expand(chunk->skb, sizeof(*ssf), 0, gfp);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
len = ntohs(chunk->chunk_hdr->length);
|
||||
len -= sctp_datachk_len(&asoc->stream);
|
||||
|
||||
skb_pull(skb, sctp_datachk_len(&asoc->stream));
|
||||
event = sctp_skb2event(skb);
|
||||
sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
|
||||
|
||||
ssf = skb_push(skb, sizeof(*ssf));
|
||||
ssf->ssf_type = SCTP_SEND_FAILED_EVENT;
|
||||
ssf->ssf_flags = flags;
|
||||
ssf->ssf_length = sizeof(*ssf) + len;
|
||||
skb_trim(skb, ssf->ssf_length);
|
||||
ssf->ssf_error = error;
|
||||
|
||||
ssf->ssfe_info.snd_sid = chunk->sinfo.sinfo_stream;
|
||||
ssf->ssfe_info.snd_ppid = chunk->sinfo.sinfo_ppid;
|
||||
ssf->ssfe_info.snd_context = chunk->sinfo.sinfo_context;
|
||||
ssf->ssfe_info.snd_assoc_id = chunk->sinfo.sinfo_assoc_id;
|
||||
ssf->ssfe_info.snd_flags = chunk->chunk_hdr->flags;
|
||||
|
||||
sctp_ulpevent_set_owner(event, asoc);
|
||||
ssf->ssf_assoc_id = sctp_assoc2id(asoc);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/* Create and initialize a SCTP_SHUTDOWN_EVENT notification.
|
||||
*
|
||||
* Socket Extensions for SCTP - draft-01
|
||||
|
Loading…
Reference in New Issue
Block a user