diff options
author | Jiri Kosina <jkosina@suse.cz> | 2013-01-29 04:48:30 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-01-29 04:48:30 -0500 |
commit | 617677295b53a40d0e54aac4cbbc216ffbc755dd (patch) | |
tree | 51b9e87213243ed5efff252c8e8d8fec4eebc588 /net/sctp | |
parent | 5c8d1b68e01a144813e38795fe6dbe7ebb506131 (diff) | |
parent | 6abb7c25775b7fb2225ad0508236d63ca710e65f (diff) |
Merge branch 'master' into for-next
Conflicts:
drivers/devfreq/exynos4_bus.c
Sync with Linus' tree to be able to apply patches that are
against newer code (mvneta).
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/Kconfig | 60 | ||||
-rw-r--r-- | net/sctp/associola.c | 16 | ||||
-rw-r--r-- | net/sctp/chunk.c | 20 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 5 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 2 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 2 | ||||
-rw-r--r-- | net/sctp/output.c | 14 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 24 | ||||
-rw-r--r-- | net/sctp/probe.c | 3 | ||||
-rw-r--r-- | net/sctp/proc.c | 29 | ||||
-rw-r--r-- | net/sctp/protocol.c | 15 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 24 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 55 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 24 | ||||
-rw-r--r-- | net/sctp/socket.c | 94 | ||||
-rw-r--r-- | net/sctp/sysctl.c | 63 | ||||
-rw-r--r-- | net/sctp/transport.c | 22 | ||||
-rw-r--r-- | net/sctp/tsnmap.c | 8 | ||||
-rw-r--r-- | net/sctp/ulpqueue.c | 3 |
19 files changed, 369 insertions, 114 deletions
diff --git a/net/sctp/Kconfig b/net/sctp/Kconfig index 126b014eb79b..7521d944c0fb 100644 --- a/net/sctp/Kconfig +++ b/net/sctp/Kconfig | |||
@@ -9,7 +9,6 @@ menuconfig IP_SCTP | |||
9 | select CRYPTO | 9 | select CRYPTO |
10 | select CRYPTO_HMAC | 10 | select CRYPTO_HMAC |
11 | select CRYPTO_SHA1 | 11 | select CRYPTO_SHA1 |
12 | select CRYPTO_MD5 if SCTP_HMAC_MD5 | ||
13 | select LIBCRC32C | 12 | select LIBCRC32C |
14 | ---help--- | 13 | ---help--- |
15 | Stream Control Transmission Protocol | 14 | Stream Control Transmission Protocol |
@@ -67,34 +66,45 @@ config SCTP_DBG_OBJCNT | |||
67 | 'cat /proc/net/sctp/sctp_dbg_objcnt' | 66 | 'cat /proc/net/sctp/sctp_dbg_objcnt' |
68 | 67 | ||
69 | If unsure, say N | 68 | If unsure, say N |
70 | |||
71 | choice | 69 | choice |
72 | prompt "SCTP: Cookie HMAC Algorithm" | 70 | prompt "Default SCTP cookie HMAC encoding" |
73 | default SCTP_HMAC_MD5 | 71 | default SCTP_DEFAULT_COOKIE_HMAC_MD5 |
72 | help | ||
73 | This option sets the default sctp cookie hmac algorithm | ||
74 | when in doubt select 'md5' | ||
75 | |||
76 | config SCTP_DEFAULT_COOKIE_HMAC_MD5 | ||
77 | bool "Enable optional MD5 hmac cookie generation" | ||
74 | help | 78 | help |
75 | HMAC algorithm to be used during association initialization. It | 79 | Enable optional MD5 hmac based SCTP cookie generation |
76 | is strongly recommended to use HMAC-SHA1 or HMAC-MD5. See | 80 | select SCTP_COOKIE_HMAC_MD5 |
77 | configuration for Cryptographic API and enable those algorithms | 81 | |
78 | to make usable by SCTP. | 82 | config SCTP_DEFAULT_COOKIE_HMAC_SHA1 |
79 | 83 | bool "Enable optional SHA1 hmac cookie generation" | |
80 | config SCTP_HMAC_NONE | 84 | help |
81 | bool "None" | 85 | Enable optional SHA1 hmac based SCTP cookie generation |
82 | help | 86 | select SCTP_COOKIE_HMAC_SHA1 |
83 | Choosing this disables the use of an HMAC during association | 87 | |
84 | establishment. It is advised to use either HMAC-MD5 or HMAC-SHA1. | 88 | config SCTP_DEFAULT_COOKIE_HMAC_NONE |
85 | 89 | bool "Use no hmac alg in SCTP cookie generation" | |
86 | config SCTP_HMAC_SHA1 | ||
87 | bool "HMAC-SHA1" | ||
88 | help | ||
89 | Enable the use of HMAC-SHA1 during association establishment. It | ||
90 | is advised to use either HMAC-MD5 or HMAC-SHA1. | ||
91 | |||
92 | config SCTP_HMAC_MD5 | ||
93 | bool "HMAC-MD5" | ||
94 | help | 90 | help |
95 | Enable the use of HMAC-MD5 during association establishment. It is | 91 | Use no hmac algorithm in SCTP cookie generation |
96 | advised to use either HMAC-MD5 or HMAC-SHA1. | ||
97 | 92 | ||
98 | endchoice | 93 | endchoice |
99 | 94 | ||
95 | config SCTP_COOKIE_HMAC_MD5 | ||
96 | bool "Enable optional MD5 hmac cookie generation" | ||
97 | help | ||
98 | Enable optional MD5 hmac based SCTP cookie generation | ||
99 | select CRYPTO_HMAC if SCTP_COOKIE_HMAC_MD5 | ||
100 | select CRYPTO_MD5 if SCTP_COOKIE_HMAC_MD5 | ||
101 | |||
102 | config SCTP_COOKIE_HMAC_SHA1 | ||
103 | bool "Enable optional SHA1 hmac cookie generation" | ||
104 | help | ||
105 | Enable optional SHA1 hmac based SCTP cookie generation | ||
106 | select CRYPTO_HMAC if SCTP_COOKIE_HMAC_SHA1 | ||
107 | select CRYPTO_SHA1 if SCTP_COOKIE_HMAC_SHA1 | ||
108 | |||
109 | |||
100 | endif # IP_SCTP | 110 | endif # IP_SCTP |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index b1ef3bc301a5..b45ed1f96921 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -321,6 +321,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
321 | asoc->default_timetolive = sp->default_timetolive; | 321 | asoc->default_timetolive = sp->default_timetolive; |
322 | asoc->default_rcv_context = sp->default_rcv_context; | 322 | asoc->default_rcv_context = sp->default_rcv_context; |
323 | 323 | ||
324 | /* SCTP_GET_ASSOC_STATS COUNTERS */ | ||
325 | memset(&asoc->stats, 0, sizeof(struct sctp_priv_assoc_stats)); | ||
326 | |||
324 | /* AUTH related initializations */ | 327 | /* AUTH related initializations */ |
325 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); | 328 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); |
326 | err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); | 329 | err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); |
@@ -445,7 +448,7 @@ void sctp_association_free(struct sctp_association *asoc) | |||
445 | /* Release the transport structures. */ | 448 | /* Release the transport structures. */ |
446 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { | 449 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { |
447 | transport = list_entry(pos, struct sctp_transport, transports); | 450 | transport = list_entry(pos, struct sctp_transport, transports); |
448 | list_del(pos); | 451 | list_del_rcu(pos); |
449 | sctp_transport_free(transport); | 452 | sctp_transport_free(transport); |
450 | } | 453 | } |
451 | 454 | ||
@@ -565,7 +568,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, | |||
565 | sctp_assoc_update_retran_path(asoc); | 568 | sctp_assoc_update_retran_path(asoc); |
566 | 569 | ||
567 | /* Remove this peer from the list. */ | 570 | /* Remove this peer from the list. */ |
568 | list_del(&peer->transports); | 571 | list_del_rcu(&peer->transports); |
569 | 572 | ||
570 | /* Get the first transport of asoc. */ | 573 | /* Get the first transport of asoc. */ |
571 | pos = asoc->peer.transport_addr_list.next; | 574 | pos = asoc->peer.transport_addr_list.next; |
@@ -760,12 +763,13 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
760 | 763 | ||
761 | /* Set the transport's RTO.initial value */ | 764 | /* Set the transport's RTO.initial value */ |
762 | peer->rto = asoc->rto_initial; | 765 | peer->rto = asoc->rto_initial; |
766 | sctp_max_rto(asoc, peer); | ||
763 | 767 | ||
764 | /* Set the peer's active state. */ | 768 | /* Set the peer's active state. */ |
765 | peer->state = peer_state; | 769 | peer->state = peer_state; |
766 | 770 | ||
767 | /* Attach the remote transport to our asoc. */ | 771 | /* Attach the remote transport to our asoc. */ |
768 | list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); | 772 | list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list); |
769 | asoc->peer.transport_count++; | 773 | asoc->peer.transport_count++; |
770 | 774 | ||
771 | /* If we do not yet have a primary path, set one. */ | 775 | /* If we do not yet have a primary path, set one. */ |
@@ -1152,8 +1156,12 @@ static void sctp_assoc_bh_rcv(struct work_struct *work) | |||
1152 | */ | 1156 | */ |
1153 | if (sctp_chunk_is_data(chunk)) | 1157 | if (sctp_chunk_is_data(chunk)) |
1154 | asoc->peer.last_data_from = chunk->transport; | 1158 | asoc->peer.last_data_from = chunk->transport; |
1155 | else | 1159 | else { |
1156 | SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS); | 1160 | SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS); |
1161 | asoc->stats.ictrlchunks++; | ||
1162 | if (chunk->chunk_hdr->type == SCTP_CID_SACK) | ||
1163 | asoc->stats.isacks++; | ||
1164 | } | ||
1157 | 1165 | ||
1158 | if (chunk->transport) | 1166 | if (chunk->transport) |
1159 | chunk->transport->last_time_heard = jiffies; | 1167 | chunk->transport->last_time_heard = jiffies; |
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 7c2df9c33df3..69ce21e3716f 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c | |||
@@ -183,7 +183,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
183 | 183 | ||
184 | msg = sctp_datamsg_new(GFP_KERNEL); | 184 | msg = sctp_datamsg_new(GFP_KERNEL); |
185 | if (!msg) | 185 | if (!msg) |
186 | return NULL; | 186 | return ERR_PTR(-ENOMEM); |
187 | 187 | ||
188 | /* Note: Calculate this outside of the loop, so that all fragments | 188 | /* Note: Calculate this outside of the loop, so that all fragments |
189 | * have the same expiration. | 189 | * have the same expiration. |
@@ -280,11 +280,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
280 | 280 | ||
281 | chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); | 281 | chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); |
282 | 282 | ||
283 | if (!chunk) | 283 | if (!chunk) { |
284 | err = -ENOMEM; | ||
284 | goto errout; | 285 | goto errout; |
286 | } | ||
287 | |||
285 | err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); | 288 | err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); |
286 | if (err < 0) | 289 | if (err < 0) |
287 | goto errout; | 290 | goto errout_chunk_free; |
288 | 291 | ||
289 | offset += len; | 292 | offset += len; |
290 | 293 | ||
@@ -315,8 +318,10 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
315 | 318 | ||
316 | chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); | 319 | chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); |
317 | 320 | ||
318 | if (!chunk) | 321 | if (!chunk) { |
322 | err = -ENOMEM; | ||
319 | goto errout; | 323 | goto errout; |
324 | } | ||
320 | 325 | ||
321 | err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); | 326 | err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); |
322 | 327 | ||
@@ -324,7 +329,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
324 | __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr | 329 | __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr |
325 | - (__u8 *)chunk->skb->data); | 330 | - (__u8 *)chunk->skb->data); |
326 | if (err < 0) | 331 | if (err < 0) |
327 | goto errout; | 332 | goto errout_chunk_free; |
328 | 333 | ||
329 | sctp_datamsg_assign(msg, chunk); | 334 | sctp_datamsg_assign(msg, chunk); |
330 | list_add_tail(&chunk->frag_list, &msg->chunks); | 335 | list_add_tail(&chunk->frag_list, &msg->chunks); |
@@ -332,6 +337,9 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
332 | 337 | ||
333 | return msg; | 338 | return msg; |
334 | 339 | ||
340 | errout_chunk_free: | ||
341 | sctp_chunk_free(chunk); | ||
342 | |||
335 | errout: | 343 | errout: |
336 | list_for_each_safe(pos, temp, &msg->chunks) { | 344 | list_for_each_safe(pos, temp, &msg->chunks) { |
337 | list_del_init(pos); | 345 | list_del_init(pos); |
@@ -339,7 +347,7 @@ errout: | |||
339 | sctp_chunk_free(chunk); | 347 | sctp_chunk_free(chunk); |
340 | } | 348 | } |
341 | sctp_datamsg_put(msg); | 349 | sctp_datamsg_put(msg); |
342 | return NULL; | 350 | return ERR_PTR(err); |
343 | } | 351 | } |
344 | 352 | ||
345 | /* Check whether this message has expired. */ | 353 | /* Check whether this message has expired. */ |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index bd7e6a6a815a..17a001bac2cc 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
@@ -480,8 +480,11 @@ normal: | |||
480 | */ | 480 | */ |
481 | if (asoc && sctp_chunk_is_data(chunk)) | 481 | if (asoc && sctp_chunk_is_data(chunk)) |
482 | asoc->peer.last_data_from = chunk->transport; | 482 | asoc->peer.last_data_from = chunk->transport; |
483 | else | 483 | else { |
484 | SCTP_INC_STATS(sock_net(ep->base.sk), SCTP_MIB_INCTRLCHUNKS); | 484 | SCTP_INC_STATS(sock_net(ep->base.sk), SCTP_MIB_INCTRLCHUNKS); |
485 | if (asoc) | ||
486 | asoc->stats.ictrlchunks++; | ||
487 | } | ||
485 | 488 | ||
486 | if (chunk->transport) | 489 | if (chunk->transport) |
487 | chunk->transport->last_time_heard = jiffies; | 490 | chunk->transport->last_time_heard = jiffies; |
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 397296fb156f..2d5ad280de38 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c | |||
@@ -104,6 +104,8 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) | |||
104 | * on the BH related data structures. | 104 | * on the BH related data structures. |
105 | */ | 105 | */ |
106 | list_add_tail(&chunk->list, &q->in_chunk_list); | 106 | list_add_tail(&chunk->list, &q->in_chunk_list); |
107 | if (chunk->asoc) | ||
108 | chunk->asoc->stats.ipackets++; | ||
107 | q->immediate.func(&q->immediate); | 109 | q->immediate.func(&q->immediate); |
108 | } | 110 | } |
109 | 111 | ||
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index ea14cb445295..f3f0f4dc31dd 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -345,7 +345,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
345 | } | 345 | } |
346 | 346 | ||
347 | out: | 347 | out: |
348 | if (!IS_ERR(dst)) { | 348 | if (!IS_ERR_OR_NULL(dst)) { |
349 | struct rt6_info *rt; | 349 | struct rt6_info *rt; |
350 | rt = (struct rt6_info *)dst; | 350 | rt = (struct rt6_info *)dst; |
351 | t->dst = dst; | 351 | t->dst = dst; |
diff --git a/net/sctp/output.c b/net/sctp/output.c index 4e90188bf489..f5200a2ad852 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
@@ -311,6 +311,8 @@ static sctp_xmit_t __sctp_packet_append_chunk(struct sctp_packet *packet, | |||
311 | 311 | ||
312 | case SCTP_CID_SACK: | 312 | case SCTP_CID_SACK: |
313 | packet->has_sack = 1; | 313 | packet->has_sack = 1; |
314 | if (chunk->asoc) | ||
315 | chunk->asoc->stats.osacks++; | ||
314 | break; | 316 | break; |
315 | 317 | ||
316 | case SCTP_CID_AUTH: | 318 | case SCTP_CID_AUTH: |
@@ -584,11 +586,13 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
584 | */ | 586 | */ |
585 | 587 | ||
586 | /* Dump that on IP! */ | 588 | /* Dump that on IP! */ |
587 | if (asoc && asoc->peer.last_sent_to != tp) { | 589 | if (asoc) { |
588 | /* Considering the multiple CPU scenario, this is a | 590 | asoc->stats.opackets++; |
589 | * "correcter" place for last_sent_to. --xguo | 591 | if (asoc->peer.last_sent_to != tp) |
590 | */ | 592 | /* Considering the multiple CPU scenario, this is a |
591 | asoc->peer.last_sent_to = tp; | 593 | * "correcter" place for last_sent_to. --xguo |
594 | */ | ||
595 | asoc->peer.last_sent_to = tp; | ||
592 | } | 596 | } |
593 | 597 | ||
594 | if (has_data) { | 598 | if (has_data) { |
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 1b4a7f8ec3fd..9bcdbd02d777 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -224,7 +224,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) | |||
224 | 224 | ||
225 | /* Free the outqueue structure and any related pending chunks. | 225 | /* Free the outqueue structure and any related pending chunks. |
226 | */ | 226 | */ |
227 | void sctp_outq_teardown(struct sctp_outq *q) | 227 | static void __sctp_outq_teardown(struct sctp_outq *q) |
228 | { | 228 | { |
229 | struct sctp_transport *transport; | 229 | struct sctp_transport *transport; |
230 | struct list_head *lchunk, *temp; | 230 | struct list_head *lchunk, *temp; |
@@ -277,8 +277,6 @@ void sctp_outq_teardown(struct sctp_outq *q) | |||
277 | sctp_chunk_free(chunk); | 277 | sctp_chunk_free(chunk); |
278 | } | 278 | } |
279 | 279 | ||
280 | q->error = 0; | ||
281 | |||
282 | /* Throw away any leftover control chunks. */ | 280 | /* Throw away any leftover control chunks. */ |
283 | list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { | 281 | list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { |
284 | list_del_init(&chunk->list); | 282 | list_del_init(&chunk->list); |
@@ -286,11 +284,17 @@ void sctp_outq_teardown(struct sctp_outq *q) | |||
286 | } | 284 | } |
287 | } | 285 | } |
288 | 286 | ||
287 | void sctp_outq_teardown(struct sctp_outq *q) | ||
288 | { | ||
289 | __sctp_outq_teardown(q); | ||
290 | sctp_outq_init(q->asoc, q); | ||
291 | } | ||
292 | |||
289 | /* Free the outqueue structure and any related pending chunks. */ | 293 | /* Free the outqueue structure and any related pending chunks. */ |
290 | void sctp_outq_free(struct sctp_outq *q) | 294 | void sctp_outq_free(struct sctp_outq *q) |
291 | { | 295 | { |
292 | /* Throw away leftover chunks. */ | 296 | /* Throw away leftover chunks. */ |
293 | sctp_outq_teardown(q); | 297 | __sctp_outq_teardown(q); |
294 | 298 | ||
295 | /* If we were kmalloc()'d, free the memory. */ | 299 | /* If we were kmalloc()'d, free the memory. */ |
296 | if (q->malloced) | 300 | if (q->malloced) |
@@ -667,6 +671,7 @@ redo: | |||
667 | chunk->fast_retransmit = SCTP_DONT_FRTX; | 671 | chunk->fast_retransmit = SCTP_DONT_FRTX; |
668 | 672 | ||
669 | q->empty = 0; | 673 | q->empty = 0; |
674 | q->asoc->stats.rtxchunks++; | ||
670 | break; | 675 | break; |
671 | } | 676 | } |
672 | 677 | ||
@@ -876,12 +881,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
876 | if (status != SCTP_XMIT_OK) { | 881 | if (status != SCTP_XMIT_OK) { |
877 | /* put the chunk back */ | 882 | /* put the chunk back */ |
878 | list_add(&chunk->list, &q->control_chunk_list); | 883 | list_add(&chunk->list, &q->control_chunk_list); |
879 | } else if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) { | 884 | } else { |
885 | asoc->stats.octrlchunks++; | ||
880 | /* PR-SCTP C5) If a FORWARD TSN is sent, the | 886 | /* PR-SCTP C5) If a FORWARD TSN is sent, the |
881 | * sender MUST assure that at least one T3-rtx | 887 | * sender MUST assure that at least one T3-rtx |
882 | * timer is running. | 888 | * timer is running. |
883 | */ | 889 | */ |
884 | sctp_transport_reset_timers(transport); | 890 | if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) |
891 | sctp_transport_reset_timers(transport); | ||
885 | } | 892 | } |
886 | break; | 893 | break; |
887 | 894 | ||
@@ -1055,6 +1062,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
1055 | */ | 1062 | */ |
1056 | if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) | 1063 | if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) |
1057 | chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM; | 1064 | chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM; |
1065 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) | ||
1066 | asoc->stats.ouodchunks++; | ||
1067 | else | ||
1068 | asoc->stats.oodchunks++; | ||
1058 | 1069 | ||
1059 | break; | 1070 | break; |
1060 | 1071 | ||
@@ -1162,6 +1173,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk) | |||
1162 | 1173 | ||
1163 | sack_ctsn = ntohl(sack->cum_tsn_ack); | 1174 | sack_ctsn = ntohl(sack->cum_tsn_ack); |
1164 | gap_ack_blocks = ntohs(sack->num_gap_ack_blocks); | 1175 | gap_ack_blocks = ntohs(sack->num_gap_ack_blocks); |
1176 | asoc->stats.gapcnt += gap_ack_blocks; | ||
1165 | /* | 1177 | /* |
1166 | * SFR-CACC algorithm: | 1178 | * SFR-CACC algorithm: |
1167 | * On receipt of a SACK the sender SHOULD execute the | 1179 | * On receipt of a SACK the sender SHOULD execute the |
diff --git a/net/sctp/probe.c b/net/sctp/probe.c index bc6cd75cc1dc..5f7518de2fd1 100644 --- a/net/sctp/probe.c +++ b/net/sctp/probe.c | |||
@@ -122,7 +122,8 @@ static const struct file_operations sctpprobe_fops = { | |||
122 | .llseek = noop_llseek, | 122 | .llseek = noop_llseek, |
123 | }; | 123 | }; |
124 | 124 | ||
125 | sctp_disposition_t jsctp_sf_eat_sack(const struct sctp_endpoint *ep, | 125 | sctp_disposition_t jsctp_sf_eat_sack(struct net *net, |
126 | const struct sctp_endpoint *ep, | ||
126 | const struct sctp_association *asoc, | 127 | const struct sctp_association *asoc, |
127 | const sctp_subtype_t type, | 128 | const sctp_subtype_t type, |
128 | void *arg, | 129 | void *arg, |
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index c3bea269faf4..8c19e97262ca 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
@@ -102,7 +102,7 @@ static const struct file_operations sctp_snmp_seq_fops = { | |||
102 | .open = sctp_snmp_seq_open, | 102 | .open = sctp_snmp_seq_open, |
103 | .read = seq_read, | 103 | .read = seq_read, |
104 | .llseek = seq_lseek, | 104 | .llseek = seq_lseek, |
105 | .release = single_release, | 105 | .release = single_release_net, |
106 | }; | 106 | }; |
107 | 107 | ||
108 | /* Set up the proc fs entry for 'snmp' object. */ | 108 | /* Set up the proc fs entry for 'snmp' object. */ |
@@ -139,7 +139,11 @@ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_commo | |||
139 | primary = &peer->saddr; | 139 | primary = &peer->saddr; |
140 | } | 140 | } |
141 | 141 | ||
142 | list_for_each_entry(laddr, &epb->bind_addr.address_list, list) { | 142 | rcu_read_lock(); |
143 | list_for_each_entry_rcu(laddr, &epb->bind_addr.address_list, list) { | ||
144 | if (!laddr->valid) | ||
145 | continue; | ||
146 | |||
143 | addr = &laddr->a; | 147 | addr = &laddr->a; |
144 | af = sctp_get_af_specific(addr->sa.sa_family); | 148 | af = sctp_get_af_specific(addr->sa.sa_family); |
145 | if (primary && af->cmp_addr(addr, primary)) { | 149 | if (primary && af->cmp_addr(addr, primary)) { |
@@ -147,6 +151,7 @@ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_commo | |||
147 | } | 151 | } |
148 | af->seq_dump_addr(seq, addr); | 152 | af->seq_dump_addr(seq, addr); |
149 | } | 153 | } |
154 | rcu_read_unlock(); | ||
150 | } | 155 | } |
151 | 156 | ||
152 | /* Dump remote addresses of an association. */ | 157 | /* Dump remote addresses of an association. */ |
@@ -157,15 +162,20 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa | |||
157 | struct sctp_af *af; | 162 | struct sctp_af *af; |
158 | 163 | ||
159 | primary = &assoc->peer.primary_addr; | 164 | primary = &assoc->peer.primary_addr; |
160 | list_for_each_entry(transport, &assoc->peer.transport_addr_list, | 165 | rcu_read_lock(); |
166 | list_for_each_entry_rcu(transport, &assoc->peer.transport_addr_list, | ||
161 | transports) { | 167 | transports) { |
162 | addr = &transport->ipaddr; | 168 | addr = &transport->ipaddr; |
169 | if (transport->dead) | ||
170 | continue; | ||
171 | |||
163 | af = sctp_get_af_specific(addr->sa.sa_family); | 172 | af = sctp_get_af_specific(addr->sa.sa_family); |
164 | if (af->cmp_addr(addr, primary)) { | 173 | if (af->cmp_addr(addr, primary)) { |
165 | seq_printf(seq, "*"); | 174 | seq_printf(seq, "*"); |
166 | } | 175 | } |
167 | af->seq_dump_addr(seq, addr); | 176 | af->seq_dump_addr(seq, addr); |
168 | } | 177 | } |
178 | rcu_read_unlock(); | ||
169 | } | 179 | } |
170 | 180 | ||
171 | static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) | 181 | static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) |
@@ -251,7 +261,7 @@ static const struct file_operations sctp_eps_seq_fops = { | |||
251 | .open = sctp_eps_seq_open, | 261 | .open = sctp_eps_seq_open, |
252 | .read = seq_read, | 262 | .read = seq_read, |
253 | .llseek = seq_lseek, | 263 | .llseek = seq_lseek, |
254 | .release = seq_release, | 264 | .release = seq_release_net, |
255 | }; | 265 | }; |
256 | 266 | ||
257 | /* Set up the proc fs entry for 'eps' object. */ | 267 | /* Set up the proc fs entry for 'eps' object. */ |
@@ -372,7 +382,7 @@ static const struct file_operations sctp_assocs_seq_fops = { | |||
372 | .open = sctp_assocs_seq_open, | 382 | .open = sctp_assocs_seq_open, |
373 | .read = seq_read, | 383 | .read = seq_read, |
374 | .llseek = seq_lseek, | 384 | .llseek = seq_lseek, |
375 | .release = seq_release, | 385 | .release = seq_release_net, |
376 | }; | 386 | }; |
377 | 387 | ||
378 | /* Set up the proc fs entry for 'assocs' object. */ | 388 | /* Set up the proc fs entry for 'assocs' object. */ |
@@ -436,12 +446,16 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) | |||
436 | head = &sctp_assoc_hashtable[hash]; | 446 | head = &sctp_assoc_hashtable[hash]; |
437 | sctp_local_bh_disable(); | 447 | sctp_local_bh_disable(); |
438 | read_lock(&head->lock); | 448 | read_lock(&head->lock); |
449 | rcu_read_lock(); | ||
439 | sctp_for_each_hentry(epb, node, &head->chain) { | 450 | sctp_for_each_hentry(epb, node, &head->chain) { |
440 | if (!net_eq(sock_net(epb->sk), seq_file_net(seq))) | 451 | if (!net_eq(sock_net(epb->sk), seq_file_net(seq))) |
441 | continue; | 452 | continue; |
442 | assoc = sctp_assoc(epb); | 453 | assoc = sctp_assoc(epb); |
443 | list_for_each_entry(tsp, &assoc->peer.transport_addr_list, | 454 | list_for_each_entry_rcu(tsp, &assoc->peer.transport_addr_list, |
444 | transports) { | 455 | transports) { |
456 | if (tsp->dead) | ||
457 | continue; | ||
458 | |||
445 | /* | 459 | /* |
446 | * The remote address (ADDR) | 460 | * The remote address (ADDR) |
447 | */ | 461 | */ |
@@ -487,6 +501,7 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) | |||
487 | } | 501 | } |
488 | } | 502 | } |
489 | 503 | ||
504 | rcu_read_unlock(); | ||
490 | read_unlock(&head->lock); | 505 | read_unlock(&head->lock); |
491 | sctp_local_bh_enable(); | 506 | sctp_local_bh_enable(); |
492 | 507 | ||
@@ -517,7 +532,7 @@ static const struct file_operations sctp_remaddr_seq_fops = { | |||
517 | .open = sctp_remaddr_seq_open, | 532 | .open = sctp_remaddr_seq_open, |
518 | .read = seq_read, | 533 | .read = seq_read, |
519 | .llseek = seq_lseek, | 534 | .llseek = seq_lseek, |
520 | .release = seq_release, | 535 | .release = seq_release_net, |
521 | }; | 536 | }; |
522 | 537 | ||
523 | int __net_init sctp_remaddr_proc_init(struct net *net) | 538 | int __net_init sctp_remaddr_proc_init(struct net *net) |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 2d518425d598..f898b1c58bd2 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -86,7 +86,7 @@ int sysctl_sctp_rmem[3]; | |||
86 | int sysctl_sctp_wmem[3]; | 86 | int sysctl_sctp_wmem[3]; |
87 | 87 | ||
88 | /* Set up the proc fs entry for the SCTP protocol. */ | 88 | /* Set up the proc fs entry for the SCTP protocol. */ |
89 | static __net_init int sctp_proc_init(struct net *net) | 89 | static int __net_init sctp_proc_init(struct net *net) |
90 | { | 90 | { |
91 | #ifdef CONFIG_PROC_FS | 91 | #ifdef CONFIG_PROC_FS |
92 | net->sctp.proc_net_sctp = proc_net_mkdir(net, "sctp", net->proc_net); | 92 | net->sctp.proc_net_sctp = proc_net_mkdir(net, "sctp", net->proc_net); |
@@ -1165,7 +1165,7 @@ static void sctp_v4_del_protocol(void) | |||
1165 | unregister_inetaddr_notifier(&sctp_inetaddr_notifier); | 1165 | unregister_inetaddr_notifier(&sctp_inetaddr_notifier); |
1166 | } | 1166 | } |
1167 | 1167 | ||
1168 | static int sctp_net_init(struct net *net) | 1168 | static int __net_init sctp_net_init(struct net *net) |
1169 | { | 1169 | { |
1170 | int status; | 1170 | int status; |
1171 | 1171 | ||
@@ -1190,6 +1190,15 @@ static int sctp_net_init(struct net *net) | |||
1190 | /* Whether Cookie Preservative is enabled(1) or not(0) */ | 1190 | /* Whether Cookie Preservative is enabled(1) or not(0) */ |
1191 | net->sctp.cookie_preserve_enable = 1; | 1191 | net->sctp.cookie_preserve_enable = 1; |
1192 | 1192 | ||
1193 | /* Default sctp sockets to use md5 as their hmac alg */ | ||
1194 | #if defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5) | ||
1195 | net->sctp.sctp_hmac_alg = "md5"; | ||
1196 | #elif defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1) | ||
1197 | net->sctp.sctp_hmac_alg = "sha1"; | ||
1198 | #else | ||
1199 | net->sctp.sctp_hmac_alg = NULL; | ||
1200 | #endif | ||
1201 | |||
1193 | /* Max.Burst - 4 */ | 1202 | /* Max.Burst - 4 */ |
1194 | net->sctp.max_burst = SCTP_DEFAULT_MAX_BURST; | 1203 | net->sctp.max_burst = SCTP_DEFAULT_MAX_BURST; |
1195 | 1204 | ||
@@ -1281,7 +1290,7 @@ err_sysctl_register: | |||
1281 | return status; | 1290 | return status; |
1282 | } | 1291 | } |
1283 | 1292 | ||
1284 | static void sctp_net_exit(struct net *net) | 1293 | static void __net_exit sctp_net_exit(struct net *net) |
1285 | { | 1294 | { |
1286 | /* Free the local address list */ | 1295 | /* Free the local address list */ |
1287 | sctp_free_addr_wq(net); | 1296 | sctp_free_addr_wq(net); |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 16a10850ed39..04df5301df04 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -804,10 +804,11 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) | |||
804 | gabs); | 804 | gabs); |
805 | 805 | ||
806 | /* Add the duplicate TSN information. */ | 806 | /* Add the duplicate TSN information. */ |
807 | if (num_dup_tsns) | 807 | if (num_dup_tsns) { |
808 | aptr->stats.idupchunks += num_dup_tsns; | ||
808 | sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, | 809 | sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, |
809 | sctp_tsnmap_get_dups(map)); | 810 | sctp_tsnmap_get_dups(map)); |
810 | 811 | } | |
811 | /* Once we have a sack generated, check to see what our sack | 812 | /* Once we have a sack generated, check to see what our sack |
812 | * generation is, if its 0, reset the transports to 0, and reset | 813 | * generation is, if its 0, reset the transports to 0, and reset |
813 | * the association generation to 1 | 814 | * the association generation to 1 |
@@ -1090,6 +1091,25 @@ nodata: | |||
1090 | return retval; | 1091 | return retval; |
1091 | } | 1092 | } |
1092 | 1093 | ||
1094 | struct sctp_chunk *sctp_make_violation_max_retrans( | ||
1095 | const struct sctp_association *asoc, | ||
1096 | const struct sctp_chunk *chunk) | ||
1097 | { | ||
1098 | struct sctp_chunk *retval; | ||
1099 | static const char error[] = "Association exceeded its max_retans count"; | ||
1100 | size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t); | ||
1101 | |||
1102 | retval = sctp_make_abort(asoc, chunk, payload_len); | ||
1103 | if (!retval) | ||
1104 | goto nodata; | ||
1105 | |||
1106 | sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, sizeof(error)); | ||
1107 | sctp_addto_chunk(retval, sizeof(error), error); | ||
1108 | |||
1109 | nodata: | ||
1110 | return retval; | ||
1111 | } | ||
1112 | |||
1093 | /* Make a HEARTBEAT chunk. */ | 1113 | /* Make a HEARTBEAT chunk. */ |
1094 | struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, | 1114 | struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, |
1095 | const struct sctp_transport *transport) | 1115 | const struct sctp_transport *transport) |
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 6773d7803627..c9577754a708 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
@@ -542,6 +542,7 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands, | |||
542 | */ | 542 | */ |
543 | if (!is_hb || transport->hb_sent) { | 543 | if (!is_hb || transport->hb_sent) { |
544 | transport->rto = min((transport->rto * 2), transport->asoc->rto_max); | 544 | transport->rto = min((transport->rto * 2), transport->asoc->rto_max); |
545 | sctp_max_rto(asoc, transport); | ||
545 | } | 546 | } |
546 | } | 547 | } |
547 | 548 | ||
@@ -577,7 +578,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, | |||
577 | unsigned int error) | 578 | unsigned int error) |
578 | { | 579 | { |
579 | struct sctp_ulpevent *event; | 580 | struct sctp_ulpevent *event; |
580 | 581 | struct sctp_chunk *abort; | |
581 | /* Cancel any partial delivery in progress. */ | 582 | /* Cancel any partial delivery in progress. */ |
582 | sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); | 583 | sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); |
583 | 584 | ||
@@ -593,6 +594,13 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, | |||
593 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | 594 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, |
594 | SCTP_ULPEVENT(event)); | 595 | SCTP_ULPEVENT(event)); |
595 | 596 | ||
597 | if (asoc->overall_error_count >= asoc->max_retrans) { | ||
598 | abort = sctp_make_violation_max_retrans(asoc, chunk); | ||
599 | if (abort) | ||
600 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, | ||
601 | SCTP_CHUNK(abort)); | ||
602 | } | ||
603 | |||
596 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | 604 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, |
597 | SCTP_STATE(SCTP_STATE_CLOSED)); | 605 | SCTP_STATE(SCTP_STATE_CLOSED)); |
598 | 606 | ||
@@ -1268,14 +1276,14 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1268 | sctp_outq_uncork(&asoc->outqueue); | 1276 | sctp_outq_uncork(&asoc->outqueue); |
1269 | local_cork = 0; | 1277 | local_cork = 0; |
1270 | } | 1278 | } |
1271 | asoc = cmd->obj.ptr; | 1279 | asoc = cmd->obj.asoc; |
1272 | /* Register with the endpoint. */ | 1280 | /* Register with the endpoint. */ |
1273 | sctp_endpoint_add_asoc(ep, asoc); | 1281 | sctp_endpoint_add_asoc(ep, asoc); |
1274 | sctp_hash_established(asoc); | 1282 | sctp_hash_established(asoc); |
1275 | break; | 1283 | break; |
1276 | 1284 | ||
1277 | case SCTP_CMD_UPDATE_ASSOC: | 1285 | case SCTP_CMD_UPDATE_ASSOC: |
1278 | sctp_assoc_update(asoc, cmd->obj.ptr); | 1286 | sctp_assoc_update(asoc, cmd->obj.asoc); |
1279 | break; | 1287 | break; |
1280 | 1288 | ||
1281 | case SCTP_CMD_PURGE_OUTQUEUE: | 1289 | case SCTP_CMD_PURGE_OUTQUEUE: |
@@ -1315,7 +1323,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1315 | break; | 1323 | break; |
1316 | 1324 | ||
1317 | case SCTP_CMD_PROCESS_FWDTSN: | 1325 | case SCTP_CMD_PROCESS_FWDTSN: |
1318 | sctp_cmd_process_fwdtsn(&asoc->ulpq, cmd->obj.ptr); | 1326 | sctp_cmd_process_fwdtsn(&asoc->ulpq, cmd->obj.chunk); |
1319 | break; | 1327 | break; |
1320 | 1328 | ||
1321 | case SCTP_CMD_GEN_SACK: | 1329 | case SCTP_CMD_GEN_SACK: |
@@ -1331,7 +1339,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1331 | case SCTP_CMD_PROCESS_SACK: | 1339 | case SCTP_CMD_PROCESS_SACK: |
1332 | /* Process an inbound SACK. */ | 1340 | /* Process an inbound SACK. */ |
1333 | error = sctp_cmd_process_sack(commands, asoc, | 1341 | error = sctp_cmd_process_sack(commands, asoc, |
1334 | cmd->obj.ptr); | 1342 | cmd->obj.chunk); |
1335 | break; | 1343 | break; |
1336 | 1344 | ||
1337 | case SCTP_CMD_GEN_INIT_ACK: | 1345 | case SCTP_CMD_GEN_INIT_ACK: |
@@ -1352,15 +1360,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1352 | * layer which will bail. | 1360 | * layer which will bail. |
1353 | */ | 1361 | */ |
1354 | error = sctp_cmd_process_init(commands, asoc, chunk, | 1362 | error = sctp_cmd_process_init(commands, asoc, chunk, |
1355 | cmd->obj.ptr, gfp); | 1363 | cmd->obj.init, gfp); |
1356 | break; | 1364 | break; |
1357 | 1365 | ||
1358 | case SCTP_CMD_GEN_COOKIE_ECHO: | 1366 | case SCTP_CMD_GEN_COOKIE_ECHO: |
1359 | /* Generate a COOKIE ECHO chunk. */ | 1367 | /* Generate a COOKIE ECHO chunk. */ |
1360 | new_obj = sctp_make_cookie_echo(asoc, chunk); | 1368 | new_obj = sctp_make_cookie_echo(asoc, chunk); |
1361 | if (!new_obj) { | 1369 | if (!new_obj) { |
1362 | if (cmd->obj.ptr) | 1370 | if (cmd->obj.chunk) |
1363 | sctp_chunk_free(cmd->obj.ptr); | 1371 | sctp_chunk_free(cmd->obj.chunk); |
1364 | goto nomem; | 1372 | goto nomem; |
1365 | } | 1373 | } |
1366 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, | 1374 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, |
@@ -1369,9 +1377,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1369 | /* If there is an ERROR chunk to be sent along with | 1377 | /* If there is an ERROR chunk to be sent along with |
1370 | * the COOKIE_ECHO, send it, too. | 1378 | * the COOKIE_ECHO, send it, too. |
1371 | */ | 1379 | */ |
1372 | if (cmd->obj.ptr) | 1380 | if (cmd->obj.chunk) |
1373 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, | 1381 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, |
1374 | SCTP_CHUNK(cmd->obj.ptr)); | 1382 | SCTP_CHUNK(cmd->obj.chunk)); |
1375 | 1383 | ||
1376 | if (new_obj->transport) { | 1384 | if (new_obj->transport) { |
1377 | new_obj->transport->init_sent_count++; | 1385 | new_obj->transport->init_sent_count++; |
@@ -1417,18 +1425,18 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1417 | case SCTP_CMD_CHUNK_ULP: | 1425 | case SCTP_CMD_CHUNK_ULP: |
1418 | /* Send a chunk to the sockets layer. */ | 1426 | /* Send a chunk to the sockets layer. */ |
1419 | SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", | 1427 | SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", |
1420 | "chunk_up:", cmd->obj.ptr, | 1428 | "chunk_up:", cmd->obj.chunk, |
1421 | "ulpq:", &asoc->ulpq); | 1429 | "ulpq:", &asoc->ulpq); |
1422 | sctp_ulpq_tail_data(&asoc->ulpq, cmd->obj.ptr, | 1430 | sctp_ulpq_tail_data(&asoc->ulpq, cmd->obj.chunk, |
1423 | GFP_ATOMIC); | 1431 | GFP_ATOMIC); |
1424 | break; | 1432 | break; |
1425 | 1433 | ||
1426 | case SCTP_CMD_EVENT_ULP: | 1434 | case SCTP_CMD_EVENT_ULP: |
1427 | /* Send a notification to the sockets layer. */ | 1435 | /* Send a notification to the sockets layer. */ |
1428 | SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", | 1436 | SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", |
1429 | "event_up:",cmd->obj.ptr, | 1437 | "event_up:",cmd->obj.ulpevent, |
1430 | "ulpq:",&asoc->ulpq); | 1438 | "ulpq:",&asoc->ulpq); |
1431 | sctp_ulpq_tail_event(&asoc->ulpq, cmd->obj.ptr); | 1439 | sctp_ulpq_tail_event(&asoc->ulpq, cmd->obj.ulpevent); |
1432 | break; | 1440 | break; |
1433 | 1441 | ||
1434 | case SCTP_CMD_REPLY: | 1442 | case SCTP_CMD_REPLY: |
@@ -1438,12 +1446,12 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1438 | local_cork = 1; | 1446 | local_cork = 1; |
1439 | } | 1447 | } |
1440 | /* Send a chunk to our peer. */ | 1448 | /* Send a chunk to our peer. */ |
1441 | error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr); | 1449 | error = sctp_outq_tail(&asoc->outqueue, cmd->obj.chunk); |
1442 | break; | 1450 | break; |
1443 | 1451 | ||
1444 | case SCTP_CMD_SEND_PKT: | 1452 | case SCTP_CMD_SEND_PKT: |
1445 | /* Send a full packet to our peer. */ | 1453 | /* Send a full packet to our peer. */ |
1446 | packet = cmd->obj.ptr; | 1454 | packet = cmd->obj.packet; |
1447 | sctp_packet_transmit(packet); | 1455 | sctp_packet_transmit(packet); |
1448 | sctp_ootb_pkt_free(packet); | 1456 | sctp_ootb_pkt_free(packet); |
1449 | break; | 1457 | break; |
@@ -1480,7 +1488,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1480 | break; | 1488 | break; |
1481 | 1489 | ||
1482 | case SCTP_CMD_SETUP_T2: | 1490 | case SCTP_CMD_SETUP_T2: |
1483 | sctp_cmd_setup_t2(commands, asoc, cmd->obj.ptr); | 1491 | sctp_cmd_setup_t2(commands, asoc, cmd->obj.chunk); |
1484 | break; | 1492 | break; |
1485 | 1493 | ||
1486 | case SCTP_CMD_TIMER_START_ONCE: | 1494 | case SCTP_CMD_TIMER_START_ONCE: |
@@ -1514,7 +1522,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1514 | break; | 1522 | break; |
1515 | 1523 | ||
1516 | case SCTP_CMD_INIT_CHOOSE_TRANSPORT: | 1524 | case SCTP_CMD_INIT_CHOOSE_TRANSPORT: |
1517 | chunk = cmd->obj.ptr; | 1525 | chunk = cmd->obj.chunk; |
1518 | t = sctp_assoc_choose_alter_transport(asoc, | 1526 | t = sctp_assoc_choose_alter_transport(asoc, |
1519 | asoc->init_last_sent_to); | 1527 | asoc->init_last_sent_to); |
1520 | asoc->init_last_sent_to = t; | 1528 | asoc->init_last_sent_to = t; |
@@ -1665,17 +1673,16 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1665 | break; | 1673 | break; |
1666 | 1674 | ||
1667 | case SCTP_CMD_PART_DELIVER: | 1675 | case SCTP_CMD_PART_DELIVER: |
1668 | sctp_ulpq_partial_delivery(&asoc->ulpq, cmd->obj.ptr, | 1676 | sctp_ulpq_partial_delivery(&asoc->ulpq, GFP_ATOMIC); |
1669 | GFP_ATOMIC); | ||
1670 | break; | 1677 | break; |
1671 | 1678 | ||
1672 | case SCTP_CMD_RENEGE: | 1679 | case SCTP_CMD_RENEGE: |
1673 | sctp_ulpq_renege(&asoc->ulpq, cmd->obj.ptr, | 1680 | sctp_ulpq_renege(&asoc->ulpq, cmd->obj.chunk, |
1674 | GFP_ATOMIC); | 1681 | GFP_ATOMIC); |
1675 | break; | 1682 | break; |
1676 | 1683 | ||
1677 | case SCTP_CMD_SETUP_T4: | 1684 | case SCTP_CMD_SETUP_T4: |
1678 | sctp_cmd_setup_t4(commands, asoc, cmd->obj.ptr); | 1685 | sctp_cmd_setup_t4(commands, asoc, cmd->obj.chunk); |
1679 | break; | 1686 | break; |
1680 | 1687 | ||
1681 | case SCTP_CMD_PROCESS_OPERR: | 1688 | case SCTP_CMD_PROCESS_OPERR: |
@@ -1734,8 +1741,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1734 | break; | 1741 | break; |
1735 | 1742 | ||
1736 | default: | 1743 | default: |
1737 | pr_warn("Impossible command: %u, %p\n", | 1744 | pr_warn("Impossible command: %u\n", |
1738 | cmd->verb, cmd->obj.ptr); | 1745 | cmd->verb); |
1739 | break; | 1746 | break; |
1740 | } | 1747 | } |
1741 | 1748 | ||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 49493f335861..5131fcfedb03 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -1055,6 +1055,7 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net, | |||
1055 | void *arg, | 1055 | void *arg, |
1056 | sctp_cmd_seq_t *commands) | 1056 | sctp_cmd_seq_t *commands) |
1057 | { | 1057 | { |
1058 | sctp_paramhdr_t *param_hdr; | ||
1058 | struct sctp_chunk *chunk = arg; | 1059 | struct sctp_chunk *chunk = arg; |
1059 | struct sctp_chunk *reply; | 1060 | struct sctp_chunk *reply; |
1060 | size_t paylen = 0; | 1061 | size_t paylen = 0; |
@@ -1072,12 +1073,17 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net, | |||
1072 | * Information field copied from the received HEARTBEAT chunk. | 1073 | * Information field copied from the received HEARTBEAT chunk. |
1073 | */ | 1074 | */ |
1074 | chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; | 1075 | chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; |
1076 | param_hdr = (sctp_paramhdr_t *) chunk->subh.hb_hdr; | ||
1075 | paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); | 1077 | paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); |
1078 | |||
1079 | if (ntohs(param_hdr->length) > paylen) | ||
1080 | return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, | ||
1081 | param_hdr, commands); | ||
1082 | |||
1076 | if (!pskb_pull(chunk->skb, paylen)) | 1083 | if (!pskb_pull(chunk->skb, paylen)) |
1077 | goto nomem; | 1084 | goto nomem; |
1078 | 1085 | ||
1079 | reply = sctp_make_heartbeat_ack(asoc, chunk, | 1086 | reply = sctp_make_heartbeat_ack(asoc, chunk, param_hdr, paylen); |
1080 | chunk->subh.hb_hdr, paylen); | ||
1081 | if (!reply) | 1087 | if (!reply) |
1082 | goto nomem; | 1088 | goto nomem; |
1083 | 1089 | ||
@@ -1773,8 +1779,10 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net, | |||
1773 | 1779 | ||
1774 | /* Update the content of current association. */ | 1780 | /* Update the content of current association. */ |
1775 | sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); | 1781 | sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); |
1776 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
1777 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | 1782 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); |
1783 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | ||
1784 | SCTP_STATE(SCTP_STATE_ESTABLISHED)); | ||
1785 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
1778 | return SCTP_DISPOSITION_CONSUME; | 1786 | return SCTP_DISPOSITION_CONSUME; |
1779 | 1787 | ||
1780 | nomem_ev: | 1788 | nomem_ev: |
@@ -6127,6 +6135,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6127 | /* The TSN is too high--silently discard the chunk and | 6135 | /* The TSN is too high--silently discard the chunk and |
6128 | * count on it getting retransmitted later. | 6136 | * count on it getting retransmitted later. |
6129 | */ | 6137 | */ |
6138 | if (chunk->asoc) | ||
6139 | chunk->asoc->stats.outofseqtsns++; | ||
6130 | return SCTP_IERROR_HIGH_TSN; | 6140 | return SCTP_IERROR_HIGH_TSN; |
6131 | } else if (tmp > 0) { | 6141 | } else if (tmp > 0) { |
6132 | /* This is a duplicate. Record it. */ | 6142 | /* This is a duplicate. Record it. */ |
@@ -6226,10 +6236,14 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6226 | /* Note: Some chunks may get overcounted (if we drop) or overcounted | 6236 | /* Note: Some chunks may get overcounted (if we drop) or overcounted |
6227 | * if we renege and the chunk arrives again. | 6237 | * if we renege and the chunk arrives again. |
6228 | */ | 6238 | */ |
6229 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) | 6239 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { |
6230 | SCTP_INC_STATS(net, SCTP_MIB_INUNORDERCHUNKS); | 6240 | SCTP_INC_STATS(net, SCTP_MIB_INUNORDERCHUNKS); |
6231 | else { | 6241 | if (chunk->asoc) |
6242 | chunk->asoc->stats.iuodchunks++; | ||
6243 | } else { | ||
6232 | SCTP_INC_STATS(net, SCTP_MIB_INORDERCHUNKS); | 6244 | SCTP_INC_STATS(net, SCTP_MIB_INORDERCHUNKS); |
6245 | if (chunk->asoc) | ||
6246 | chunk->asoc->stats.iodchunks++; | ||
6233 | ordered = 1; | 6247 | ordered = 1; |
6234 | } | 6248 | } |
6235 | 6249 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 59d16ea927f0..9e65758cb038 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -110,7 +110,6 @@ static int sctp_do_bind(struct sock *, union sctp_addr *, int); | |||
110 | static int sctp_autobind(struct sock *sk); | 110 | static int sctp_autobind(struct sock *sk); |
111 | static void sctp_sock_migrate(struct sock *, struct sock *, | 111 | static void sctp_sock_migrate(struct sock *, struct sock *, |
112 | struct sctp_association *, sctp_socket_type_t); | 112 | struct sctp_association *, sctp_socket_type_t); |
113 | static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; | ||
114 | 113 | ||
115 | extern struct kmem_cache *sctp_bucket_cachep; | 114 | extern struct kmem_cache *sctp_bucket_cachep; |
116 | extern long sysctl_sctp_mem[3]; | 115 | extern long sysctl_sctp_mem[3]; |
@@ -336,6 +335,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, | |||
336 | /* Bind a local address either to an endpoint or to an association. */ | 335 | /* Bind a local address either to an endpoint or to an association. */ |
337 | SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) | 336 | SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) |
338 | { | 337 | { |
338 | struct net *net = sock_net(sk); | ||
339 | struct sctp_sock *sp = sctp_sk(sk); | 339 | struct sctp_sock *sp = sctp_sk(sk); |
340 | struct sctp_endpoint *ep = sp->ep; | 340 | struct sctp_endpoint *ep = sp->ep; |
341 | struct sctp_bind_addr *bp = &ep->base.bind_addr; | 341 | struct sctp_bind_addr *bp = &ep->base.bind_addr; |
@@ -379,7 +379,8 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) | |||
379 | } | 379 | } |
380 | } | 380 | } |
381 | 381 | ||
382 | if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) | 382 | if (snum && snum < PROT_SOCK && |
383 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) | ||
383 | return -EACCES; | 384 | return -EACCES; |
384 | 385 | ||
385 | /* See if the address matches any of the addresses we may have | 386 | /* See if the address matches any of the addresses we may have |
@@ -610,6 +611,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, | |||
610 | 2*asoc->pathmtu, 4380)); | 611 | 2*asoc->pathmtu, 4380)); |
611 | trans->ssthresh = asoc->peer.i.a_rwnd; | 612 | trans->ssthresh = asoc->peer.i.a_rwnd; |
612 | trans->rto = asoc->rto_initial; | 613 | trans->rto = asoc->rto_initial; |
614 | sctp_max_rto(asoc, trans); | ||
613 | trans->rtt = trans->srtt = trans->rttvar = 0; | 615 | trans->rtt = trans->srtt = trans->rttvar = 0; |
614 | sctp_transport_route(trans, NULL, | 616 | sctp_transport_route(trans, NULL, |
615 | sctp_sk(asoc->base.sk)); | 617 | sctp_sk(asoc->base.sk)); |
@@ -974,7 +976,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, | |||
974 | void *addr_buf; | 976 | void *addr_buf; |
975 | struct sctp_af *af; | 977 | struct sctp_af *af; |
976 | 978 | ||
977 | SCTP_DEBUG_PRINTK("sctp_setsocktopt_bindx: sk %p addrs %p" | 979 | SCTP_DEBUG_PRINTK("sctp_setsockopt_bindx: sk %p addrs %p" |
978 | " addrs_size %d opt %d\n", sk, addrs, addrs_size, op); | 980 | " addrs_size %d opt %d\n", sk, addrs, addrs_size, op); |
979 | 981 | ||
980 | if (unlikely(addrs_size <= 0)) | 982 | if (unlikely(addrs_size <= 0)) |
@@ -1162,7 +1164,7 @@ static int __sctp_connect(struct sock* sk, | |||
1162 | * be permitted to open new associations. | 1164 | * be permitted to open new associations. |
1163 | */ | 1165 | */ |
1164 | if (ep->base.bind_addr.port < PROT_SOCK && | 1166 | if (ep->base.bind_addr.port < PROT_SOCK && |
1165 | !capable(CAP_NET_BIND_SERVICE)) { | 1167 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { |
1166 | err = -EACCES; | 1168 | err = -EACCES; |
1167 | goto out_free; | 1169 | goto out_free; |
1168 | } | 1170 | } |
@@ -1791,7 +1793,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1791 | * associations. | 1793 | * associations. |
1792 | */ | 1794 | */ |
1793 | if (ep->base.bind_addr.port < PROT_SOCK && | 1795 | if (ep->base.bind_addr.port < PROT_SOCK && |
1794 | !capable(CAP_NET_BIND_SERVICE)) { | 1796 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { |
1795 | err = -EACCES; | 1797 | err = -EACCES; |
1796 | goto out_unlock; | 1798 | goto out_unlock; |
1797 | } | 1799 | } |
@@ -1915,8 +1917,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1915 | 1917 | ||
1916 | /* Break the message into multiple chunks of maximum size. */ | 1918 | /* Break the message into multiple chunks of maximum size. */ |
1917 | datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); | 1919 | datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); |
1918 | if (!datamsg) { | 1920 | if (IS_ERR(datamsg)) { |
1919 | err = -ENOMEM; | 1921 | err = PTR_ERR(datamsg); |
1920 | goto out_free; | 1922 | goto out_free; |
1921 | } | 1923 | } |
1922 | 1924 | ||
@@ -3890,6 +3892,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3890 | sp->default_rcv_context = 0; | 3892 | sp->default_rcv_context = 0; |
3891 | sp->max_burst = net->sctp.max_burst; | 3893 | sp->max_burst = net->sctp.max_burst; |
3892 | 3894 | ||
3895 | sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg; | ||
3896 | |||
3893 | /* Initialize default setup parameters. These parameters | 3897 | /* Initialize default setup parameters. These parameters |
3894 | * can be modified with the SCTP_INITMSG socket option or | 3898 | * can be modified with the SCTP_INITMSG socket option or |
3895 | * overridden by the SCTP_INIT CMSG. | 3899 | * overridden by the SCTP_INIT CMSG. |
@@ -5632,6 +5636,71 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk, | |||
5632 | return 0; | 5636 | return 0; |
5633 | } | 5637 | } |
5634 | 5638 | ||
5639 | /* | ||
5640 | * SCTP_GET_ASSOC_STATS | ||
5641 | * | ||
5642 | * This option retrieves local per endpoint statistics. It is modeled | ||
5643 | * after OpenSolaris' implementation | ||
5644 | */ | ||
5645 | static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, | ||
5646 | char __user *optval, | ||
5647 | int __user *optlen) | ||
5648 | { | ||
5649 | struct sctp_assoc_stats sas; | ||
5650 | struct sctp_association *asoc = NULL; | ||
5651 | |||
5652 | /* User must provide at least the assoc id */ | ||
5653 | if (len < sizeof(sctp_assoc_t)) | ||
5654 | return -EINVAL; | ||
5655 | |||
5656 | if (copy_from_user(&sas, optval, len)) | ||
5657 | return -EFAULT; | ||
5658 | |||
5659 | asoc = sctp_id2assoc(sk, sas.sas_assoc_id); | ||
5660 | if (!asoc) | ||
5661 | return -EINVAL; | ||
5662 | |||
5663 | sas.sas_rtxchunks = asoc->stats.rtxchunks; | ||
5664 | sas.sas_gapcnt = asoc->stats.gapcnt; | ||
5665 | sas.sas_outofseqtsns = asoc->stats.outofseqtsns; | ||
5666 | sas.sas_osacks = asoc->stats.osacks; | ||
5667 | sas.sas_isacks = asoc->stats.isacks; | ||
5668 | sas.sas_octrlchunks = asoc->stats.octrlchunks; | ||
5669 | sas.sas_ictrlchunks = asoc->stats.ictrlchunks; | ||
5670 | sas.sas_oodchunks = asoc->stats.oodchunks; | ||
5671 | sas.sas_iodchunks = asoc->stats.iodchunks; | ||
5672 | sas.sas_ouodchunks = asoc->stats.ouodchunks; | ||
5673 | sas.sas_iuodchunks = asoc->stats.iuodchunks; | ||
5674 | sas.sas_idupchunks = asoc->stats.idupchunks; | ||
5675 | sas.sas_opackets = asoc->stats.opackets; | ||
5676 | sas.sas_ipackets = asoc->stats.ipackets; | ||
5677 | |||
5678 | /* New high max rto observed, will return 0 if not a single | ||
5679 | * RTO update took place. obs_rto_ipaddr will be bogus | ||
5680 | * in such a case | ||
5681 | */ | ||
5682 | sas.sas_maxrto = asoc->stats.max_obs_rto; | ||
5683 | memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, | ||
5684 | sizeof(struct sockaddr_storage)); | ||
5685 | |||
5686 | /* Mark beginning of a new observation period */ | ||
5687 | asoc->stats.max_obs_rto = asoc->rto_min; | ||
5688 | |||
5689 | /* Allow the struct to grow and fill in as much as possible */ | ||
5690 | len = min_t(size_t, len, sizeof(sas)); | ||
5691 | |||
5692 | if (put_user(len, optlen)) | ||
5693 | return -EFAULT; | ||
5694 | |||
5695 | SCTP_DEBUG_PRINTK("sctp_getsockopt_assoc_stat(%d): %d\n", | ||
5696 | len, sas.sas_assoc_id); | ||
5697 | |||
5698 | if (copy_to_user(optval, &sas, len)) | ||
5699 | return -EFAULT; | ||
5700 | |||
5701 | return 0; | ||
5702 | } | ||
5703 | |||
5635 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 5704 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, |
5636 | char __user *optval, int __user *optlen) | 5705 | char __user *optval, int __user *optlen) |
5637 | { | 5706 | { |
@@ -5773,6 +5842,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5773 | case SCTP_PEER_ADDR_THLDS: | 5842 | case SCTP_PEER_ADDR_THLDS: |
5774 | retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); | 5843 | retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); |
5775 | break; | 5844 | break; |
5845 | case SCTP_GET_ASSOC_STATS: | ||
5846 | retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); | ||
5847 | break; | ||
5776 | default: | 5848 | default: |
5777 | retval = -ENOPROTOOPT; | 5849 | retval = -ENOPROTOOPT; |
5778 | break; | 5850 | break; |
@@ -5981,13 +6053,15 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog) | |||
5981 | struct sctp_sock *sp = sctp_sk(sk); | 6053 | struct sctp_sock *sp = sctp_sk(sk); |
5982 | struct sctp_endpoint *ep = sp->ep; | 6054 | struct sctp_endpoint *ep = sp->ep; |
5983 | struct crypto_hash *tfm = NULL; | 6055 | struct crypto_hash *tfm = NULL; |
6056 | char alg[32]; | ||
5984 | 6057 | ||
5985 | /* Allocate HMAC for generating cookie. */ | 6058 | /* Allocate HMAC for generating cookie. */ |
5986 | if (!sctp_sk(sk)->hmac && sctp_hmac_alg) { | 6059 | if (!sp->hmac && sp->sctp_hmac_alg) { |
5987 | tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC); | 6060 | sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg); |
6061 | tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC); | ||
5988 | if (IS_ERR(tfm)) { | 6062 | if (IS_ERR(tfm)) { |
5989 | net_info_ratelimited("failed to load transform for %s: %ld\n", | 6063 | net_info_ratelimited("failed to load transform for %s: %ld\n", |
5990 | sctp_hmac_alg, PTR_ERR(tfm)); | 6064 | sp->sctp_hmac_alg, PTR_ERR(tfm)); |
5991 | return -ENOSYS; | 6065 | return -ENOSYS; |
5992 | } | 6066 | } |
5993 | sctp_sk(sk)->hmac = tfm; | 6067 | sctp_sk(sk)->hmac = tfm; |
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 70e3ba5cb50b..bf3c6e8fc401 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c | |||
@@ -62,6 +62,11 @@ extern long sysctl_sctp_mem[3]; | |||
62 | extern int sysctl_sctp_rmem[3]; | 62 | extern int sysctl_sctp_rmem[3]; |
63 | extern int sysctl_sctp_wmem[3]; | 63 | extern int sysctl_sctp_wmem[3]; |
64 | 64 | ||
65 | static int proc_sctp_do_hmac_alg(ctl_table *ctl, | ||
66 | int write, | ||
67 | void __user *buffer, size_t *lenp, | ||
68 | |||
69 | loff_t *ppos); | ||
65 | static ctl_table sctp_table[] = { | 70 | static ctl_table sctp_table[] = { |
66 | { | 71 | { |
67 | .procname = "sctp_mem", | 72 | .procname = "sctp_mem", |
@@ -147,6 +152,12 @@ static ctl_table sctp_net_table[] = { | |||
147 | .proc_handler = proc_dointvec, | 152 | .proc_handler = proc_dointvec, |
148 | }, | 153 | }, |
149 | { | 154 | { |
155 | .procname = "cookie_hmac_alg", | ||
156 | .maxlen = 8, | ||
157 | .mode = 0644, | ||
158 | .proc_handler = proc_sctp_do_hmac_alg, | ||
159 | }, | ||
160 | { | ||
150 | .procname = "valid_cookie_life", | 161 | .procname = "valid_cookie_life", |
151 | .data = &init_net.sctp.valid_cookie_life, | 162 | .data = &init_net.sctp.valid_cookie_life, |
152 | .maxlen = sizeof(unsigned int), | 163 | .maxlen = sizeof(unsigned int), |
@@ -289,6 +300,54 @@ static ctl_table sctp_net_table[] = { | |||
289 | { /* sentinel */ } | 300 | { /* sentinel */ } |
290 | }; | 301 | }; |
291 | 302 | ||
303 | static int proc_sctp_do_hmac_alg(ctl_table *ctl, | ||
304 | int write, | ||
305 | void __user *buffer, size_t *lenp, | ||
306 | loff_t *ppos) | ||
307 | { | ||
308 | struct net *net = current->nsproxy->net_ns; | ||
309 | char tmp[8]; | ||
310 | ctl_table tbl; | ||
311 | int ret; | ||
312 | int changed = 0; | ||
313 | char *none = "none"; | ||
314 | |||
315 | memset(&tbl, 0, sizeof(struct ctl_table)); | ||
316 | |||
317 | if (write) { | ||
318 | tbl.data = tmp; | ||
319 | tbl.maxlen = 8; | ||
320 | } else { | ||
321 | tbl.data = net->sctp.sctp_hmac_alg ? : none; | ||
322 | tbl.maxlen = strlen(tbl.data); | ||
323 | } | ||
324 | ret = proc_dostring(&tbl, write, buffer, lenp, ppos); | ||
325 | |||
326 | if (write) { | ||
327 | #ifdef CONFIG_CRYPTO_MD5 | ||
328 | if (!strncmp(tmp, "md5", 3)) { | ||
329 | net->sctp.sctp_hmac_alg = "md5"; | ||
330 | changed = 1; | ||
331 | } | ||
332 | #endif | ||
333 | #ifdef CONFIG_CRYPTO_SHA1 | ||
334 | if (!strncmp(tmp, "sha1", 4)) { | ||
335 | net->sctp.sctp_hmac_alg = "sha1"; | ||
336 | changed = 1; | ||
337 | } | ||
338 | #endif | ||
339 | if (!strncmp(tmp, "none", 4)) { | ||
340 | net->sctp.sctp_hmac_alg = NULL; | ||
341 | changed = 1; | ||
342 | } | ||
343 | |||
344 | if (!changed) | ||
345 | ret = -EINVAL; | ||
346 | } | ||
347 | |||
348 | return ret; | ||
349 | } | ||
350 | |||
292 | int sctp_sysctl_net_register(struct net *net) | 351 | int sctp_sysctl_net_register(struct net *net) |
293 | { | 352 | { |
294 | struct ctl_table *table; | 353 | struct ctl_table *table; |
@@ -307,7 +366,11 @@ int sctp_sysctl_net_register(struct net *net) | |||
307 | 366 | ||
308 | void sctp_sysctl_net_unregister(struct net *net) | 367 | void sctp_sysctl_net_unregister(struct net *net) |
309 | { | 368 | { |
369 | struct ctl_table *table; | ||
370 | |||
371 | table = net->sctp.sysctl_header->ctl_table_arg; | ||
310 | unregister_net_sysctl_table(net->sctp.sysctl_header); | 372 | unregister_net_sysctl_table(net->sctp.sysctl_header); |
373 | kfree(table); | ||
311 | } | 374 | } |
312 | 375 | ||
313 | static struct ctl_table_header * sctp_sysctl_header; | 376 | static struct ctl_table_header * sctp_sysctl_header; |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 953c21e4af97..4e45bb68aef0 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -163,13 +163,11 @@ void sctp_transport_free(struct sctp_transport *transport) | |||
163 | sctp_transport_put(transport); | 163 | sctp_transport_put(transport); |
164 | } | 164 | } |
165 | 165 | ||
166 | /* Destroy the transport data structure. | 166 | static void sctp_transport_destroy_rcu(struct rcu_head *head) |
167 | * Assumes there are no more users of this structure. | ||
168 | */ | ||
169 | static void sctp_transport_destroy(struct sctp_transport *transport) | ||
170 | { | 167 | { |
171 | SCTP_ASSERT(transport->dead, "Transport is not dead", return); | 168 | struct sctp_transport *transport; |
172 | 169 | ||
170 | transport = container_of(head, struct sctp_transport, rcu); | ||
173 | if (transport->asoc) | 171 | if (transport->asoc) |
174 | sctp_association_put(transport->asoc); | 172 | sctp_association_put(transport->asoc); |
175 | 173 | ||
@@ -180,6 +178,16 @@ static void sctp_transport_destroy(struct sctp_transport *transport) | |||
180 | SCTP_DBG_OBJCNT_DEC(transport); | 178 | SCTP_DBG_OBJCNT_DEC(transport); |
181 | } | 179 | } |
182 | 180 | ||
181 | /* Destroy the transport data structure. | ||
182 | * Assumes there are no more users of this structure. | ||
183 | */ | ||
184 | static void sctp_transport_destroy(struct sctp_transport *transport) | ||
185 | { | ||
186 | SCTP_ASSERT(transport->dead, "Transport is not dead", return); | ||
187 | |||
188 | call_rcu(&transport->rcu, sctp_transport_destroy_rcu); | ||
189 | } | ||
190 | |||
183 | /* Start T3_rtx timer if it is not already running and update the heartbeat | 191 | /* Start T3_rtx timer if it is not already running and update the heartbeat |
184 | * timer. This routine is called every time a DATA chunk is sent. | 192 | * timer. This routine is called every time a DATA chunk is sent. |
185 | */ | 193 | */ |
@@ -331,7 +339,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) | |||
331 | * 1/8, rto_alpha would be expressed as 3. | 339 | * 1/8, rto_alpha would be expressed as 3. |
332 | */ | 340 | */ |
333 | tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta) | 341 | tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta) |
334 | + ((abs(tp->srtt - rtt)) >> net->sctp.rto_beta); | 342 | + (((__u32)abs64((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta); |
335 | tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha) | 343 | tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha) |
336 | + (rtt >> net->sctp.rto_alpha); | 344 | + (rtt >> net->sctp.rto_alpha); |
337 | } else { | 345 | } else { |
@@ -363,6 +371,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) | |||
363 | if (tp->rto > tp->asoc->rto_max) | 371 | if (tp->rto > tp->asoc->rto_max) |
364 | tp->rto = tp->asoc->rto_max; | 372 | tp->rto = tp->asoc->rto_max; |
365 | 373 | ||
374 | sctp_max_rto(tp->asoc, tp); | ||
366 | tp->rtt = rtt; | 375 | tp->rtt = rtt; |
367 | 376 | ||
368 | /* Reset rto_pending so that a new RTT measurement is started when a | 377 | /* Reset rto_pending so that a new RTT measurement is started when a |
@@ -620,6 +629,7 @@ void sctp_transport_reset(struct sctp_transport *t) | |||
620 | t->burst_limited = 0; | 629 | t->burst_limited = 0; |
621 | t->ssthresh = asoc->peer.i.a_rwnd; | 630 | t->ssthresh = asoc->peer.i.a_rwnd; |
622 | t->rto = asoc->rto_initial; | 631 | t->rto = asoc->rto_initial; |
632 | sctp_max_rto(asoc, t); | ||
623 | t->rtt = 0; | 633 | t->rtt = 0; |
624 | t->srtt = 0; | 634 | t->srtt = 0; |
625 | t->rttvar = 0; | 635 | t->rttvar = 0; |
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c index b5fb7c409023..5f25e0c92c31 100644 --- a/net/sctp/tsnmap.c +++ b/net/sctp/tsnmap.c | |||
@@ -272,7 +272,7 @@ __u16 sctp_tsnmap_pending(struct sctp_tsnmap *map) | |||
272 | __u32 max_tsn = map->max_tsn_seen; | 272 | __u32 max_tsn = map->max_tsn_seen; |
273 | __u32 base_tsn = map->base_tsn; | 273 | __u32 base_tsn = map->base_tsn; |
274 | __u16 pending_data; | 274 | __u16 pending_data; |
275 | u32 gap, i; | 275 | u32 gap; |
276 | 276 | ||
277 | pending_data = max_tsn - cum_tsn; | 277 | pending_data = max_tsn - cum_tsn; |
278 | gap = max_tsn - base_tsn; | 278 | gap = max_tsn - base_tsn; |
@@ -280,11 +280,7 @@ __u16 sctp_tsnmap_pending(struct sctp_tsnmap *map) | |||
280 | if (gap == 0 || gap >= map->len) | 280 | if (gap == 0 || gap >= map->len) |
281 | goto out; | 281 | goto out; |
282 | 282 | ||
283 | for (i = 0; i < gap+1; i++) { | 283 | pending_data -= bitmap_weight(map->tsn_map, gap + 1); |
284 | if (test_bit(i, map->tsn_map)) | ||
285 | pending_data--; | ||
286 | } | ||
287 | |||
288 | out: | 284 | out: |
289 | return pending_data; | 285 | return pending_data; |
290 | } | 286 | } |
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 360d8697b95c..ada17464b65b 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c | |||
@@ -997,7 +997,6 @@ static __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed) | |||
997 | 997 | ||
998 | /* Partial deliver the first message as there is pressure on rwnd. */ | 998 | /* Partial deliver the first message as there is pressure on rwnd. */ |
999 | void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, | 999 | void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, |
1000 | struct sctp_chunk *chunk, | ||
1001 | gfp_t gfp) | 1000 | gfp_t gfp) |
1002 | { | 1001 | { |
1003 | struct sctp_ulpevent *event; | 1002 | struct sctp_ulpevent *event; |
@@ -1060,7 +1059,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, | |||
1060 | sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport); | 1059 | sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport); |
1061 | sctp_ulpq_tail_data(ulpq, chunk, gfp); | 1060 | sctp_ulpq_tail_data(ulpq, chunk, gfp); |
1062 | 1061 | ||
1063 | sctp_ulpq_partial_delivery(ulpq, chunk, gfp); | 1062 | sctp_ulpq_partial_delivery(ulpq, gfp); |
1064 | } | 1063 | } |
1065 | 1064 | ||
1066 | sk_mem_reclaim(asoc->base.sk); | 1065 | sk_mem_reclaim(asoc->base.sk); |