diff options
Diffstat (limited to 'net/sctp')
| -rw-r--r-- | net/sctp/associola.c | 13 | ||||
| -rw-r--r-- | net/sctp/input.c | 4 | ||||
| -rw-r--r-- | net/sctp/output.c | 69 | ||||
| -rw-r--r-- | net/sctp/outqueue.c | 3 | ||||
| -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 | 18 | ||||
| -rw-r--r-- | net/sctp/stream.c | 43 | ||||
| -rw-r--r-- | net/sctp/transport.c | 19 |
10 files changed, 107 insertions, 81 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 0439a1a68367..a9708da28eb5 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
| @@ -246,6 +246,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 246 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) | 246 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) |
| 247 | goto fail_init; | 247 | goto fail_init; |
| 248 | 248 | ||
| 249 | if (sctp_stream_new(asoc, gfp)) | ||
| 250 | goto fail_init; | ||
| 251 | |||
| 249 | /* Assume that peer would support both address types unless we are | 252 | /* Assume that peer would support both address types unless we are |
| 250 | * told otherwise. | 253 | * told otherwise. |
| 251 | */ | 254 | */ |
| @@ -264,7 +267,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 264 | /* AUTH related initializations */ | 267 | /* AUTH related initializations */ |
| 265 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); | 268 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); |
| 266 | if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp)) | 269 | if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp)) |
| 267 | goto fail_init; | 270 | goto stream_free; |
| 268 | 271 | ||
| 269 | asoc->active_key_id = ep->active_key_id; | 272 | asoc->active_key_id = ep->active_key_id; |
| 270 | asoc->prsctp_enable = ep->prsctp_enable; | 273 | asoc->prsctp_enable = ep->prsctp_enable; |
| @@ -287,6 +290,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 287 | 290 | ||
| 288 | return asoc; | 291 | return asoc; |
| 289 | 292 | ||
| 293 | stream_free: | ||
| 294 | sctp_stream_free(asoc->stream); | ||
| 290 | fail_init: | 295 | fail_init: |
| 291 | sock_put(asoc->base.sk); | 296 | sock_put(asoc->base.sk); |
| 292 | sctp_endpoint_put(asoc->ep); | 297 | sctp_endpoint_put(asoc->ep); |
| @@ -1407,7 +1412,7 @@ sctp_assoc_choose_alter_transport(struct sctp_association *asoc, | |||
| 1407 | /* 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 |
| 1408 | * 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. |
| 1409 | */ | 1414 | */ |
| 1410 | void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | 1415 | void sctp_assoc_sync_pmtu(struct sctp_association *asoc) |
| 1411 | { | 1416 | { |
| 1412 | struct sctp_transport *t; | 1417 | struct sctp_transport *t; |
| 1413 | __u32 pmtu = 0; | 1418 | __u32 pmtu = 0; |
| @@ -1419,8 +1424,8 @@ void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | |||
| 1419 | list_for_each_entry(t, &asoc->peer.transport_addr_list, | 1424 | list_for_each_entry(t, &asoc->peer.transport_addr_list, |
| 1420 | transports) { | 1425 | transports) { |
| 1421 | if (t->pmtu_pending && t->dst) { | 1426 | if (t->pmtu_pending && t->dst) { |
| 1422 | sctp_transport_update_pmtu(sk, t, | 1427 | sctp_transport_update_pmtu( |
| 1423 | SCTP_TRUNC4(dst_mtu(t->dst))); | 1428 | t, SCTP_TRUNC4(dst_mtu(t->dst))); |
| 1424 | t->pmtu_pending = 0; | 1429 | t->pmtu_pending = 0; |
| 1425 | } | 1430 | } |
| 1426 | 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 1224421036b3..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. */ |
| @@ -582,12 +592,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) | |||
| 582 | sh->vtag = htonl(packet->vtag); | 592 | sh->vtag = htonl(packet->vtag); |
| 583 | sh->checksum = 0; | 593 | sh->checksum = 0; |
| 584 | 594 | ||
| 585 | /* update dst if in need */ | 595 | /* drop packet if no dst */ |
| 586 | if (!sctp_transport_dst_check(tp)) { | ||
| 587 | sctp_transport_route(tp, NULL, sctp_sk(sk)); | ||
| 588 | if (asoc && asoc->param_flags & SPP_PMTUD_ENABLE) | ||
| 589 | sctp_assoc_sync_pmtu(sk, asoc); | ||
| 590 | } | ||
| 591 | dst = dst_clone(tp->dst); | 596 | dst = dst_clone(tp->dst); |
| 592 | if (!dst) { | 597 | if (!dst) { |
| 593 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 598 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
| @@ -704,7 +709,7 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | |||
| 704 | */ | 709 | */ |
| 705 | 710 | ||
| 706 | if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && | 711 | if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && |
| 707 | !chunk->msg->force_delay) | 712 | !asoc->force_delay) |
| 708 | /* Nothing unacked */ | 713 | /* Nothing unacked */ |
| 709 | return SCTP_XMIT_OK; | 714 | return SCTP_XMIT_OK; |
| 710 | 715 | ||
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 3f78d7f06e14..fe4c3d462f6e 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
| @@ -1036,8 +1036,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
| 1036 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid | 1036 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid |
| 1037 | * stream identifier. | 1037 | * stream identifier. |
| 1038 | */ | 1038 | */ |
| 1039 | if (chunk->sinfo.sinfo_stream >= | 1039 | if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) { |
| 1040 | asoc->c.sinit_num_ostreams) { | ||
| 1041 | 1040 | ||
| 1042 | /* Mark as failed send. */ | 1041 | /* Mark as failed send. */ |
| 1043 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); | 1042 | 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 ab1374fa5ab0..4f5e6cfc7f60 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -3955,7 +3955,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(struct net *net, | |||
| 3955 | 3955 | ||
| 3956 | /* Silently discard the chunk if stream-id is not valid */ | 3956 | /* Silently discard the chunk if stream-id is not valid */ |
| 3957 | sctp_walk_fwdtsn(skip, chunk) { | 3957 | sctp_walk_fwdtsn(skip, chunk) { |
| 3958 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | 3958 | if (ntohs(skip->stream) >= asoc->stream->incnt) |
| 3959 | goto discard_noforce; | 3959 | goto discard_noforce; |
| 3960 | } | 3960 | } |
| 3961 | 3961 | ||
| @@ -4026,7 +4026,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( | |||
| 4026 | 4026 | ||
| 4027 | /* Silently discard the chunk if stream-id is not valid */ | 4027 | /* Silently discard the chunk if stream-id is not valid */ |
| 4028 | sctp_walk_fwdtsn(skip, chunk) { | 4028 | sctp_walk_fwdtsn(skip, chunk) { |
| 4029 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | 4029 | if (ntohs(skip->stream) >= asoc->stream->incnt) |
| 4030 | goto gen_shutdown; | 4030 | goto gen_shutdown; |
| 4031 | } | 4031 | } |
| 4032 | 4032 | ||
| @@ -6362,7 +6362,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
| 6362 | * and discard the DATA chunk. | 6362 | * and discard the DATA chunk. |
| 6363 | */ | 6363 | */ |
| 6364 | sid = ntohs(data_hdr->stream); | 6364 | sid = ntohs(data_hdr->stream); |
| 6365 | if (sid >= asoc->c.sinit_max_instreams) { | 6365 | if (sid >= asoc->stream->incnt) { |
| 6366 | /* Mark tsn as received even though we drop it */ | 6366 | /* Mark tsn as received even though we drop it */ |
| 6367 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); | 6367 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); |
| 6368 | 6368 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6489446925e6..8e56df8d175d 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 = |
| @@ -4497,8 +4497,8 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, | |||
| 4497 | info->sctpi_rwnd = asoc->a_rwnd; | 4497 | info->sctpi_rwnd = asoc->a_rwnd; |
| 4498 | info->sctpi_unackdata = asoc->unack_data; | 4498 | info->sctpi_unackdata = asoc->unack_data; |
| 4499 | info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); | 4499 | info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); |
| 4500 | info->sctpi_instrms = asoc->c.sinit_max_instreams; | 4500 | info->sctpi_instrms = asoc->stream->incnt; |
| 4501 | info->sctpi_outstrms = asoc->c.sinit_num_ostreams; | 4501 | info->sctpi_outstrms = asoc->stream->outcnt; |
| 4502 | list_for_each(pos, &asoc->base.inqueue.in_chunk_list) | 4502 | list_for_each(pos, &asoc->base.inqueue.in_chunk_list) |
| 4503 | info->sctpi_inqueue++; | 4503 | info->sctpi_inqueue++; |
| 4504 | list_for_each(pos, &asoc->outqueue.out_chunk_list) | 4504 | list_for_each(pos, &asoc->outqueue.out_chunk_list) |
| @@ -4727,8 +4727,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, | |||
| 4727 | status.sstat_unackdata = asoc->unack_data; | 4727 | status.sstat_unackdata = asoc->unack_data; |
| 4728 | 4728 | ||
| 4729 | status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); | 4729 | status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); |
| 4730 | status.sstat_instrms = asoc->c.sinit_max_instreams; | 4730 | status.sstat_instrms = asoc->stream->incnt; |
| 4731 | status.sstat_outstrms = asoc->c.sinit_num_ostreams; | 4731 | status.sstat_outstrms = asoc->stream->outcnt; |
| 4732 | status.sstat_fragmentation_point = asoc->frag_point; | 4732 | status.sstat_fragmentation_point = asoc->frag_point; |
| 4733 | status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); | 4733 | status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); |
| 4734 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, | 4734 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, |
diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 961d0a1e99d1..eff6008a32ba 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 |
