[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: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bdf3092af6
commit
a5a35e7675
|
@ -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 {
|
||||||
__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,
|
||||||
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,
|
||||||
/* 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);
|
||||||
|
|
||||||
event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
|
if (event_type == SCTP_EVENT_T_CHUNK && subtype.chunk == SCTP_CID_ABORT)
|
||||||
(__u16)error, 0, 0,
|
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);
|
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,
|
||||||
* 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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
* 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)
|
||||||
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;
|
||||||
|
|
||||||
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);
|
MSG_NOTIFICATION, gfp);
|
||||||
if (!event)
|
if (!event)
|
||||||
goto fail;
|
goto fail;
|
||||||
skb = sctp_event2skb(event);
|
|
||||||
sac = (struct sctp_assoc_change *)
|
skb = sctp_event2skb(event);
|
||||||
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
|
/* Socket Extensions for SCTP
|
||||||
* 5.3.1.1 SCTP_ASSOC_CHANGE
|
* 5.3.1.1 SCTP_ASSOC_CHANGE
|
||||||
|
|
Loading…
Reference in New Issue