[SCTP]: Implement sac_info field in SCTP_ASSOC_CHANGE notification.
authorVlad Yasevich <vladislav.yasevich@hp.com>
Fri, 23 Mar 2007 18:34:08 +0000 (11:34 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Thu, 26 Apr 2007 05:28:03 +0000 (22:28 -0700)
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: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sctp/ulpevent.h
include/net/sctp/user.h
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/ulpevent.c

index 2923e3d..de88ed5 100644 (file)
@@ -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(
index 80b7afe..1b3153c 100644 (file)
@@ -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];
 };
 
 /*
index 1355674..0a1a197 100644 (file)
@@ -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);
 
-       event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
-                                               (__u16)error, 0, 0,
+       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, 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,
index 438e5dc..e0ec16d 100644 (file)
@@ -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;
 
index 2e11bc8..661ea2d 100644 (file)
@@ -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;
 
-       event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
+       /* 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));
+               if (!event)
+                       goto fail;
+
+               skb = sctp_event2skb(event);
+               sac = (struct sctp_assoc_change *) skb_put(skb,
+                                       sizeof(struct sctp_assoc_change));
+       }
 
        /* Socket Extensions for SCTP
         * 5.3.1.1 SCTP_ASSOC_CHANGE