Commit b2d8c273 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'sctp-add-some-missing-events-from-rfc5061'

Xin Long says:
====================
There are 4 events defined in rfc5061 missed in linux sctp:
SCTP_ADDR_ADDED, SCTP_ADDR_REMOVED, SCTP_ADDR_MADE_PRIM and
SCTP_SEND_FAILED_EVENT.

This patchset is to add them up.
====================
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
parents 75792624 b6e6b5f1
...@@ -80,13 +80,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( ...@@ -80,13 +80,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
struct sctp_chunk *chunk, struct sctp_chunk *chunk,
gfp_t gfp); gfp_t gfp);
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( void sctp_ulpevent_nofity_peer_addr_change(struct sctp_transport *transport,
const struct sctp_association *asoc, int state, int error);
const struct sockaddr_storage *aaddr,
int flags,
int state,
int error,
gfp_t gfp);
struct sctp_ulpevent *sctp_ulpevent_make_remote_error( struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
const struct sctp_association *asoc, const struct sctp_association *asoc,
...@@ -100,6 +95,13 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -100,6 +95,13 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
__u32 error, __u32 error,
gfp_t gfp); 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( struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
const struct sctp_association *asoc, const struct sctp_association *asoc,
__u16 flags, __u16 flags,
......
...@@ -449,6 +449,16 @@ struct sctp_send_failed { ...@@ -449,6 +449,16 @@ struct sctp_send_failed {
__u8 ssf_data[0]; __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) * ssf_flags: 16 bits (unsigned integer)
* *
...@@ -605,6 +615,7 @@ struct sctp_event_subscribe { ...@@ -605,6 +615,7 @@ struct sctp_event_subscribe {
__u8 sctp_stream_reset_event; __u8 sctp_stream_reset_event;
__u8 sctp_assoc_reset_event; __u8 sctp_assoc_reset_event;
__u8 sctp_stream_change_event; __u8 sctp_stream_change_event;
__u8 sctp_send_failure_event_event;
}; };
/* /*
...@@ -632,6 +643,7 @@ union sctp_notification { ...@@ -632,6 +643,7 @@ union sctp_notification {
struct sctp_stream_reset_event sn_strreset_event; struct sctp_stream_reset_event sn_strreset_event;
struct sctp_assoc_reset_event sn_assocreset_event; struct sctp_assoc_reset_event sn_assocreset_event;
struct sctp_stream_change_event sn_strchange_event; struct sctp_stream_change_event sn_strchange_event;
struct sctp_send_failed_event sn_send_failed_event;
}; };
/* Section 5.3.1 /* Section 5.3.1
...@@ -667,7 +679,9 @@ enum sctp_sn_type { ...@@ -667,7 +679,9 @@ enum sctp_sn_type {
#define SCTP_ASSOC_RESET_EVENT SCTP_ASSOC_RESET_EVENT #define SCTP_ASSOC_RESET_EVENT SCTP_ASSOC_RESET_EVENT
SCTP_STREAM_CHANGE_EVENT, SCTP_STREAM_CHANGE_EVENT,
#define SCTP_STREAM_CHANGE_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 #define SCTP_SN_TYPE_MAX SCTP_SN_TYPE_MAX
}; };
......
...@@ -429,6 +429,8 @@ void sctp_assoc_set_primary(struct sctp_association *asoc, ...@@ -429,6 +429,8 @@ void sctp_assoc_set_primary(struct sctp_association *asoc,
changeover = 1 ; changeover = 1 ;
asoc->peer.primary_path = transport; asoc->peer.primary_path = transport;
sctp_ulpevent_nofity_peer_addr_change(transport,
SCTP_ADDR_MADE_PRIM, 0);
/* Set a default msg_name for events. */ /* Set a default msg_name for events. */
memcpy(&asoc->peer.primary_addr, &transport->ipaddr, memcpy(&asoc->peer.primary_addr, &transport->ipaddr,
...@@ -569,6 +571,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, ...@@ -569,6 +571,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
asoc->peer.transport_count--; asoc->peer.transport_count--;
sctp_ulpevent_nofity_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
sctp_transport_free(peer); sctp_transport_free(peer);
} }
...@@ -707,6 +710,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -707,6 +710,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list); list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
asoc->peer.transport_count++; asoc->peer.transport_count++;
sctp_ulpevent_nofity_peer_addr_change(peer, SCTP_ADDR_ADDED, 0);
/* If we do not yet have a primary path, set one. */ /* If we do not yet have a primary path, set one. */
if (!asoc->peer.primary_path) { if (!asoc->peer.primary_path) {
sctp_assoc_set_primary(asoc, peer); sctp_assoc_set_primary(asoc, peer);
...@@ -781,10 +786,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, ...@@ -781,10 +786,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
enum sctp_transport_cmd command, enum sctp_transport_cmd command,
sctp_sn_error_t error) sctp_sn_error_t error)
{ {
struct sctp_ulpevent *event;
struct sockaddr_storage addr;
int spc_state = 0;
bool ulp_notify = true; bool ulp_notify = true;
int spc_state = 0;
/* Record the transition on the transport. */ /* Record the transition on the transport. */
switch (command) { switch (command) {
...@@ -836,16 +839,9 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, ...@@ -836,16 +839,9 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
/* Generate and send a SCTP_PEER_ADDR_CHANGE notification /* Generate and send a SCTP_PEER_ADDR_CHANGE notification
* to the user. * to the user.
*/ */
if (ulp_notify) { if (ulp_notify)
memset(&addr, 0, sizeof(struct sockaddr_storage)); sctp_ulpevent_nofity_peer_addr_change(transport,
memcpy(&addr, &transport->ipaddr, spc_state, error);
transport->af_specific->sockaddr_len);
event = sctp_ulpevent_make_peer_addr_change(asoc, &addr,
0, spc_state, error, GFP_ATOMIC);
if (event)
asoc->stream.si->enqueue_event(&asoc->ulpq, event);
}
/* Select new active and retran paths. */ /* Select new active and retran paths. */
sctp_select_active_and_retran_path(asoc); sctp_select_active_and_retran_path(asoc);
......
...@@ -75,41 +75,39 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg) ...@@ -75,41 +75,39 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
struct list_head *pos, *temp; struct list_head *pos, *temp;
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
struct sctp_ulpevent *ev; struct sctp_ulpevent *ev;
int error = 0, notify; int error, sent;
/* If we failed, we may need to notify. */
notify = msg->send_failed ? -1 : 0;
/* Release all references. */ /* Release all references. */
list_for_each_safe(pos, temp, &msg->chunks) { list_for_each_safe(pos, temp, &msg->chunks) {
list_del_init(pos); list_del_init(pos);
chunk = list_entry(pos, struct sctp_chunk, frag_list); chunk = list_entry(pos, struct sctp_chunk, frag_list);
/* Check whether we _really_ need to notify. */
if (notify < 0) { if (!msg->send_failed) {
asoc = chunk->asoc; sctp_chunk_put(chunk);
if (msg->send_error) continue;
error = msg->send_error;
else
error = asoc->outqueue.error;
notify = sctp_ulpevent_type_enabled(asoc->subscribe,
SCTP_SEND_FAILED);
} }
/* Generate a SEND FAILED event only if enabled. */ asoc = chunk->asoc;
if (notify > 0) { error = msg->send_error ?: asoc->outqueue.error;
int sent; sent = chunk->has_tsn ? SCTP_DATA_SENT : SCTP_DATA_UNSENT;
if (chunk->has_tsn)
sent = SCTP_DATA_SENT;
else
sent = SCTP_DATA_UNSENT;
if (sctp_ulpevent_type_enabled(asoc->subscribe,
SCTP_SEND_FAILED)) {
ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent, ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent,
error, GFP_ATOMIC); error, GFP_ATOMIC);
if (ev) if (ev)
asoc->stream.si->enqueue_event(&asoc->ulpq, 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); sctp_chunk_put(chunk);
} }
......
...@@ -238,7 +238,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( ...@@ -238,7 +238,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
* When a destination address on a multi-homed peer encounters a change * When a destination address on a multi-homed peer encounters a change
* an interface details event is sent. * an interface details event is sent.
*/ */
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( static struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
const struct sctp_association *asoc, const struct sctp_association *asoc,
const struct sockaddr_storage *aaddr, const struct sockaddr_storage *aaddr,
int flags, int state, int error, gfp_t gfp) int flags, int state, int error, gfp_t gfp)
...@@ -336,6 +336,22 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( ...@@ -336,6 +336,22 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
return NULL; return NULL;
} }
void sctp_ulpevent_nofity_peer_addr_change(struct sctp_transport *transport,
int state, int error)
{
struct sctp_association *asoc = transport->asoc;
struct sockaddr_storage addr;
struct sctp_ulpevent *event;
memset(&addr, 0, sizeof(struct sockaddr_storage));
memcpy(&addr, &transport->ipaddr, transport->af_specific->sockaddr_len);
event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, 0, state,
error, GFP_ATOMIC);
if (event)
asoc->stream.si->enqueue_event(&asoc->ulpq, event);
}
/* Create and initialize an SCTP_REMOTE_ERROR notification. /* Create and initialize an SCTP_REMOTE_ERROR notification.
* *
* Note: This assumes that the chunk->skb->data already points to the * Note: This assumes that the chunk->skb->data already points to the
...@@ -511,6 +527,45 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -511,6 +527,45 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
return NULL; 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. /* Create and initialize a SCTP_SHUTDOWN_EVENT notification.
* *
* Socket Extensions for SCTP - draft-01 * Socket Extensions for SCTP - draft-01
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment