Merge gregkh@master.kernel.org:/home/rmk/linux-2.6-arm
[deliverable/linux.git] / net / sctp / ulpevent.c
index e049f41faa47cbcd7af477909b977c806f667685..ee236784a6bb91ea8bbf3787b776aabf65971ae9 100644 (file)
 static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
                                       struct sctp_association *asoc);
 static void sctp_ulpevent_release_data(struct sctp_ulpevent *event);
+static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event);
 
-/* Stub skb destructor.  */
-static void sctp_stub_rfree(struct sk_buff *skb)
-{
-/* WARNING:  This function is just a warning not to use the
- * skb destructor.  If the skb is shared, we may get the destructor
- * callback on some processor that does not own the sock_lock.  This
- * was occuring with PACKET socket applications that were monitoring
- * our skbs.   We can't take the sock_lock, because we can't risk
- * recursing if we do really own the sock lock.  Instead, do all
- * of our rwnd manipulation while we own the sock_lock outright.
- */
-}
 
 /* Initialize an ULP event from an given skb.  */
 SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
@@ -111,15 +100,19 @@ static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
         */
        sctp_association_hold((struct sctp_association *)asoc);
        skb = sctp_event2skb(event);
-       skb->sk = asoc->base.sk;
        event->asoc = (struct sctp_association *)asoc;
-       skb->destructor = sctp_stub_rfree;
+       atomic_add(skb->truesize, &event->asoc->rmem_alloc);
+       skb_set_owner_r(skb, asoc->base.sk);
 }
 
 /* A simple destructor to give up the reference to the association. */
 static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
 {
-       sctp_association_put(event->asoc);
+       struct sctp_association *asoc = event->asoc;
+       struct sk_buff *skb = sctp_event2skb(event);
+
+       atomic_sub(skb->truesize, &asoc->rmem_alloc);
+       sctp_association_put(asoc);
 }
 
 /* Create and initialize an SCTP_ASSOC_CHANGE event.
@@ -892,6 +885,7 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
 static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
 {
        struct sk_buff *skb, *frag;
+       unsigned int    len;
 
        /* Current stack structures assume that the rcv buffer is
         * per socket.   For UDP style sockets this is not true as
@@ -901,7 +895,30 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
         */
 
        skb = sctp_event2skb(event);
-       sctp_assoc_rwnd_increase(event->asoc, skb_headlen(skb));
+       len = skb->len;
+
+       if (!skb->data_len)
+               goto done;
+
+       /* Don't forget the fragments. */
+       for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
+               /* NOTE:  skb_shinfos are recursive. Although IP returns
+                * skb's with only 1 level of fragments, SCTP reassembly can
+                * increase the levels.
+                */
+               sctp_ulpevent_release_frag_data(sctp_skb2event(frag));
+       }
+
+done:
+       sctp_assoc_rwnd_increase(event->asoc, len);
+       sctp_ulpevent_release_owner(event);
+}
+
+static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event)
+{
+       struct sk_buff *skb, *frag;
+
+       skb = sctp_event2skb(event);
 
        if (!skb->data_len)
                goto done;
@@ -912,7 +929,7 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
                 * skb's with only 1 level of fragments, SCTP reassembly can
                 * increase the levels.
                 */
-               sctp_ulpevent_release_data(sctp_skb2event(frag));
+               sctp_ulpevent_release_frag_data(sctp_skb2event(frag));
        }
 
 done:
@@ -922,7 +939,6 @@ done:
 /* Free a ulpevent that has an owner.  It includes releasing the reference
  * to the owner, updating the rwnd in case of a DATA event and freeing the
  * skb.
- * See comments in sctp_stub_rfree().
  */
 void sctp_ulpevent_free(struct sctp_ulpevent *event)
 {
This page took 0.045145 seconds and 5 git commands to generate.