aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2007-03-23 14:34:08 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:28:03 -0400
commita5a35e76753d27e782028843a5186f176b50dd16 (patch)
tree229cd1440150deca3893774dd837e901e88af960
parentbdf3092af601ccad765974652ab103162fbe14f4 (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.h1
-rw-r--r--include/net/sctp/user.h1
-rw-r--r--net/sctp/sm_sideeffect.c11
-rw-r--r--net/sctp/sm_statefuns.c14
-rw-r--r--net/sctp/ulpevent.c49
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
94struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( 95struct 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)
131struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( 131struct 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