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

[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
...@@ -89,6 +89,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( ...@@ -89,6 +89,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
__u16 error, __u16 error,
__u16 outbound, __u16 outbound,
__u16 inbound, __u16 inbound,
struct sctp_chunk *chunk,
gfp_t gfp); gfp_t gfp);
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
......
...@@ -217,6 +217,7 @@ struct sctp_assoc_change { ...@@ -217,6 +217,7 @@ struct sctp_assoc_change {
__u16 sac_outbound_streams; __u16 sac_outbound_streams;
__u16 sac_inbound_streams; __u16 sac_inbound_streams;
sctp_assoc_t sac_assoc_id; sctp_assoc_t sac_assoc_id;
__u8 sac_info[0];
}; };
/* /*
......
...@@ -464,7 +464,7 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, ...@@ -464,7 +464,7 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC, event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC,
(__u16)error, 0, 0, (__u16)error, 0, 0, NULL,
GFP_ATOMIC); GFP_ATOMIC);
if (event) if (event)
...@@ -492,8 +492,13 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, ...@@ -492,8 +492,13 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
/* Cancel any partial delivery in progress. */ /* Cancel any partial delivery in progress. */
sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); 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, 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); GFP_ATOMIC);
if (event) if (event)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
......
...@@ -186,7 +186,7 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, ...@@ -186,7 +186,7 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
* notification is passed to the upper layer. * notification is passed to the upper layer.
*/ */
ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
0, 0, 0, GFP_ATOMIC); 0, 0, 0, NULL, GFP_ATOMIC);
if (ev) if (ev)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
SCTP_ULPEVENT(ev)); SCTP_ULPEVENT(ev));
...@@ -661,7 +661,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, ...@@ -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, ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0,
new_asoc->c.sinit_num_ostreams, new_asoc->c.sinit_num_ostreams,
new_asoc->c.sinit_max_instreams, new_asoc->c.sinit_max_instreams,
GFP_ATOMIC); NULL, GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem_ev; goto nomem_ev;
...@@ -790,7 +790,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep, ...@@ -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, ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP,
0, asoc->c.sinit_num_ostreams, 0, asoc->c.sinit_num_ostreams,
asoc->c.sinit_max_instreams, asoc->c.sinit_max_instreams,
GFP_ATOMIC); NULL, GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem; goto nomem;
...@@ -1625,7 +1625,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, ...@@ -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, ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0,
new_asoc->c.sinit_num_ostreams, new_asoc->c.sinit_num_ostreams,
new_asoc->c.sinit_max_instreams, new_asoc->c.sinit_max_instreams,
GFP_ATOMIC); NULL, GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem_ev; goto nomem_ev;
...@@ -1691,7 +1691,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, ...@@ -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, ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0,
new_asoc->c.sinit_num_ostreams, new_asoc->c.sinit_num_ostreams,
new_asoc->c.sinit_max_instreams, new_asoc->c.sinit_max_instreams,
GFP_ATOMIC); NULL, GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem_ev; goto nomem_ev;
...@@ -1786,7 +1786,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, ...@@ -1786,7 +1786,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
SCTP_COMM_UP, 0, SCTP_COMM_UP, 0,
asoc->c.sinit_num_ostreams, asoc->c.sinit_num_ostreams,
asoc->c.sinit_max_instreams, asoc->c.sinit_max_instreams,
GFP_ATOMIC); NULL, GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem; goto nomem;
...@@ -3035,7 +3035,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, ...@@ -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. * notification is passed to the upper layer.
*/ */
ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
0, 0, 0, GFP_ATOMIC); 0, 0, 0, NULL, GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem; goto nomem;
......
...@@ -131,19 +131,54 @@ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) ...@@ -131,19 +131,54 @@ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
const struct sctp_association *asoc, const struct sctp_association *asoc,
__u16 flags, __u16 state, __u16 error, __u16 outbound, __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_ulpevent *event;
struct sctp_assoc_change *sac; struct sctp_assoc_change *sac;
struct sk_buff *skb; 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), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, gfp); MSG_NOTIFICATION, gfp);
if (!event) if (!event)
goto fail; goto fail;
skb = sctp_event2skb(event); skb = sctp_event2skb(event);
sac = (struct sctp_assoc_change *) sac = (struct sctp_assoc_change *) skb_put(skb,
skb_put(skb, sizeof(struct sctp_assoc_change)); sizeof(struct sctp_assoc_change));
}
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.1 SCTP_ASSOC_CHANGE * 5.3.1.1 SCTP_ASSOC_CHANGE
......
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