diff options
Diffstat (limited to 'net/sctp')
| -rw-r--r-- | net/sctp/associola.c | 19 | ||||
| -rw-r--r-- | net/sctp/input.c | 4 | ||||
| -rw-r--r-- | net/sctp/output.c | 76 | ||||
| -rw-r--r-- | net/sctp/outqueue.c | 14 | ||||
| -rw-r--r-- | net/sctp/proc.c | 4 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 9 | ||||
| -rw-r--r-- | net/sctp/sm_statefuns.c | 6 | ||||
| -rw-r--r-- | net/sctp/socket.c | 21 | ||||
| -rw-r--r-- | net/sctp/stream.c | 43 | ||||
| -rw-r--r-- | net/sctp/transport.c | 19 |
10 files changed, 120 insertions, 95 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 2a6835b4562b..a9708da28eb5 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
| @@ -71,9 +71,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 71 | { | 71 | { |
| 72 | struct net *net = sock_net(sk); | 72 | struct net *net = sock_net(sk); |
| 73 | struct sctp_sock *sp; | 73 | struct sctp_sock *sp; |
| 74 | int i; | ||
| 75 | sctp_paramhdr_t *p; | 74 | sctp_paramhdr_t *p; |
| 76 | int err; | 75 | int i; |
| 77 | 76 | ||
| 78 | /* Retrieve the SCTP per socket area. */ | 77 | /* Retrieve the SCTP per socket area. */ |
| 79 | sp = sctp_sk((struct sock *)sk); | 78 | sp = sctp_sk((struct sock *)sk); |
| @@ -247,6 +246,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 247 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) | 246 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) |
| 248 | goto fail_init; | 247 | goto fail_init; |
| 249 | 248 | ||
| 249 | if (sctp_stream_new(asoc, gfp)) | ||
| 250 | goto fail_init; | ||
| 251 | |||
| 250 | /* Assume that peer would support both address types unless we are | 252 | /* Assume that peer would support both address types unless we are |
| 251 | * told otherwise. | 253 | * told otherwise. |
| 252 | */ | 254 | */ |
| @@ -264,9 +266,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 264 | 266 | ||
| 265 | /* AUTH related initializations */ | 267 | /* AUTH related initializations */ |
| 266 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); | 268 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); |
| 267 | err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); | 269 | if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp)) |
| 268 | if (err) | 270 | goto stream_free; |
| 269 | goto fail_init; | ||
| 270 | 271 | ||
| 271 | asoc->active_key_id = ep->active_key_id; | 272 | asoc->active_key_id = ep->active_key_id; |
| 272 | asoc->prsctp_enable = ep->prsctp_enable; | 273 | asoc->prsctp_enable = ep->prsctp_enable; |
| @@ -289,6 +290,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 289 | 290 | ||
| 290 | return asoc; | 291 | return asoc; |
| 291 | 292 | ||
| 293 | stream_free: | ||
| 294 | sctp_stream_free(asoc->stream); | ||
| 292 | fail_init: | 295 | fail_init: |
| 293 | sock_put(asoc->base.sk); | 296 | sock_put(asoc->base.sk); |
| 294 | sctp_endpoint_put(asoc->ep); | 297 | sctp_endpoint_put(asoc->ep); |
| @@ -1409,7 +1412,7 @@ sctp_assoc_choose_alter_transport(struct sctp_association *asoc, | |||
| 1409 | /* Update the association's pmtu and frag_point by going through all the | 1412 | /* Update the association's pmtu and frag_point by going through all the |
| 1410 | * transports. This routine is called when a transport's PMTU has changed. | 1413 | * transports. This routine is called when a transport's PMTU has changed. |
| 1411 | */ | 1414 | */ |
| 1412 | void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | 1415 | void sctp_assoc_sync_pmtu(struct sctp_association *asoc) |
| 1413 | { | 1416 | { |
| 1414 | struct sctp_transport *t; | 1417 | struct sctp_transport *t; |
| 1415 | __u32 pmtu = 0; | 1418 | __u32 pmtu = 0; |
| @@ -1421,8 +1424,8 @@ void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | |||
| 1421 | list_for_each_entry(t, &asoc->peer.transport_addr_list, | 1424 | list_for_each_entry(t, &asoc->peer.transport_addr_list, |
| 1422 | transports) { | 1425 | transports) { |
| 1423 | if (t->pmtu_pending && t->dst) { | 1426 | if (t->pmtu_pending && t->dst) { |
| 1424 | sctp_transport_update_pmtu(sk, t, | 1427 | sctp_transport_update_pmtu( |
| 1425 | SCTP_TRUNC4(dst_mtu(t->dst))); | 1428 | t, SCTP_TRUNC4(dst_mtu(t->dst))); |
| 1426 | t->pmtu_pending = 0; | 1429 | t->pmtu_pending = 0; |
| 1427 | } | 1430 | } |
| 1428 | if (!pmtu || (t->pathmtu < pmtu)) | 1431 | if (!pmtu || (t->pathmtu < pmtu)) |
diff --git a/net/sctp/input.c b/net/sctp/input.c index 2a28ab20487f..0e06a278d2a9 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
| @@ -401,10 +401,10 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, | |||
| 401 | 401 | ||
| 402 | if (t->param_flags & SPP_PMTUD_ENABLE) { | 402 | if (t->param_flags & SPP_PMTUD_ENABLE) { |
| 403 | /* Update transports view of the MTU */ | 403 | /* Update transports view of the MTU */ |
| 404 | sctp_transport_update_pmtu(sk, t, pmtu); | 404 | sctp_transport_update_pmtu(t, pmtu); |
| 405 | 405 | ||
| 406 | /* Update association pmtu. */ | 406 | /* Update association pmtu. */ |
| 407 | sctp_assoc_sync_pmtu(sk, asoc); | 407 | sctp_assoc_sync_pmtu(asoc); |
| 408 | } | 408 | } |
| 409 | 409 | ||
| 410 | /* Retransmit with the new pmtu setting. | 410 | /* Retransmit with the new pmtu setting. |
diff --git a/net/sctp/output.c b/net/sctp/output.c index 71ce6b945dcb..1409a875ad8e 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
| @@ -86,43 +86,53 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag, | |||
| 86 | { | 86 | { |
| 87 | struct sctp_transport *tp = packet->transport; | 87 | struct sctp_transport *tp = packet->transport; |
| 88 | struct sctp_association *asoc = tp->asoc; | 88 | struct sctp_association *asoc = tp->asoc; |
| 89 | struct sock *sk; | ||
| 89 | 90 | ||
| 90 | pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); | 91 | pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); |
| 91 | |||
| 92 | packet->vtag = vtag; | 92 | packet->vtag = vtag; |
| 93 | 93 | ||
| 94 | if (asoc && tp->dst) { | 94 | /* do the following jobs only once for a flush schedule */ |
| 95 | struct sock *sk = asoc->base.sk; | 95 | if (!sctp_packet_empty(packet)) |
| 96 | 96 | return; | |
| 97 | rcu_read_lock(); | ||
| 98 | if (__sk_dst_get(sk) != tp->dst) { | ||
| 99 | dst_hold(tp->dst); | ||
| 100 | sk_setup_caps(sk, tp->dst); | ||
| 101 | } | ||
| 102 | |||
| 103 | if (sk_can_gso(sk)) { | ||
| 104 | struct net_device *dev = tp->dst->dev; | ||
| 105 | 97 | ||
| 106 | packet->max_size = dev->gso_max_size; | 98 | /* set packet max_size with pathmtu */ |
| 107 | } else { | 99 | packet->max_size = tp->pathmtu; |
| 108 | packet->max_size = asoc->pathmtu; | 100 | if (!asoc) |
| 109 | } | 101 | return; |
| 110 | rcu_read_unlock(); | ||
| 111 | 102 | ||
| 112 | } else { | 103 | /* update dst or transport pathmtu if in need */ |
| 113 | packet->max_size = tp->pathmtu; | 104 | sk = asoc->base.sk; |
| 105 | if (!sctp_transport_dst_check(tp)) { | ||
| 106 | sctp_transport_route(tp, NULL, sctp_sk(sk)); | ||
| 107 | if (asoc->param_flags & SPP_PMTUD_ENABLE) | ||
| 108 | sctp_assoc_sync_pmtu(asoc); | ||
| 109 | } else if (!sctp_transport_pmtu_check(tp)) { | ||
| 110 | if (asoc->param_flags & SPP_PMTUD_ENABLE) | ||
| 111 | sctp_assoc_sync_pmtu(asoc); | ||
| 114 | } | 112 | } |
| 115 | 113 | ||
| 116 | if (ecn_capable && sctp_packet_empty(packet)) { | 114 | /* If there a is a prepend chunk stick it on the list before |
| 117 | struct sctp_chunk *chunk; | 115 | * any other chunks get appended. |
| 116 | */ | ||
| 117 | if (ecn_capable) { | ||
| 118 | struct sctp_chunk *chunk = sctp_get_ecne_prepend(asoc); | ||
| 118 | 119 | ||
| 119 | /* If there a is a prepend chunk stick it on the list before | ||
| 120 | * any other chunks get appended. | ||
| 121 | */ | ||
| 122 | chunk = sctp_get_ecne_prepend(asoc); | ||
| 123 | if (chunk) | 120 | if (chunk) |
| 124 | sctp_packet_append_chunk(packet, chunk); | 121 | sctp_packet_append_chunk(packet, chunk); |
| 125 | } | 122 | } |
| 123 | |||
| 124 | if (!tp->dst) | ||
| 125 | return; | ||
| 126 | |||
| 127 | /* set packet max_size with gso_max_size if gso is enabled*/ | ||
| 128 | rcu_read_lock(); | ||
| 129 | if (__sk_dst_get(sk) != tp->dst) { | ||
| 130 | dst_hold(tp->dst); | ||
| 131 | sk_setup_caps(sk, tp->dst); | ||
| 132 | } | ||
| 133 | packet->max_size = sk_can_gso(sk) ? tp->dst->dev->gso_max_size | ||
| 134 | : asoc->pathmtu; | ||
| 135 | rcu_read_unlock(); | ||
| 126 | } | 136 | } |
| 127 | 137 | ||
| 128 | /* Initialize the packet structure. */ | 138 | /* Initialize the packet structure. */ |
| @@ -546,7 +556,6 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) | |||
| 546 | struct sctp_association *asoc = tp->asoc; | 556 | struct sctp_association *asoc = tp->asoc; |
| 547 | struct sctp_chunk *chunk, *tmp; | 557 | struct sctp_chunk *chunk, *tmp; |
| 548 | int pkt_count, gso = 0; | 558 | int pkt_count, gso = 0; |
| 549 | int confirm; | ||
| 550 | struct dst_entry *dst; | 559 | struct dst_entry *dst; |
| 551 | struct sk_buff *head; | 560 | struct sk_buff *head; |
| 552 | struct sctphdr *sh; | 561 | struct sctphdr *sh; |
| @@ -583,12 +592,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) | |||
| 583 | sh->vtag = htonl(packet->vtag); | 592 | sh->vtag = htonl(packet->vtag); |
| 584 | sh->checksum = 0; | 593 | sh->checksum = 0; |
| 585 | 594 | ||
| 586 | /* update dst if in need */ | 595 | /* drop packet if no dst */ |
| 587 | if (!sctp_transport_dst_check(tp)) { | ||
| 588 | sctp_transport_route(tp, NULL, sctp_sk(sk)); | ||
| 589 | if (asoc && asoc->param_flags & SPP_PMTUD_ENABLE) | ||
| 590 | sctp_assoc_sync_pmtu(sk, asoc); | ||
| 591 | } | ||
| 592 | dst = dst_clone(tp->dst); | 596 | dst = dst_clone(tp->dst); |
| 593 | if (!dst) { | 597 | if (!dst) { |
| 594 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 598 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
| @@ -625,13 +629,13 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) | |||
| 625 | asoc->peer.last_sent_to = tp; | 629 | asoc->peer.last_sent_to = tp; |
| 626 | } | 630 | } |
| 627 | head->ignore_df = packet->ipfragok; | 631 | head->ignore_df = packet->ipfragok; |
| 628 | confirm = tp->dst_pending_confirm; | 632 | if (tp->dst_pending_confirm) |
| 629 | if (confirm) | ||
| 630 | skb_set_dst_pending_confirm(head, 1); | 633 | skb_set_dst_pending_confirm(head, 1); |
| 631 | /* neighbour should be confirmed on successful transmission or | 634 | /* neighbour should be confirmed on successful transmission or |
| 632 | * positive error | 635 | * positive error |
| 633 | */ | 636 | */ |
| 634 | if (tp->af_specific->sctp_xmit(head, tp) >= 0 && confirm) | 637 | if (tp->af_specific->sctp_xmit(head, tp) >= 0 && |
| 638 | tp->dst_pending_confirm) | ||
| 635 | tp->dst_pending_confirm = 0; | 639 | tp->dst_pending_confirm = 0; |
| 636 | 640 | ||
| 637 | out: | 641 | out: |
| @@ -705,7 +709,7 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | |||
| 705 | */ | 709 | */ |
| 706 | 710 | ||
| 707 | if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && | 711 | if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && |
| 708 | !chunk->msg->force_delay) | 712 | !asoc->force_delay) |
| 709 | /* Nothing unacked */ | 713 | /* Nothing unacked */ |
| 710 | return SCTP_XMIT_OK; | 714 | return SCTP_XMIT_OK; |
| 711 | 715 | ||
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index db352e5d61f8..8081476ed313 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
| @@ -382,17 +382,18 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc, | |||
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, | 384 | static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, |
| 385 | struct sctp_sndrcvinfo *sinfo, | 385 | struct sctp_sndrcvinfo *sinfo, int msg_len) |
| 386 | struct list_head *queue, int msg_len) | ||
| 387 | { | 386 | { |
| 387 | struct sctp_outq *q = &asoc->outqueue; | ||
| 388 | struct sctp_chunk *chk, *temp; | 388 | struct sctp_chunk *chk, *temp; |
| 389 | 389 | ||
| 390 | list_for_each_entry_safe(chk, temp, queue, list) { | 390 | list_for_each_entry_safe(chk, temp, &q->out_chunk_list, list) { |
| 391 | if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || | 391 | if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || |
| 392 | chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive) | 392 | chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive) |
| 393 | continue; | 393 | continue; |
| 394 | 394 | ||
| 395 | list_del_init(&chk->list); | 395 | list_del_init(&chk->list); |
| 396 | q->out_qlen -= chk->skb->len; | ||
| 396 | asoc->sent_cnt_removable--; | 397 | asoc->sent_cnt_removable--; |
| 397 | asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; | 398 | asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; |
| 398 | 399 | ||
| @@ -431,9 +432,7 @@ void sctp_prsctp_prune(struct sctp_association *asoc, | |||
| 431 | return; | 432 | return; |
| 432 | } | 433 | } |
| 433 | 434 | ||
| 434 | sctp_prsctp_prune_unsent(asoc, sinfo, | 435 | sctp_prsctp_prune_unsent(asoc, sinfo, msg_len); |
| 435 | &asoc->outqueue.out_chunk_list, | ||
| 436 | msg_len); | ||
| 437 | } | 436 | } |
| 438 | 437 | ||
| 439 | /* Mark all the eligible packets on a transport for retransmission. */ | 438 | /* Mark all the eligible packets on a transport for retransmission. */ |
| @@ -1027,8 +1026,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
| 1027 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid | 1026 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid |
| 1028 | * stream identifier. | 1027 | * stream identifier. |
| 1029 | */ | 1028 | */ |
| 1030 | if (chunk->sinfo.sinfo_stream >= | 1029 | if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) { |
| 1031 | asoc->c.sinit_num_ostreams) { | ||
| 1032 | 1030 | ||
| 1033 | /* Mark as failed send. */ | 1031 | /* Mark as failed send. */ |
| 1034 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); | 1032 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); |
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 206377fe91ec..a0b29d43627f 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
| @@ -361,8 +361,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | |||
| 361 | sctp_seq_dump_remote_addrs(seq, assoc); | 361 | sctp_seq_dump_remote_addrs(seq, assoc); |
| 362 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " | 362 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " |
| 363 | "%8d %8d %8d %8d", | 363 | "%8d %8d %8d %8d", |
| 364 | assoc->hbinterval, assoc->c.sinit_max_instreams, | 364 | assoc->hbinterval, assoc->stream->incnt, |
| 365 | assoc->c.sinit_num_ostreams, assoc->max_retrans, | 365 | assoc->stream->outcnt, assoc->max_retrans, |
| 366 | assoc->init_retries, assoc->shutdown_retries, | 366 | assoc->init_retries, assoc->shutdown_retries, |
| 367 | assoc->rtx_data_chunks, | 367 | assoc->rtx_data_chunks, |
| 368 | atomic_read(&sk->sk_wmem_alloc), | 368 | atomic_read(&sk->sk_wmem_alloc), |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 969a30c7bb54..118faff6a332 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
| @@ -2460,15 +2460,10 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, | |||
| 2460 | * association. | 2460 | * association. |
| 2461 | */ | 2461 | */ |
| 2462 | if (!asoc->temp) { | 2462 | if (!asoc->temp) { |
| 2463 | int error; | 2463 | if (sctp_stream_init(asoc, gfp)) |
| 2464 | |||
| 2465 | asoc->stream = sctp_stream_new(asoc->c.sinit_max_instreams, | ||
| 2466 | asoc->c.sinit_num_ostreams, gfp); | ||
| 2467 | if (!asoc->stream) | ||
| 2468 | goto clean_up; | 2464 | goto clean_up; |
| 2469 | 2465 | ||
| 2470 | error = sctp_assoc_set_id(asoc, gfp); | 2466 | if (sctp_assoc_set_id(asoc, gfp)) |
| 2471 | if (error) | ||
| 2472 | goto clean_up; | 2467 | goto clean_up; |
| 2473 | } | 2468 | } |
| 2474 | 2469 | ||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index e03bb1aab4d0..24c6ccce7539 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -3946,7 +3946,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(struct net *net, | |||
| 3946 | 3946 | ||
| 3947 | /* Silently discard the chunk if stream-id is not valid */ | 3947 | /* Silently discard the chunk if stream-id is not valid */ |
| 3948 | sctp_walk_fwdtsn(skip, chunk) { | 3948 | sctp_walk_fwdtsn(skip, chunk) { |
| 3949 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | 3949 | if (ntohs(skip->stream) >= asoc->stream->incnt) |
| 3950 | goto discard_noforce; | 3950 | goto discard_noforce; |
| 3951 | } | 3951 | } |
| 3952 | 3952 | ||
| @@ -4017,7 +4017,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( | |||
| 4017 | 4017 | ||
| 4018 | /* Silently discard the chunk if stream-id is not valid */ | 4018 | /* Silently discard the chunk if stream-id is not valid */ |
| 4019 | sctp_walk_fwdtsn(skip, chunk) { | 4019 | sctp_walk_fwdtsn(skip, chunk) { |
| 4020 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | 4020 | if (ntohs(skip->stream) >= asoc->stream->incnt) |
| 4021 | goto gen_shutdown; | 4021 | goto gen_shutdown; |
| 4022 | } | 4022 | } |
| 4023 | 4023 | ||
| @@ -6353,7 +6353,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
| 6353 | * and discard the DATA chunk. | 6353 | * and discard the DATA chunk. |
| 6354 | */ | 6354 | */ |
| 6355 | sid = ntohs(data_hdr->stream); | 6355 | sid = ntohs(data_hdr->stream); |
| 6356 | if (sid >= asoc->c.sinit_max_instreams) { | 6356 | if (sid >= asoc->stream->incnt) { |
| 6357 | /* Mark tsn as received even though we drop it */ | 6357 | /* Mark tsn as received even though we drop it */ |
| 6358 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); | 6358 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); |
| 6359 | 6359 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0f378ea2ae38..d9d4c92e06b3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -1907,7 +1907,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
| 1907 | } | 1907 | } |
| 1908 | 1908 | ||
| 1909 | if (asoc->pmtu_pending) | 1909 | if (asoc->pmtu_pending) |
| 1910 | sctp_assoc_pending_pmtu(sk, asoc); | 1910 | sctp_assoc_pending_pmtu(asoc); |
| 1911 | 1911 | ||
| 1912 | /* If fragmentation is disabled and the message length exceeds the | 1912 | /* If fragmentation is disabled and the message length exceeds the |
| 1913 | * association fragmentation point, return EMSGSIZE. The I-D | 1913 | * association fragmentation point, return EMSGSIZE. The I-D |
| @@ -1920,7 +1920,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
| 1920 | } | 1920 | } |
| 1921 | 1921 | ||
| 1922 | /* Check for invalid stream. */ | 1922 | /* Check for invalid stream. */ |
| 1923 | if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { | 1923 | if (sinfo->sinfo_stream >= asoc->stream->outcnt) { |
| 1924 | err = -EINVAL; | 1924 | err = -EINVAL; |
| 1925 | goto out_free; | 1925 | goto out_free; |
| 1926 | } | 1926 | } |
| @@ -1965,7 +1965,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
| 1965 | err = PTR_ERR(datamsg); | 1965 | err = PTR_ERR(datamsg); |
| 1966 | goto out_free; | 1966 | goto out_free; |
| 1967 | } | 1967 | } |
| 1968 | datamsg->force_delay = !!(msg->msg_flags & MSG_MORE); | 1968 | asoc->force_delay = !!(msg->msg_flags & MSG_MORE); |
| 1969 | 1969 | ||
| 1970 | /* Now send the (possibly) fragmented message. */ | 1970 | /* Now send the (possibly) fragmented message. */ |
| 1971 | list_for_each_entry(chunk, &datamsg->chunks, frag_list) { | 1971 | list_for_each_entry(chunk, &datamsg->chunks, frag_list) { |
| @@ -2435,7 +2435,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
| 2435 | if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { | 2435 | if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { |
| 2436 | if (trans) { | 2436 | if (trans) { |
| 2437 | trans->pathmtu = params->spp_pathmtu; | 2437 | trans->pathmtu = params->spp_pathmtu; |
| 2438 | sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); | 2438 | sctp_assoc_sync_pmtu(asoc); |
| 2439 | } else if (asoc) { | 2439 | } else if (asoc) { |
| 2440 | asoc->pathmtu = params->spp_pathmtu; | 2440 | asoc->pathmtu = params->spp_pathmtu; |
| 2441 | } else { | 2441 | } else { |
| @@ -2451,7 +2451,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
| 2451 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; | 2451 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; |
| 2452 | if (update) { | 2452 | if (update) { |
| 2453 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); | 2453 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); |
| 2454 | sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); | 2454 | sctp_assoc_sync_pmtu(asoc); |
| 2455 | } | 2455 | } |
| 2456 | } else if (asoc) { | 2456 | } else if (asoc) { |
| 2457 | asoc->param_flags = | 2457 | asoc->param_flags = |
| @@ -4461,8 +4461,8 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, | |||
| 4461 | info->sctpi_rwnd = asoc->a_rwnd; | 4461 | info->sctpi_rwnd = asoc->a_rwnd; |
| 4462 | info->sctpi_unackdata = asoc->unack_data; | 4462 | info->sctpi_unackdata = asoc->unack_data; |
| 4463 | info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); | 4463 | info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); |
| 4464 | info->sctpi_instrms = asoc->c.sinit_max_instreams; | 4464 | info->sctpi_instrms = asoc->stream->incnt; |
| 4465 | info->sctpi_outstrms = asoc->c.sinit_num_ostreams; | 4465 | info->sctpi_outstrms = asoc->stream->outcnt; |
| 4466 | list_for_each(pos, &asoc->base.inqueue.in_chunk_list) | 4466 | list_for_each(pos, &asoc->base.inqueue.in_chunk_list) |
| 4467 | info->sctpi_inqueue++; | 4467 | info->sctpi_inqueue++; |
| 4468 | list_for_each(pos, &asoc->outqueue.out_chunk_list) | 4468 | list_for_each(pos, &asoc->outqueue.out_chunk_list) |
| @@ -4691,8 +4691,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, | |||
| 4691 | status.sstat_unackdata = asoc->unack_data; | 4691 | status.sstat_unackdata = asoc->unack_data; |
| 4692 | 4692 | ||
| 4693 | status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); | 4693 | status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); |
| 4694 | status.sstat_instrms = asoc->c.sinit_max_instreams; | 4694 | status.sstat_instrms = asoc->stream->incnt; |
| 4695 | status.sstat_outstrms = asoc->c.sinit_num_ostreams; | 4695 | status.sstat_outstrms = asoc->stream->outcnt; |
| 4696 | status.sstat_fragmentation_point = asoc->frag_point; | 4696 | status.sstat_fragmentation_point = asoc->frag_point; |
| 4697 | status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); | 4697 | status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); |
| 4698 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, | 4698 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, |
| @@ -7034,6 +7034,9 @@ int sctp_inet_listen(struct socket *sock, int backlog) | |||
| 7034 | if (sock->state != SS_UNCONNECTED) | 7034 | if (sock->state != SS_UNCONNECTED) |
| 7035 | goto out; | 7035 | goto out; |
| 7036 | 7036 | ||
| 7037 | if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED)) | ||
| 7038 | goto out; | ||
| 7039 | |||
| 7037 | /* If backlog is zero, disable listening. */ | 7040 | /* If backlog is zero, disable listening. */ |
| 7038 | if (!backlog) { | 7041 | if (!backlog) { |
| 7039 | if (sctp_sstate(sk, CLOSED)) | 7042 | if (sctp_sstate(sk, CLOSED)) |
diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 1c6cc04fa3a4..bbed997e1c5f 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c | |||
| @@ -35,33 +35,60 @@ | |||
| 35 | #include <net/sctp/sctp.h> | 35 | #include <net/sctp/sctp.h> |
| 36 | #include <net/sctp/sm.h> | 36 | #include <net/sctp/sm.h> |
| 37 | 37 | ||
| 38 | struct sctp_stream *sctp_stream_new(__u16 incnt, __u16 outcnt, gfp_t gfp) | 38 | int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp) |
| 39 | { | 39 | { |
| 40 | struct sctp_stream *stream; | 40 | struct sctp_stream *stream; |
| 41 | int i; | 41 | int i; |
| 42 | 42 | ||
| 43 | stream = kzalloc(sizeof(*stream), gfp); | 43 | stream = kzalloc(sizeof(*stream), gfp); |
| 44 | if (!stream) | 44 | if (!stream) |
| 45 | return NULL; | 45 | return -ENOMEM; |
| 46 | 46 | ||
| 47 | stream->outcnt = outcnt; | 47 | stream->outcnt = asoc->c.sinit_num_ostreams; |
| 48 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); | 48 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); |
| 49 | if (!stream->out) { | 49 | if (!stream->out) { |
| 50 | kfree(stream); | 50 | kfree(stream); |
| 51 | return NULL; | 51 | return -ENOMEM; |
| 52 | } | 52 | } |
| 53 | for (i = 0; i < stream->outcnt; i++) | 53 | for (i = 0; i < stream->outcnt; i++) |
| 54 | stream->out[i].state = SCTP_STREAM_OPEN; | 54 | stream->out[i].state = SCTP_STREAM_OPEN; |
| 55 | 55 | ||
| 56 | stream->incnt = incnt; | 56 | asoc->stream = stream; |
| 57 | |||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp) | ||
| 62 | { | ||
| 63 | struct sctp_stream *stream = asoc->stream; | ||
| 64 | int i; | ||
| 65 | |||
| 66 | /* Initial stream->out size may be very big, so free it and alloc | ||
| 67 | * a new one with new outcnt to save memory. | ||
| 68 | */ | ||
| 69 | kfree(stream->out); | ||
| 70 | stream->outcnt = asoc->c.sinit_num_ostreams; | ||
| 71 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); | ||
| 72 | if (!stream->out) | ||
| 73 | goto nomem; | ||
| 74 | |||
| 75 | for (i = 0; i < stream->outcnt; i++) | ||
| 76 | stream->out[i].state = SCTP_STREAM_OPEN; | ||
| 77 | |||
| 78 | stream->incnt = asoc->c.sinit_max_instreams; | ||
| 57 | stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp); | 79 | stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp); |
| 58 | if (!stream->in) { | 80 | if (!stream->in) { |
| 59 | kfree(stream->out); | 81 | kfree(stream->out); |
| 60 | kfree(stream); | 82 | goto nomem; |
| 61 | return NULL; | ||
| 62 | } | 83 | } |
| 63 | 84 | ||
| 64 | return stream; | 85 | return 0; |
| 86 | |||
| 87 | nomem: | ||
| 88 | asoc->stream = NULL; | ||
| 89 | kfree(stream); | ||
| 90 | |||
| 91 | return -ENOMEM; | ||
| 65 | } | 92 | } |
| 66 | 93 | ||
| 67 | void sctp_stream_free(struct sctp_stream *stream) | 94 | void sctp_stream_free(struct sctp_stream *stream) |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 3379668af368..721eeebfcd8a 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
| @@ -251,14 +251,13 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) | |||
| 251 | transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; | 251 | transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 pmtu) | 254 | void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) |
| 255 | { | 255 | { |
| 256 | struct dst_entry *dst; | 256 | struct dst_entry *dst = sctp_transport_dst_check(t); |
| 257 | 257 | ||
| 258 | if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { | 258 | if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { |
| 259 | pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n", | 259 | pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n", |
| 260 | __func__, pmtu, | 260 | __func__, pmtu, SCTP_DEFAULT_MINSEGMENT); |
| 261 | SCTP_DEFAULT_MINSEGMENT); | ||
| 262 | /* Use default minimum segment size and disable | 261 | /* Use default minimum segment size and disable |
| 263 | * pmtu discovery on this transport. | 262 | * pmtu discovery on this transport. |
| 264 | */ | 263 | */ |
| @@ -267,17 +266,13 @@ void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 p | |||
| 267 | t->pathmtu = pmtu; | 266 | t->pathmtu = pmtu; |
| 268 | } | 267 | } |
| 269 | 268 | ||
| 270 | dst = sctp_transport_dst_check(t); | ||
| 271 | if (!dst) | ||
| 272 | t->af_specific->get_dst(t, &t->saddr, &t->fl, sk); | ||
| 273 | |||
| 274 | if (dst) { | 269 | if (dst) { |
| 275 | dst->ops->update_pmtu(dst, sk, NULL, pmtu); | 270 | dst->ops->update_pmtu(dst, t->asoc->base.sk, NULL, pmtu); |
| 276 | |||
| 277 | dst = sctp_transport_dst_check(t); | 271 | dst = sctp_transport_dst_check(t); |
| 278 | if (!dst) | ||
| 279 | t->af_specific->get_dst(t, &t->saddr, &t->fl, sk); | ||
| 280 | } | 272 | } |
| 273 | |||
| 274 | if (!dst) | ||
| 275 | t->af_specific->get_dst(t, &t->saddr, &t->fl, t->asoc->base.sk); | ||
| 281 | } | 276 | } |
| 282 | 277 | ||
| 283 | /* Caches the dst entry and source address for a transport's destination | 278 | /* Caches the dst entry and source address for a transport's destination |
