diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2007-03-23 14:34:08 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:28:03 -0400 |
commit | a5a35e76753d27e782028843a5186f176b50dd16 (patch) | |
tree | 229cd1440150deca3893774dd837e901e88af960 | |
parent | bdf3092af601ccad765974652ab103162fbe14f4 (diff) |
[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>
-rw-r--r-- | include/net/sctp/ulpevent.h | 1 | ||||
-rw-r--r-- | include/net/sctp/user.h | 1 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 11 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 14 | ||||
-rw-r--r-- | net/sctp/ulpevent.c | 49 |
5 files changed, 59 insertions, 17 deletions
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 2923e3d31a08..de88ed5b0ba6 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h | |||
@@ -89,6 +89,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( | |||
89 | __u16 error, | 89 | __u16 error, |
90 | __u16 outbound, | 90 | __u16 outbound, |
91 | __u16 inbound, | 91 | __u16 inbound, |
92 | struct sctp_chunk *chunk, | ||
92 | gfp_t gfp); | 93 | gfp_t gfp); |
93 | 94 | ||
94 | struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( | 95 | struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( |
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 80b7afea17fc..1b3153c2cdf0 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h | |||
@@ -217,6 +217,7 @@ struct sctp_assoc_change { | |||
217 | __u16 sac_outbound_streams; | 217 | __u16 sac_outbound_streams; |
218 | __u16 sac_inbound_streams; | 218 | __u16 sac_inbound_streams; |
219 | sctp_assoc_t sac_assoc_id; | 219 | sctp_assoc_t sac_assoc_id; |
220 | __u8 sac_info[0]; | ||
220 | }; | 221 | }; |
221 | 222 | ||
222 | /* | 223 | /* |
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 135567493119..0a1a197193a2 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
@@ -464,7 +464,7 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, | |||
464 | struct sctp_ulpevent *event; | 464 | struct sctp_ulpevent *event; |
465 | 465 | ||
466 | event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC, | 466 | event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC, |
467 | (__u16)error, 0, 0, | 467 | (__u16)error, 0, 0, NULL, |
468 | GFP_ATOMIC); | 468 | GFP_ATOMIC); |
469 | 469 | ||
470 | if (event) | 470 | if (event) |
@@ -492,8 +492,13 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, | |||
492 | /* Cancel any partial delivery in progress. */ | 492 | /* Cancel any partial delivery in progress. */ |
493 | sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); | 493 | sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); |
494 | 494 | ||
495 | event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST, | 495 | if (event_type == SCTP_EVENT_T_CHUNK && subtype.chunk == SCTP_CID_ABORT) |
496 | (__u16)error, 0, 0, | 496 | event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST, |
497 | (__u16)error, 0, 0, chunk, | ||
498 | GFP_ATOMIC); | ||
499 | else | ||
500 | event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST, | ||
501 | (__u16)error, 0, 0, NULL, | ||
497 | GFP_ATOMIC); | 502 | GFP_ATOMIC); |
498 | if (event) | 503 | if (event) |
499 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | 504 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 438e5dc5c714..e0ec16dd678a 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -186,7 +186,7 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, | |||
186 | * notification is passed to the upper layer. | 186 | * notification is passed to the upper layer. |
187 | */ | 187 | */ |
188 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, | 188 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, |
189 | 0, 0, 0, GFP_ATOMIC); | 189 | 0, 0, 0, NULL, GFP_ATOMIC); |
190 | if (ev) | 190 | if (ev) |
191 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | 191 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, |
192 | SCTP_ULPEVENT(ev)); | 192 | SCTP_ULPEVENT(ev)); |
@@ -661,7 +661,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
661 | ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0, | 661 | ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0, |
662 | new_asoc->c.sinit_num_ostreams, | 662 | new_asoc->c.sinit_num_ostreams, |
663 | new_asoc->c.sinit_max_instreams, | 663 | new_asoc->c.sinit_max_instreams, |
664 | GFP_ATOMIC); | 664 | NULL, GFP_ATOMIC); |
665 | if (!ev) | 665 | if (!ev) |
666 | goto nomem_ev; | 666 | goto nomem_ev; |
667 | 667 | ||
@@ -790,7 +790,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep, | |||
790 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, | 790 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, |
791 | 0, asoc->c.sinit_num_ostreams, | 791 | 0, asoc->c.sinit_num_ostreams, |
792 | asoc->c.sinit_max_instreams, | 792 | asoc->c.sinit_max_instreams, |
793 | GFP_ATOMIC); | 793 | NULL, GFP_ATOMIC); |
794 | 794 | ||
795 | if (!ev) | 795 | if (!ev) |
796 | goto nomem; | 796 | goto nomem; |
@@ -1625,7 +1625,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, | |||
1625 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, | 1625 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, |
1626 | new_asoc->c.sinit_num_ostreams, | 1626 | new_asoc->c.sinit_num_ostreams, |
1627 | new_asoc->c.sinit_max_instreams, | 1627 | new_asoc->c.sinit_max_instreams, |
1628 | GFP_ATOMIC); | 1628 | NULL, GFP_ATOMIC); |
1629 | if (!ev) | 1629 | if (!ev) |
1630 | goto nomem_ev; | 1630 | goto nomem_ev; |
1631 | 1631 | ||
@@ -1691,7 +1691,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, | |||
1691 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0, | 1691 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0, |
1692 | new_asoc->c.sinit_num_ostreams, | 1692 | new_asoc->c.sinit_num_ostreams, |
1693 | new_asoc->c.sinit_max_instreams, | 1693 | new_asoc->c.sinit_max_instreams, |
1694 | GFP_ATOMIC); | 1694 | NULL, GFP_ATOMIC); |
1695 | if (!ev) | 1695 | if (!ev) |
1696 | goto nomem_ev; | 1696 | goto nomem_ev; |
1697 | 1697 | ||
@@ -1786,7 +1786,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, | |||
1786 | SCTP_COMM_UP, 0, | 1786 | SCTP_COMM_UP, 0, |
1787 | asoc->c.sinit_num_ostreams, | 1787 | asoc->c.sinit_num_ostreams, |
1788 | asoc->c.sinit_max_instreams, | 1788 | asoc->c.sinit_max_instreams, |
1789 | GFP_ATOMIC); | 1789 | NULL, GFP_ATOMIC); |
1790 | if (!ev) | 1790 | if (!ev) |
1791 | goto nomem; | 1791 | goto nomem; |
1792 | 1792 | ||
@@ -3035,7 +3035,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3035 | * notification is passed to the upper layer. | 3035 | * notification is passed to the upper layer. |
3036 | */ | 3036 | */ |
3037 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, | 3037 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, |
3038 | 0, 0, 0, GFP_ATOMIC); | 3038 | 0, 0, 0, NULL, GFP_ATOMIC); |
3039 | if (!ev) | 3039 | if (!ev) |
3040 | goto nomem; | 3040 | goto nomem; |
3041 | 3041 | ||
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 2e11bc8d5d35..661ea2dd78ba 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
@@ -131,19 +131,54 @@ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) | |||
131 | struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( | 131 | struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( |
132 | const struct sctp_association *asoc, | 132 | const struct sctp_association *asoc, |
133 | __u16 flags, __u16 state, __u16 error, __u16 outbound, | 133 | __u16 flags, __u16 state, __u16 error, __u16 outbound, |
134 | __u16 inbound, gfp_t gfp) | 134 | __u16 inbound, struct sctp_chunk *chunk, gfp_t gfp) |
135 | { | 135 | { |
136 | struct sctp_ulpevent *event; | 136 | struct sctp_ulpevent *event; |
137 | struct sctp_assoc_change *sac; | 137 | struct sctp_assoc_change *sac; |
138 | struct sk_buff *skb; | 138 | struct sk_buff *skb; |
139 | 139 | ||
140 | event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), | 140 | /* If the lower layer passed in the chunk, it will be |
141 | * an ABORT, so we need to include it in the sac_info. | ||
142 | */ | ||
143 | if (chunk) { | ||
144 | /* sctp_inqu_pop() has allready pulled off the chunk | ||
145 | * header. We need to put it back temporarily | ||
146 | */ | ||
147 | skb_push(chunk->skb, sizeof(sctp_chunkhdr_t)); | ||
148 | |||
149 | /* Copy the chunk data to a new skb and reserve enough | ||
150 | * head room to use as notification. | ||
151 | */ | ||
152 | skb = skb_copy_expand(chunk->skb, | ||
153 | sizeof(struct sctp_assoc_change), 0, gfp); | ||
154 | |||
155 | if (!skb) | ||
156 | goto fail; | ||
157 | |||
158 | /* put back the chunk header now that we have a copy */ | ||
159 | skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); | ||
160 | |||
161 | /* Embed the event fields inside the cloned skb. */ | ||
162 | event = sctp_skb2event(skb); | ||
163 | sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); | ||
164 | |||
165 | /* Include the notification structure */ | ||
166 | sac = (struct sctp_assoc_change *) | ||
167 | skb_push(skb, sizeof(struct sctp_assoc_change)); | ||
168 | |||
169 | /* Trim the buffer to the right length. */ | ||
170 | skb_trim(skb, sizeof(struct sctp_assoc_change) + | ||
171 | ntohs(chunk->chunk_hdr->length)); | ||
172 | } else { | ||
173 | event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), | ||
141 | MSG_NOTIFICATION, gfp); | 174 | MSG_NOTIFICATION, gfp); |
142 | if (!event) | 175 | if (!event) |
143 | goto fail; | 176 | goto fail; |
144 | skb = sctp_event2skb(event); | 177 | |
145 | sac = (struct sctp_assoc_change *) | 178 | skb = sctp_event2skb(event); |
146 | skb_put(skb, sizeof(struct sctp_assoc_change)); | 179 | sac = (struct sctp_assoc_change *) skb_put(skb, |
180 | sizeof(struct sctp_assoc_change)); | ||
181 | } | ||
147 | 182 | ||
148 | /* Socket Extensions for SCTP | 183 | /* Socket Extensions for SCTP |
149 | * 5.3.1.1 SCTP_ASSOC_CHANGE | 184 | * 5.3.1.1 SCTP_ASSOC_CHANGE |