diff options
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/inqueue.c | 1 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 59 | ||||
-rw-r--r-- | net/sctp/sm_statetable.c | 10 | ||||
-rw-r--r-- | net/sctp/ulpqueue.c | 27 |
4 files changed, 75 insertions, 22 deletions
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 297b8951463e..cf0c767d43ae 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c | |||
@@ -149,6 +149,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) | |||
149 | /* This is the first chunk in the packet. */ | 149 | /* This is the first chunk in the packet. */ |
150 | chunk->singleton = 1; | 150 | chunk->singleton = 1; |
151 | ch = (sctp_chunkhdr_t *) chunk->skb->data; | 151 | ch = (sctp_chunkhdr_t *) chunk->skb->data; |
152 | chunk->data_accepted = 0; | ||
152 | } | 153 | } |
153 | 154 | ||
154 | chunk->chunk_hdr = ch; | 155 | chunk->chunk_hdr = ch; |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 2b9a832b29a7..8cdba51ec076 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -636,8 +636,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
636 | */ | 636 | */ |
637 | chunk->subh.cookie_hdr = | 637 | chunk->subh.cookie_hdr = |
638 | (struct sctp_signed_cookie *)chunk->skb->data; | 638 | (struct sctp_signed_cookie *)chunk->skb->data; |
639 | skb_pull(chunk->skb, | 639 | if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - |
640 | ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); | 640 | sizeof(sctp_chunkhdr_t))) |
641 | goto nomem; | ||
641 | 642 | ||
642 | /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint | 643 | /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint |
643 | * "Z" will reply with a COOKIE ACK chunk after building a TCB | 644 | * "Z" will reply with a COOKIE ACK chunk after building a TCB |
@@ -965,7 +966,8 @@ sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep, | |||
965 | */ | 966 | */ |
966 | chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; | 967 | chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; |
967 | paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); | 968 | paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); |
968 | skb_pull(chunk->skb, paylen); | 969 | if (!pskb_pull(chunk->skb, paylen)) |
970 | goto nomem; | ||
969 | 971 | ||
970 | reply = sctp_make_heartbeat_ack(asoc, chunk, | 972 | reply = sctp_make_heartbeat_ack(asoc, chunk, |
971 | chunk->subh.hb_hdr, paylen); | 973 | chunk->subh.hb_hdr, paylen); |
@@ -1860,8 +1862,9 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep, | |||
1860 | * are in good shape. | 1862 | * are in good shape. |
1861 | */ | 1863 | */ |
1862 | chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; | 1864 | chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; |
1863 | skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - | 1865 | if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - |
1864 | sizeof(sctp_chunkhdr_t)); | 1866 | sizeof(sctp_chunkhdr_t))) |
1867 | goto nomem; | ||
1865 | 1868 | ||
1866 | /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie | 1869 | /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie |
1867 | * of a duplicate COOKIE ECHO match the Verification Tags of the | 1870 | * of a duplicate COOKIE ECHO match the Verification Tags of the |
@@ -5151,7 +5154,9 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5151 | int tmp; | 5154 | int tmp; |
5152 | __u32 tsn; | 5155 | __u32 tsn; |
5153 | int account_value; | 5156 | int account_value; |
5157 | struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; | ||
5154 | struct sock *sk = asoc->base.sk; | 5158 | struct sock *sk = asoc->base.sk; |
5159 | int rcvbuf_over = 0; | ||
5155 | 5160 | ||
5156 | data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; | 5161 | data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; |
5157 | skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); | 5162 | skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); |
@@ -5162,10 +5167,16 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5162 | /* ASSERT: Now skb->data is really the user data. */ | 5167 | /* ASSERT: Now skb->data is really the user data. */ |
5163 | 5168 | ||
5164 | /* | 5169 | /* |
5165 | * if we are established, and we have used up our receive | 5170 | * If we are established, and we have used up our receive buffer |
5166 | * buffer memory, drop the frame | 5171 | * memory, think about droping the frame. |
5167 | */ | 5172 | * Note that we have an opportunity to improve performance here. |
5168 | if (asoc->state == SCTP_STATE_ESTABLISHED) { | 5173 | * If we accept one chunk from an skbuff, we have to keep all the |
5174 | * memory of that skbuff around until the chunk is read into user | ||
5175 | * space. Therefore, once we accept 1 chunk we may as well accept all | ||
5176 | * remaining chunks in the skbuff. The data_accepted flag helps us do | ||
5177 | * that. | ||
5178 | */ | ||
5179 | if ((asoc->state == SCTP_STATE_ESTABLISHED) && (!chunk->data_accepted)) { | ||
5169 | /* | 5180 | /* |
5170 | * If the receive buffer policy is 1, then each | 5181 | * If the receive buffer policy is 1, then each |
5171 | * association can allocate up to sk_rcvbuf bytes | 5182 | * association can allocate up to sk_rcvbuf bytes |
@@ -5176,9 +5187,25 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5176 | account_value = atomic_read(&asoc->rmem_alloc); | 5187 | account_value = atomic_read(&asoc->rmem_alloc); |
5177 | else | 5188 | else |
5178 | account_value = atomic_read(&sk->sk_rmem_alloc); | 5189 | account_value = atomic_read(&sk->sk_rmem_alloc); |
5179 | 5190 | if (account_value > sk->sk_rcvbuf) { | |
5180 | if (account_value > sk->sk_rcvbuf) | 5191 | /* |
5181 | return SCTP_IERROR_IGNORE_TSN; | 5192 | * We need to make forward progress, even when we are |
5193 | * under memory pressure, so we always allow the | ||
5194 | * next tsn after the ctsn ack point to be accepted. | ||
5195 | * This lets us avoid deadlocks in which we have to | ||
5196 | * drop frames that would otherwise let us drain the | ||
5197 | * receive queue. | ||
5198 | */ | ||
5199 | if ((sctp_tsnmap_get_ctsn(map) + 1) != tsn) | ||
5200 | return SCTP_IERROR_IGNORE_TSN; | ||
5201 | |||
5202 | /* | ||
5203 | * We're going to accept the frame but we should renege | ||
5204 | * to make space for it. This will send us down that | ||
5205 | * path later in this function. | ||
5206 | */ | ||
5207 | rcvbuf_over = 1; | ||
5208 | } | ||
5182 | } | 5209 | } |
5183 | 5210 | ||
5184 | /* Process ECN based congestion. | 5211 | /* Process ECN based congestion. |
@@ -5226,6 +5253,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5226 | datalen -= sizeof(sctp_data_chunk_t); | 5253 | datalen -= sizeof(sctp_data_chunk_t); |
5227 | 5254 | ||
5228 | deliver = SCTP_CMD_CHUNK_ULP; | 5255 | deliver = SCTP_CMD_CHUNK_ULP; |
5256 | chunk->data_accepted = 1; | ||
5229 | 5257 | ||
5230 | /* Think about partial delivery. */ | 5258 | /* Think about partial delivery. */ |
5231 | if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { | 5259 | if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { |
@@ -5242,7 +5270,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5242 | * large spill over. | 5270 | * large spill over. |
5243 | */ | 5271 | */ |
5244 | if (!asoc->rwnd || asoc->rwnd_over || | 5272 | if (!asoc->rwnd || asoc->rwnd_over || |
5245 | (datalen > asoc->rwnd + asoc->frag_point)) { | 5273 | (datalen > asoc->rwnd + asoc->frag_point) || |
5274 | rcvbuf_over) { | ||
5246 | 5275 | ||
5247 | /* If this is the next TSN, consider reneging to make | 5276 | /* If this is the next TSN, consider reneging to make |
5248 | * room. Note: Playing nice with a confused sender. A | 5277 | * room. Note: Playing nice with a confused sender. A |
@@ -5250,8 +5279,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5250 | * space and in the future we may want to detect and | 5279 | * space and in the future we may want to detect and |
5251 | * do more drastic reneging. | 5280 | * do more drastic reneging. |
5252 | */ | 5281 | */ |
5253 | if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) && | 5282 | if (sctp_tsnmap_has_gap(map) && |
5254 | (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) { | 5283 | (sctp_tsnmap_get_ctsn(map) + 1) == tsn) { |
5255 | SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn); | 5284 | SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn); |
5256 | deliver = SCTP_CMD_RENEGE; | 5285 | deliver = SCTP_CMD_RENEGE; |
5257 | } else { | 5286 | } else { |
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 75ef10408764..8bcca5676151 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c | |||
@@ -366,9 +366,9 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, | |||
366 | /* SCTP_STATE_EMPTY */ \ | 366 | /* SCTP_STATE_EMPTY */ \ |
367 | {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \ | 367 | {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \ |
368 | /* SCTP_STATE_CLOSED */ \ | 368 | /* SCTP_STATE_CLOSED */ \ |
369 | {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ | 369 | {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ |
370 | /* SCTP_STATE_COOKIE_WAIT */ \ | 370 | /* SCTP_STATE_COOKIE_WAIT */ \ |
371 | {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ | 371 | {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ |
372 | /* SCTP_STATE_COOKIE_ECHOED */ \ | 372 | /* SCTP_STATE_COOKIE_ECHOED */ \ |
373 | {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \ | 373 | {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \ |
374 | /* SCTP_STATE_ESTABLISHED */ \ | 374 | /* SCTP_STATE_ESTABLISHED */ \ |
@@ -380,7 +380,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, | |||
380 | /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ | 380 | /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ |
381 | {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \ | 381 | {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \ |
382 | /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ | 382 | /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ |
383 | {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ | 383 | {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ |
384 | } /* TYPE_SCTP_ECN_ECNE */ | 384 | } /* TYPE_SCTP_ECN_ECNE */ |
385 | 385 | ||
386 | #define TYPE_SCTP_ECN_CWR { \ | 386 | #define TYPE_SCTP_ECN_CWR { \ |
@@ -401,7 +401,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, | |||
401 | /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ | 401 | /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ |
402 | {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ | 402 | {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ |
403 | /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ | 403 | /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ |
404 | {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ | 404 | {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ |
405 | } /* TYPE_SCTP_ECN_CWR */ | 405 | } /* TYPE_SCTP_ECN_CWR */ |
406 | 406 | ||
407 | #define TYPE_SCTP_SHUTDOWN_COMPLETE { \ | 407 | #define TYPE_SCTP_SHUTDOWN_COMPLETE { \ |
@@ -647,7 +647,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { | |||
647 | /* SCTP_STATE_EMPTY */ \ | 647 | /* SCTP_STATE_EMPTY */ \ |
648 | {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ | 648 | {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ |
649 | /* SCTP_STATE_CLOSED */ \ | 649 | /* SCTP_STATE_CLOSED */ \ |
650 | {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ | 650 | {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \ |
651 | /* SCTP_STATE_COOKIE_WAIT */ \ | 651 | /* SCTP_STATE_COOKIE_WAIT */ \ |
652 | {.fn = sctp_sf_do_prm_requestheartbeat, \ | 652 | {.fn = sctp_sf_do_prm_requestheartbeat, \ |
653 | .name = "sctp_sf_do_prm_requestheartbeat"}, \ | 653 | .name = "sctp_sf_do_prm_requestheartbeat"}, \ |
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 2080b2d28c98..575e556aeb3e 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c | |||
@@ -279,6 +279,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, | |||
279 | static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag) | 279 | static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag) |
280 | { | 280 | { |
281 | struct sk_buff *pos; | 281 | struct sk_buff *pos; |
282 | struct sk_buff *new = NULL; | ||
282 | struct sctp_ulpevent *event; | 283 | struct sctp_ulpevent *event; |
283 | struct sk_buff *pnext, *last; | 284 | struct sk_buff *pnext, *last; |
284 | struct sk_buff *list = skb_shinfo(f_frag)->frag_list; | 285 | struct sk_buff *list = skb_shinfo(f_frag)->frag_list; |
@@ -297,11 +298,33 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu | |||
297 | */ | 298 | */ |
298 | if (last) | 299 | if (last) |
299 | last->next = pos; | 300 | last->next = pos; |
300 | else | 301 | else { |
301 | skb_shinfo(f_frag)->frag_list = pos; | 302 | if (skb_cloned(f_frag)) { |
303 | /* This is a cloned skb, we can't just modify | ||
304 | * the frag_list. We need a new skb to do that. | ||
305 | * Instead of calling skb_unshare(), we'll do it | ||
306 | * ourselves since we need to delay the free. | ||
307 | */ | ||
308 | new = skb_copy(f_frag, GFP_ATOMIC); | ||
309 | if (!new) | ||
310 | return NULL; /* try again later */ | ||
311 | |||
312 | new->sk = f_frag->sk; | ||
313 | |||
314 | skb_shinfo(new)->frag_list = pos; | ||
315 | } else | ||
316 | skb_shinfo(f_frag)->frag_list = pos; | ||
317 | } | ||
302 | 318 | ||
303 | /* Remove the first fragment from the reassembly queue. */ | 319 | /* Remove the first fragment from the reassembly queue. */ |
304 | __skb_unlink(f_frag, queue); | 320 | __skb_unlink(f_frag, queue); |
321 | |||
322 | /* if we did unshare, then free the old skb and re-assign */ | ||
323 | if (new) { | ||
324 | kfree_skb(f_frag); | ||
325 | f_frag = new; | ||
326 | } | ||
327 | |||
305 | while (pos) { | 328 | while (pos) { |
306 | 329 | ||
307 | pnext = pos->next; | 330 | pnext = pos->next; |