Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5a35e76 authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller
Browse files

[SCTP]: Implement sac_info field in SCTP_ASSOC_CHANGE notification.



As stated in the sctp socket api draft:

   sac_info: variable

   If the sac_state is SCTP_COMM_LOST and an ABORT chunk was received
   for this association, sac_info[] contains the complete ABORT chunk as
   defined in the SCTP specification RFC2960 [RFC2960] section 3.3.7.

We now save received ABORT chunks into the sac_info field and pass that
to the user.

Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bdf3092a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
	__u16 error,
	__u16 outbound,
	__u16 inbound,
	struct sctp_chunk *chunk,
	gfp_t gfp);

struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
+1 −0
Original line number Diff line number Diff line
@@ -217,6 +217,7 @@ struct sctp_assoc_change {
	__u16 sac_outbound_streams;
	__u16 sac_inbound_streams;
	sctp_assoc_t sac_assoc_id;
	__u8 sac_info[0];
};

/*
+8 −3
Original line number Diff line number Diff line
@@ -464,7 +464,7 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
	struct sctp_ulpevent *event;

	event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC,
						(__u16)error, 0, 0,
						(__u16)error, 0, 0, NULL,
						GFP_ATOMIC);

	if (event)
@@ -492,8 +492,13 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
	/* Cancel any partial delivery in progress. */
	sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);

	if (event_type == SCTP_EVENT_T_CHUNK && subtype.chunk == SCTP_CID_ABORT)
		event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
						(__u16)error, 0, 0,
						(__u16)error, 0, 0, chunk,
						GFP_ATOMIC);
	else
		event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
						(__u16)error, 0, 0, NULL,
						GFP_ATOMIC);
	if (event)
		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+7 −7
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
	 * notification is passed to the upper layer.
	 */
	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
					     0, 0, 0, GFP_ATOMIC);
					     0, 0, 0, NULL, GFP_ATOMIC);
	if (ev)
		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
				SCTP_ULPEVENT(ev));
@@ -661,7 +661,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
	ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0,
					     new_asoc->c.sinit_num_ostreams,
					     new_asoc->c.sinit_max_instreams,
					     GFP_ATOMIC);
					     NULL, GFP_ATOMIC);
	if (!ev)
		goto nomem_ev;

@@ -790,7 +790,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP,
					     0, asoc->c.sinit_num_ostreams,
					     asoc->c.sinit_max_instreams,
					     GFP_ATOMIC);
					     NULL, GFP_ATOMIC);

	if (!ev)
		goto nomem;
@@ -1625,7 +1625,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0,
					     new_asoc->c.sinit_num_ostreams,
					     new_asoc->c.sinit_max_instreams,
					     GFP_ATOMIC);
					     NULL, GFP_ATOMIC);
	if (!ev)
		goto nomem_ev;

@@ -1691,7 +1691,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0,
					     new_asoc->c.sinit_num_ostreams,
					     new_asoc->c.sinit_max_instreams,
					     GFP_ATOMIC);
					     NULL, GFP_ATOMIC);
	if (!ev)
		goto nomem_ev;

@@ -1786,7 +1786,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
					     SCTP_COMM_UP, 0,
					     asoc->c.sinit_num_ostreams,
					     asoc->c.sinit_max_instreams,
					     GFP_ATOMIC);
                                             NULL, GFP_ATOMIC);
		if (!ev)
			goto nomem;

@@ -3035,7 +3035,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
	 * notification is passed to the upper layer.
	 */
	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
					     0, 0, 0, GFP_ATOMIC);
					     0, 0, 0, NULL, GFP_ATOMIC);
	if (!ev)
		goto nomem;

+42 −7
Original line number Diff line number Diff line
@@ -131,19 +131,54 @@ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
	const struct sctp_association *asoc,
	__u16 flags, __u16 state, __u16 error, __u16 outbound,
	__u16 inbound, gfp_t gfp)
	__u16 inbound, struct sctp_chunk *chunk, gfp_t gfp)
{
	struct sctp_ulpevent *event;
	struct sctp_assoc_change *sac;
	struct sk_buff *skb;

	/* If the lower layer passed in the chunk, it will be
	 * an ABORT, so we need to include it in the sac_info.
	 */
	if (chunk) {
		/* sctp_inqu_pop() has allready pulled off the chunk
		 * header.  We need to put it back temporarily
		 */
		skb_push(chunk->skb, sizeof(sctp_chunkhdr_t));

		/* Copy the chunk data to a new skb and reserve enough
		 * head room to use as notification.
		 */
		skb = skb_copy_expand(chunk->skb,
				      sizeof(struct sctp_assoc_change), 0, gfp);

		if (!skb)
			goto fail;

		/* put back the chunk header now that we have a copy */
		skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));

		/* Embed the event fields inside the cloned skb.  */
		event = sctp_skb2event(skb);
		sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);

		/* Include the notification structure */
		sac = (struct sctp_assoc_change *)
			skb_push(skb, sizeof(struct sctp_assoc_change));

		/* Trim the buffer to the right length.  */
		skb_trim(skb, sizeof(struct sctp_assoc_change) +
			 ntohs(chunk->chunk_hdr->length));
	} else {
		event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
				  MSG_NOTIFICATION, gfp);
		if (!event)
			goto fail;

		skb = sctp_event2skb(event);
	sac = (struct sctp_assoc_change *)
		skb_put(skb, sizeof(struct sctp_assoc_change));
		sac = (struct sctp_assoc_change *) skb_put(skb,
					sizeof(struct sctp_assoc_change));
	}

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE