aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sysctl.h1
-rw-r--r--include/net/sctp/structs.h16
-rw-r--r--net/sctp/associola.c9
-rw-r--r--net/sctp/endpointola.c3
-rw-r--r--net/sctp/input.c20
-rw-r--r--net/sctp/protocol.c3
-rw-r--r--net/sctp/sm_statefuns.c22
-rw-r--r--net/sctp/socket.c4
-rw-r--r--net/sctp/sysctl.c8
-rw-r--r--net/sctp/ulpevent.c24
10 files changed, 71 insertions, 39 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index ab2791b3189d..64f203c45378 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -715,6 +715,7 @@ enum {
715 NET_SCTP_PRSCTP_ENABLE = 14, 715 NET_SCTP_PRSCTP_ENABLE = 14,
716 NET_SCTP_SNDBUF_POLICY = 15, 716 NET_SCTP_SNDBUF_POLICY = 15,
717 NET_SCTP_SACK_TIMEOUT = 16, 717 NET_SCTP_SACK_TIMEOUT = 16,
718 NET_SCTP_RCVBUF_POLICY = 17,
718}; 719};
719 720
720/* /proc/sys/net/bridge */ 721/* /proc/sys/net/bridge */
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 2aad4468797e..8e7794ee27ff 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -161,6 +161,13 @@ extern struct sctp_globals {
161 */ 161 */
162 int sndbuf_policy; 162 int sndbuf_policy;
163 163
164 /*
165 * Policy for preforming sctp/socket accounting
166 * 0 - do socket level accounting, all assocs share sk_rcvbuf
167 * 1 - do sctp accounting, each asoc may use sk_rcvbuf bytes
168 */
169 int rcvbuf_policy;
170
164 /* Delayed SACK timeout 200ms default*/ 171 /* Delayed SACK timeout 200ms default*/
165 int sack_timeout; 172 int sack_timeout;
166 173
@@ -218,6 +225,7 @@ extern struct sctp_globals {
218#define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable) 225#define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable)
219#define sctp_max_retrans_association (sctp_globals.max_retrans_association) 226#define sctp_max_retrans_association (sctp_globals.max_retrans_association)
220#define sctp_sndbuf_policy (sctp_globals.sndbuf_policy) 227#define sctp_sndbuf_policy (sctp_globals.sndbuf_policy)
228#define sctp_rcvbuf_policy (sctp_globals.rcvbuf_policy)
221#define sctp_max_retrans_path (sctp_globals.max_retrans_path) 229#define sctp_max_retrans_path (sctp_globals.max_retrans_path)
222#define sctp_max_retrans_init (sctp_globals.max_retrans_init) 230#define sctp_max_retrans_init (sctp_globals.max_retrans_init)
223#define sctp_sack_timeout (sctp_globals.sack_timeout) 231#define sctp_sack_timeout (sctp_globals.sack_timeout)
@@ -1224,6 +1232,9 @@ struct sctp_endpoint {
1224 1232
1225 /* sendbuf acct. policy. */ 1233 /* sendbuf acct. policy. */
1226 __u32 sndbuf_policy; 1234 __u32 sndbuf_policy;
1235
1236 /* rcvbuf acct. policy. */
1237 __u32 rcvbuf_policy;
1227}; 1238};
1228 1239
1229/* Recover the outter endpoint structure. */ 1240/* Recover the outter endpoint structure. */
@@ -1550,6 +1561,11 @@ struct sctp_association {
1550 */ 1561 */
1551 int sndbuf_used; 1562 int sndbuf_used;
1552 1563
1564 /* This is the amount of memory that this association has allocated
1565 * in the receive path at any given time.
1566 */
1567 atomic_t rmem_alloc;
1568
1553 /* This is the wait queue head for send requests waiting on 1569 /* This is the wait queue head for send requests waiting on
1554 * the association sndbuf space. 1570 * the association sndbuf space.
1555 */ 1571 */
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5f07ddb19554..dec68a604773 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -177,10 +177,10 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
177 * RFC 6 - A SCTP receiver MUST be able to receive a minimum of 177 * RFC 6 - A SCTP receiver MUST be able to receive a minimum of
178 * 1500 bytes in one SCTP packet. 178 * 1500 bytes in one SCTP packet.
179 */ 179 */
180 if (sk->sk_rcvbuf < SCTP_DEFAULT_MINWINDOW) 180 if ((sk->sk_rcvbuf/2) < SCTP_DEFAULT_MINWINDOW)
181 asoc->rwnd = SCTP_DEFAULT_MINWINDOW; 181 asoc->rwnd = SCTP_DEFAULT_MINWINDOW;
182 else 182 else
183 asoc->rwnd = sk->sk_rcvbuf; 183 asoc->rwnd = sk->sk_rcvbuf/2;
184 184
185 asoc->a_rwnd = asoc->rwnd; 185 asoc->a_rwnd = asoc->rwnd;
186 186
@@ -192,6 +192,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
192 /* Set the sndbuf size for transmit. */ 192 /* Set the sndbuf size for transmit. */
193 asoc->sndbuf_used = 0; 193 asoc->sndbuf_used = 0;
194 194
195 /* Initialize the receive memory counter */
196 atomic_set(&asoc->rmem_alloc, 0);
197
195 init_waitqueue_head(&asoc->wait); 198 init_waitqueue_head(&asoc->wait);
196 199
197 asoc->c.my_vtag = sctp_generate_tag(ep); 200 asoc->c.my_vtag = sctp_generate_tag(ep);
@@ -400,6 +403,8 @@ static void sctp_association_destroy(struct sctp_association *asoc)
400 spin_unlock_bh(&sctp_assocs_id_lock); 403 spin_unlock_bh(&sctp_assocs_id_lock);
401 } 404 }
402 405
406 BUG_TRAP(!atomic_read(&asoc->rmem_alloc));
407
403 if (asoc->base.malloced) { 408 if (asoc->base.malloced) {
404 kfree(asoc); 409 kfree(asoc);
405 SCTP_DBG_OBJCNT_DEC(assoc); 410 SCTP_DBG_OBJCNT_DEC(assoc);
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index 0df76897f563..67bd53070ee0 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -104,6 +104,9 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
104 sk->sk_write_space = sctp_write_space; 104 sk->sk_write_space = sctp_write_space;
105 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); 105 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
106 106
107 /* Get the receive buffer policy for this endpoint */
108 ep->rcvbuf_policy = sctp_rcvbuf_policy;
109
107 /* Initialize the secret key used with cookie. */ 110 /* Initialize the secret key used with cookie. */
108 get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE); 111 get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE);
109 ep->last_key = ep->current_key = 0; 112 ep->last_key = ep->current_key = 0;
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 28f32243397f..b24ff2c1aef5 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -100,21 +100,6 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
100 return 0; 100 return 0;
101} 101}
102 102
103/* The free routine for skbuffs that sctp receives */
104static void sctp_rfree(struct sk_buff *skb)
105{
106 atomic_sub(sizeof(struct sctp_chunk),&skb->sk->sk_rmem_alloc);
107 sock_rfree(skb);
108}
109
110/* The ownership wrapper routine to do receive buffer accounting */
111static void sctp_rcv_set_owner_r(struct sk_buff *skb, struct sock *sk)
112{
113 skb_set_owner_r(skb,sk);
114 skb->destructor = sctp_rfree;
115 atomic_add(sizeof(struct sctp_chunk),&sk->sk_rmem_alloc);
116}
117
118struct sctp_input_cb { 103struct sctp_input_cb {
119 union { 104 union {
120 struct inet_skb_parm h4; 105 struct inet_skb_parm h4;
@@ -217,9 +202,6 @@ int sctp_rcv(struct sk_buff *skb)
217 rcvr = &ep->base; 202 rcvr = &ep->base;
218 } 203 }
219 204
220 if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
221 goto discard_release;
222
223 /* 205 /*
224 * RFC 2960, 8.4 - Handle "Out of the blue" Packets. 206 * RFC 2960, 8.4 - Handle "Out of the blue" Packets.
225 * An SCTP packet is called an "out of the blue" (OOTB) 207 * An SCTP packet is called an "out of the blue" (OOTB)
@@ -256,8 +238,6 @@ int sctp_rcv(struct sk_buff *skb)
256 } 238 }
257 SCTP_INPUT_CB(skb)->chunk = chunk; 239 SCTP_INPUT_CB(skb)->chunk = chunk;
258 240
259 sctp_rcv_set_owner_r(skb,sk);
260
261 /* Remember what endpoint is to handle this packet. */ 241 /* Remember what endpoint is to handle this packet. */
262 chunk->rcvr = rcvr; 242 chunk->rcvr = rcvr;
263 243
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index dc9dff396fad..f775d78aa59d 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1050,6 +1050,9 @@ SCTP_STATIC __init int sctp_init(void)
1050 /* Sendbuffer growth - do per-socket accounting */ 1050 /* Sendbuffer growth - do per-socket accounting */
1051 sctp_sndbuf_policy = 0; 1051 sctp_sndbuf_policy = 0;
1052 1052
1053 /* Rcvbuffer growth - do per-socket accounting */
1054 sctp_rcvbuf_policy = 0;
1055
1053 /* HB.interval - 30 seconds */ 1056 /* HB.interval - 30 seconds */
1054 sctp_hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; 1057 sctp_hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
1055 1058
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 505c7de10c50..475bfb4972d9 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -5160,6 +5160,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
5160 sctp_verb_t deliver; 5160 sctp_verb_t deliver;
5161 int tmp; 5161 int tmp;
5162 __u32 tsn; 5162 __u32 tsn;
5163 int account_value;
5164 struct sock *sk = asoc->base.sk;
5163 5165
5164 data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; 5166 data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
5165 skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); 5167 skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
@@ -5169,6 +5171,26 @@ static int sctp_eat_data(const struct sctp_association *asoc,
5169 5171
5170 /* ASSERT: Now skb->data is really the user data. */ 5172 /* ASSERT: Now skb->data is really the user data. */
5171 5173
5174 /*
5175 * if we are established, and we have used up our receive
5176 * buffer memory, drop the frame
5177 */
5178 if (asoc->state == SCTP_STATE_ESTABLISHED) {
5179 /*
5180 * If the receive buffer policy is 1, then each
5181 * association can allocate up to sk_rcvbuf bytes
5182 * otherwise, all the associations in aggregate
5183 * may allocate up to sk_rcvbuf bytes
5184 */
5185 if (asoc->ep->rcvbuf_policy)
5186 account_value = atomic_read(&asoc->rmem_alloc);
5187 else
5188 account_value = atomic_read(&sk->sk_rmem_alloc);
5189
5190 if (account_value > sk->sk_rcvbuf)
5191 return SCTP_IERROR_IGNORE_TSN;
5192 }
5193
5172 /* Process ECN based congestion. 5194 /* Process ECN based congestion.
5173 * 5195 *
5174 * Since the chunk structure is reused for all chunks within 5196 * Since the chunk structure is reused for all chunks within
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 4d1b8d8904c4..abab81f3818f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -5114,8 +5114,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
5114 sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { 5114 sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
5115 event = sctp_skb2event(skb); 5115 event = sctp_skb2event(skb);
5116 if (event->asoc == assoc) { 5116 if (event->asoc == assoc) {
5117 sock_rfree(skb);
5117 __skb_unlink(skb, &oldsk->sk_receive_queue); 5118 __skb_unlink(skb, &oldsk->sk_receive_queue);
5118 __skb_queue_tail(&newsk->sk_receive_queue, skb); 5119 __skb_queue_tail(&newsk->sk_receive_queue, skb);
5120 skb_set_owner_r(skb, newsk);
5119 } 5121 }
5120 } 5122 }
5121 5123
@@ -5143,8 +5145,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
5143 sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { 5145 sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
5144 event = sctp_skb2event(skb); 5146 event = sctp_skb2event(skb);
5145 if (event->asoc == assoc) { 5147 if (event->asoc == assoc) {
5148 sock_rfree(skb);
5146 __skb_unlink(skb, &oldsp->pd_lobby); 5149 __skb_unlink(skb, &oldsp->pd_lobby);
5147 __skb_queue_tail(queue, skb); 5150 __skb_queue_tail(queue, skb);
5151 skb_set_owner_r(skb, newsk);
5148 } 5152 }
5149 } 5153 }
5150 5154
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 75b28dd634fe..fcd7096c953d 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -121,6 +121,14 @@ static ctl_table sctp_table[] = {
121 .proc_handler = &proc_dointvec 121 .proc_handler = &proc_dointvec
122 }, 122 },
123 { 123 {
124 .ctl_name = NET_SCTP_RCVBUF_POLICY,
125 .procname = "rcvbuf_policy",
126 .data = &sctp_rcvbuf_policy,
127 .maxlen = sizeof(int),
128 .mode = 0644,
129 .proc_handler = &proc_dointvec
130 },
131 {
124 .ctl_name = NET_SCTP_PATH_MAX_RETRANS, 132 .ctl_name = NET_SCTP_PATH_MAX_RETRANS,
125 .procname = "path_max_retrans", 133 .procname = "path_max_retrans",
126 .data = &sctp_max_retrans_path, 134 .data = &sctp_max_retrans_path,
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index e049f41faa47..ba97f974f57c 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -52,19 +52,6 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
52 struct sctp_association *asoc); 52 struct sctp_association *asoc);
53static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); 53static void sctp_ulpevent_release_data(struct sctp_ulpevent *event);
54 54
55/* Stub skb destructor. */
56static void sctp_stub_rfree(struct sk_buff *skb)
57{
58/* WARNING: This function is just a warning not to use the
59 * skb destructor. If the skb is shared, we may get the destructor
60 * callback on some processor that does not own the sock_lock. This
61 * was occuring with PACKET socket applications that were monitoring
62 * our skbs. We can't take the sock_lock, because we can't risk
63 * recursing if we do really own the sock lock. Instead, do all
64 * of our rwnd manipulation while we own the sock_lock outright.
65 */
66}
67
68/* Initialize an ULP event from an given skb. */ 55/* Initialize an ULP event from an given skb. */
69SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) 56SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
70{ 57{
@@ -111,15 +98,19 @@ static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
111 */ 98 */
112 sctp_association_hold((struct sctp_association *)asoc); 99 sctp_association_hold((struct sctp_association *)asoc);
113 skb = sctp_event2skb(event); 100 skb = sctp_event2skb(event);
114 skb->sk = asoc->base.sk;
115 event->asoc = (struct sctp_association *)asoc; 101 event->asoc = (struct sctp_association *)asoc;
116 skb->destructor = sctp_stub_rfree; 102 atomic_add(skb->truesize, &event->asoc->rmem_alloc);
103 skb_set_owner_r(skb, asoc->base.sk);
117} 104}
118 105
119/* A simple destructor to give up the reference to the association. */ 106/* A simple destructor to give up the reference to the association. */
120static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) 107static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
121{ 108{
122 sctp_association_put(event->asoc); 109 struct sctp_association *asoc = event->asoc;
110 struct sk_buff *skb = sctp_event2skb(event);
111
112 atomic_sub(skb->truesize, &asoc->rmem_alloc);
113 sctp_association_put(asoc);
123} 114}
124 115
125/* Create and initialize an SCTP_ASSOC_CHANGE event. 116/* Create and initialize an SCTP_ASSOC_CHANGE event.
@@ -922,7 +913,6 @@ done:
922/* Free a ulpevent that has an owner. It includes releasing the reference 913/* Free a ulpevent that has an owner. It includes releasing the reference
923 * to the owner, updating the rwnd in case of a DATA event and freeing the 914 * to the owner, updating the rwnd in case of a DATA event and freeing the
924 * skb. 915 * skb.
925 * See comments in sctp_stub_rfree().
926 */ 916 */
927void sctp_ulpevent_free(struct sctp_ulpevent *event) 917void sctp_ulpevent_free(struct sctp_ulpevent *event)
928{ 918{