summaryrefslogtreecommitdiff
path: root/net/sctp/ulpevent.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-04-27 19:16:19 +0100
committerDavid Woodhouse <dwmw2@infradead.org>2007-04-27 19:16:19 +0100
commitd1da4e50e5d09f02c340927a4fcb7f54202fa033 (patch)
tree7f98317bdd45dbdb7644e9179891c5af6a3a8ef1 /net/sctp/ulpevent.c
parent78ab67da1002d954ea4c3e2b441e2483c41f94e8 (diff)
parenta205752d1ad2d37d6597aaae5a56fc396a770868 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: drivers/mtd/Kconfig Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'net/sctp/ulpevent.c')
-rw-r--r--net/sctp/ulpevent.c49
1 files changed, 42 insertions, 7 deletions
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)
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