NET_SCTP_PRSCTP_ENABLE           = 14,
        NET_SCTP_SNDBUF_POLICY           = 15,
        NET_SCTP_SACK_TIMEOUT            = 16,
+       NET_SCTP_RCVBUF_POLICY           = 17,
 };
 
 /* /proc/sys/net/bridge */
 
         */
        int sndbuf_policy;
 
+       /*
+        * Policy for preforming sctp/socket accounting
+        * 0   - do socket level accounting, all assocs share sk_rcvbuf
+        * 1   - do sctp accounting, each asoc may use sk_rcvbuf bytes
+        */
+       int rcvbuf_policy;
+
        /* Delayed SACK timeout  200ms default*/
        int sack_timeout;
 
 #define sctp_cookie_preserve_enable    (sctp_globals.cookie_preserve_enable)
 #define sctp_max_retrans_association   (sctp_globals.max_retrans_association)
 #define sctp_sndbuf_policy             (sctp_globals.sndbuf_policy)
+#define sctp_rcvbuf_policy             (sctp_globals.rcvbuf_policy)
 #define sctp_max_retrans_path          (sctp_globals.max_retrans_path)
 #define sctp_max_retrans_init          (sctp_globals.max_retrans_init)
 #define sctp_sack_timeout              (sctp_globals.sack_timeout)
 
        /* sendbuf acct. policy.        */
        __u32 sndbuf_policy;
+
+       /* rcvbuf acct. policy. */
+       __u32 rcvbuf_policy;
 };
 
 /* Recover the outter endpoint structure. */
         */
        int sndbuf_used;
 
+       /* This is the amount of memory that this association has allocated
+        * in the receive path at any given time.
+        */
+       atomic_t rmem_alloc;
+
        /* This is the wait queue head for send requests waiting on
         * the association sndbuf space.
         */
 
         * RFC 6 - A SCTP receiver MUST be able to receive a minimum of
         * 1500 bytes in one SCTP packet.
         */
-       if (sk->sk_rcvbuf < SCTP_DEFAULT_MINWINDOW)
+       if ((sk->sk_rcvbuf/2) < SCTP_DEFAULT_MINWINDOW)
                asoc->rwnd = SCTP_DEFAULT_MINWINDOW;
        else
-               asoc->rwnd = sk->sk_rcvbuf;
+               asoc->rwnd = sk->sk_rcvbuf/2;
 
        asoc->a_rwnd = asoc->rwnd;
 
        /* Set the sndbuf size for transmit.  */
        asoc->sndbuf_used = 0;
 
+       /* Initialize the receive memory counter */
+       atomic_set(&asoc->rmem_alloc, 0);
+
        init_waitqueue_head(&asoc->wait);
 
        asoc->c.my_vtag = sctp_generate_tag(ep);
                spin_unlock_bh(&sctp_assocs_id_lock);
        }
 
+       BUG_TRAP(!atomic_read(&asoc->rmem_alloc));
+
        if (asoc->base.malloced) {
                kfree(asoc);
                SCTP_DBG_OBJCNT_DEC(assoc);
 
        sk->sk_write_space = sctp_write_space;
        sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
 
+       /* Get the receive buffer policy for this endpoint */
+       ep->rcvbuf_policy = sctp_rcvbuf_policy;
+
        /* Initialize the secret key used with cookie. */
        get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE);
        ep->last_key = ep->current_key = 0;
 
        return 0;
 }
 
-/* The free routine for skbuffs that sctp receives */
-static void sctp_rfree(struct sk_buff *skb)
-{
-       atomic_sub(sizeof(struct sctp_chunk),&skb->sk->sk_rmem_alloc);
-       sock_rfree(skb);
-}
-
-/* The ownership wrapper routine to do receive buffer accounting */
-static void sctp_rcv_set_owner_r(struct sk_buff *skb, struct sock *sk)
-{
-       skb_set_owner_r(skb,sk);
-       skb->destructor = sctp_rfree;
-       atomic_add(sizeof(struct sctp_chunk),&sk->sk_rmem_alloc);
-}
-
 struct sctp_input_cb {
        union {
                struct inet_skb_parm    h4;
                rcvr = &ep->base;
        }
 
-       if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
-               goto discard_release;
-
        /*
         * RFC 2960, 8.4 - Handle "Out of the blue" Packets.
         * An SCTP packet is called an "out of the blue" (OOTB)
        }
        SCTP_INPUT_CB(skb)->chunk = chunk;
 
-       sctp_rcv_set_owner_r(skb,sk);
-
        /* Remember what endpoint is to handle this packet. */
        chunk->rcvr = rcvr;
 
 
        /* Sendbuffer growth        - do per-socket accounting */
        sctp_sndbuf_policy              = 0;
 
+       /* Rcvbuffer growth         - do per-socket accounting */
+       sctp_rcvbuf_policy              = 0;
+
        /* HB.interval              - 30 seconds */
        sctp_hb_interval                = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
 
 
        sctp_verb_t deliver;
        int tmp;
        __u32 tsn;
+       int account_value;
+       struct sock *sk = asoc->base.sk;
 
        data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
        skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
 
        /* ASSERT:  Now skb->data is really the user data.  */
 
+       /*
+        * if we are established, and we have used up our receive
+        * buffer memory, drop the frame
+        */
+       if (asoc->state == SCTP_STATE_ESTABLISHED) {
+               /*
+                * If the receive buffer policy is 1, then each
+                * association can allocate up to sk_rcvbuf bytes
+                * otherwise, all the associations in aggregate
+                * may allocate up to sk_rcvbuf bytes
+                */
+               if (asoc->ep->rcvbuf_policy)
+                       account_value = atomic_read(&asoc->rmem_alloc);
+               else
+                       account_value = atomic_read(&sk->sk_rmem_alloc);
+
+               if (account_value > sk->sk_rcvbuf)
+                       return SCTP_IERROR_IGNORE_TSN;
+       }
+
        /* Process ECN based congestion.
         *
         * Since the chunk structure is reused for all chunks within
 
        sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
                event = sctp_skb2event(skb);
                if (event->asoc == assoc) {
+                       sock_rfree(skb);
                        __skb_unlink(skb, &oldsk->sk_receive_queue);
                        __skb_queue_tail(&newsk->sk_receive_queue, skb);
+                       skb_set_owner_r(skb, newsk);
                }
        }
 
                sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
                        event = sctp_skb2event(skb);
                        if (event->asoc == assoc) {
+                               sock_rfree(skb);
                                __skb_unlink(skb, &oldsp->pd_lobby);
                                __skb_queue_tail(queue, skb);
+                               skb_set_owner_r(skb, newsk);
                        }
                }
 
 
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
+       {
+               .ctl_name       = NET_SCTP_RCVBUF_POLICY,
+               .procname       = "rcvbuf_policy",
+               .data           = &sctp_rcvbuf_policy,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
        {
                .ctl_name       = NET_SCTP_PATH_MAX_RETRANS,
                .procname       = "path_max_retrans",
 
                                       struct sctp_association *asoc);
 static void sctp_ulpevent_release_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)
 {
         */
        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.
 /* 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)
 {