Commit b2d8c273 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -80,13 +80,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
	struct sctp_chunk *chunk,
	gfp_t gfp);

struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
	const struct sctp_association *asoc,
	const struct sockaddr_storage *aaddr,
	int flags,
	int state,
	int error,
	gfp_t gfp);
void sctp_ulpevent_nofity_peer_addr_change(struct sctp_transport *transport,
					   int state, int error);

struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
	const struct sctp_association *asoc,
@@ -100,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,
+15 −1
Original line number Diff line number Diff line
@@ -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
};

+9 −13
Original line number Diff line number Diff line
@@ -429,6 +429,8 @@ void sctp_assoc_set_primary(struct sctp_association *asoc,
		changeover = 1 ;

	asoc->peer.primary_path = transport;
	sctp_ulpevent_nofity_peer_addr_change(transport,
					      SCTP_ADDR_MADE_PRIM, 0);

	/* Set a default msg_name for events. */
	memcpy(&asoc->peer.primary_addr, &transport->ipaddr,
@@ -569,6 +571,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,

	asoc->peer.transport_count--;

	sctp_ulpevent_nofity_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
	sctp_transport_free(peer);
}

@@ -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);
	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 (!asoc->peer.primary_path) {
		sctp_assoc_set_primary(asoc, peer);
@@ -781,10 +786,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
				  enum sctp_transport_cmd command,
				  sctp_sn_error_t error)
{
	struct sctp_ulpevent *event;
	struct sockaddr_storage addr;
	int spc_state = 0;
	bool ulp_notify = true;
	int spc_state = 0;

	/* Record the transition on the transport.  */
	switch (command) {
@@ -836,16 +839,9 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
	/* Generate and send a SCTP_PEER_ADDR_CHANGE notification
	 * to the user.
	 */
	if (ulp_notify) {
		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, spc_state, error, GFP_ATOMIC);
		if (event)
			asoc->stream.si->enqueue_event(&asoc->ulpq, event);
	}
	if (ulp_notify)
		sctp_ulpevent_nofity_peer_addr_change(transport,
						      spc_state, error);

	/* Select new active and retran paths. */
	sctp_select_active_and_retran_path(asoc);
+19 −21
Original line number Diff line number Diff line
@@ -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);
	}

+56 −1
Original line number Diff line number Diff line
@@ -238,7 +238,7 @@ fail:
 * When a destination address on a multi-homed peer encounters a change
 * 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 sockaddr_storage *aaddr,
	int flags, int state, int error, gfp_t gfp)
@@ -336,6 +336,22 @@ fail:
	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.
 *
 * Note: This assumes that the chunk->skb->data already points to the
@@ -511,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