diff options
-rw-r--r-- | include/linux/sysctl.h | 1 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 16 | ||||
-rw-r--r-- | net/sctp/associola.c | 9 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 3 | ||||
-rw-r--r-- | net/sctp/input.c | 20 | ||||
-rw-r--r-- | net/sctp/protocol.c | 3 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 22 | ||||
-rw-r--r-- | net/sctp/socket.c | 4 | ||||
-rw-r--r-- | net/sctp/sysctl.c | 8 | ||||
-rw-r--r-- | net/sctp/ulpevent.c | 24 |
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 */ | ||
104 | static 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 */ | ||
111 | static 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 | |||
118 | struct sctp_input_cb { | 103 | struct 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); |
53 | static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); | 53 | static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); |
54 | 54 | ||
55 | /* Stub skb destructor. */ | ||
56 | static 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. */ |
69 | SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) | 56 | SCTP_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. */ |
120 | static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) | 107 | static 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 | */ |
927 | void sctp_ulpevent_free(struct sctp_ulpevent *event) | 917 | void sctp_ulpevent_free(struct sctp_ulpevent *event) |
928 | { | 918 | { |