summaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/associola.c47
-rw-r--r--net/sctp/chunk.c4
-rw-r--r--net/sctp/offload.c7
-rw-r--r--net/sctp/output.c8
-rw-r--r--net/sctp/outqueue.c10
-rw-r--r--net/sctp/proc.c10
-rw-r--r--net/sctp/sm_make_chunk.c18
-rw-r--r--net/sctp/sm_sideeffect.c28
-rw-r--r--net/sctp/sm_statefuns.c12
-rw-r--r--net/sctp/socket.c20
-rw-r--r--net/sctp/stream.c93
-rw-r--r--net/sctp/ulpevent.c37
-rw-r--r--net/sctp/ulpqueue.c8
13 files changed, 151 insertions, 151 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 95238284c422..757be416f778 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -246,7 +246,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
if (!sctp_ulpq_init(&asoc->ulpq, asoc))
goto fail_init;
- if (sctp_stream_new(asoc, gfp))
+ if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams,
+ 0, gfp))
goto fail_init;
/* Assume that peer would support both address types unless we are
@@ -291,7 +292,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
return asoc;
stream_free:
- sctp_stream_free(asoc->stream);
+ sctp_stream_free(&asoc->stream);
fail_init:
sock_put(asoc->base.sk);
sctp_endpoint_put(asoc->ep);
@@ -365,7 +366,7 @@ void sctp_association_free(struct sctp_association *asoc)
sctp_tsnmap_free(&asoc->peer.tsn_map);
/* Free stream information. */
- sctp_stream_free(asoc->stream);
+ sctp_stream_free(&asoc->stream);
if (asoc->strreset_chunk)
sctp_chunk_free(asoc->strreset_chunk);
@@ -1111,8 +1112,8 @@ void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk)
}
/* Update an association (possibly from unexpected COOKIE-ECHO processing). */
-void sctp_assoc_update(struct sctp_association *asoc,
- struct sctp_association *new)
+int sctp_assoc_update(struct sctp_association *asoc,
+ struct sctp_association *new)
{
struct sctp_transport *trans;
struct list_head *pos, *temp;
@@ -1123,8 +1124,10 @@ void sctp_assoc_update(struct sctp_association *asoc,
asoc->peer.sack_needed = new->peer.sack_needed;
asoc->peer.auth_capable = new->peer.auth_capable;
asoc->peer.i = new->peer.i;
- sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
- asoc->peer.i.initial_tsn, GFP_ATOMIC);
+
+ if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
+ asoc->peer.i.initial_tsn, GFP_ATOMIC))
+ return -ENOMEM;
/* Remove any peer addresses not present in the new association. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
@@ -1151,7 +1154,7 @@ void sctp_assoc_update(struct sctp_association *asoc,
/* Reinitialize SSN for both local streams
* and peer's streams.
*/
- sctp_stream_clear(asoc->stream);
+ sctp_stream_clear(&asoc->stream);
/* Flush the ULP reassembly and ordered queue.
* Any data there will now be stale and will
@@ -1168,27 +1171,21 @@ void sctp_assoc_update(struct sctp_association *asoc,
} else {
/* Add any peer addresses from the new association. */
list_for_each_entry(trans, &new->peer.transport_addr_list,
- transports) {
- if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr))
- sctp_assoc_add_peer(asoc, &trans->ipaddr,
- GFP_ATOMIC, trans->state);
- }
+ transports)
+ if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr) &&
+ !sctp_assoc_add_peer(asoc, &trans->ipaddr,
+ GFP_ATOMIC, trans->state))
+ return -ENOMEM;
asoc->ctsn_ack_point = asoc->next_tsn - 1;
asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
- if (sctp_state(asoc, COOKIE_WAIT)) {
- sctp_stream_free(asoc->stream);
- asoc->stream = new->stream;
- new->stream = NULL;
- }
+ if (sctp_state(asoc, COOKIE_WAIT))
+ sctp_stream_update(&asoc->stream, &new->stream);
- if (!asoc->assoc_id) {
- /* get a new association id since we don't have one
- * yet.
- */
- sctp_assoc_set_id(asoc, GFP_ATOMIC);
- }
+ /* get a new assoc id if we don't have one yet. */
+ if (sctp_assoc_set_id(asoc, GFP_ATOMIC))
+ return -ENOMEM;
}
/* SCTP-AUTH: Save the peer parameters from the new associations
@@ -1206,7 +1203,7 @@ void sctp_assoc_update(struct sctp_association *asoc,
asoc->peer.peer_hmacs = new->peer.peer_hmacs;
new->peer.peer_hmacs = NULL;
- sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
+ return sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
}
/* Update the retran path for sending a retransmitted packet.
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 697721a7a3f1..81466f6442e8 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -307,7 +307,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) &&
time_after(jiffies, chunk->msg->expires_at)) {
struct sctp_stream_out *streamout =
- &chunk->asoc->stream->out[chunk->sinfo.sinfo_stream];
+ &chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
if (chunk->sent_count) {
chunk->asoc->abandoned_sent[SCTP_PR_INDEX(TTL)]++;
@@ -320,7 +320,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
} else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) &&
chunk->sent_count > chunk->sinfo.sinfo_timetolive) {
struct sctp_stream_out *streamout =
- &chunk->asoc->stream->out[chunk->sinfo.sinfo_stream];
+ &chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
streamout->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
diff --git a/net/sctp/offload.c b/net/sctp/offload.c
index 4f5a2b580aa5..275925b93b29 100644
--- a/net/sctp/offload.c
+++ b/net/sctp/offload.c
@@ -35,6 +35,7 @@
static __le32 sctp_gso_make_checksum(struct sk_buff *skb)
{
skb->ip_summed = CHECKSUM_NONE;
+ skb->csum_not_inet = 0;
return sctp_compute_cksum(skb, skb_transport_offset(skb));
}
@@ -98,6 +99,11 @@ static const struct net_offload sctp6_offload = {
},
};
+static const struct skb_checksum_ops crc32c_csum_ops = {
+ .update = sctp_csum_update,
+ .combine = sctp_csum_combine,
+};
+
int __init sctp_offload_init(void)
{
int ret;
@@ -110,6 +116,7 @@ int __init sctp_offload_init(void)
if (ret)
goto ipv4;
+ crc32c_csum_stub = &crc32c_csum_ops;
return ret;
ipv4:
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 1409a875ad8e..89cee1482d35 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -463,14 +463,13 @@ merge:
padding = SCTP_PAD4(chunk->skb->len) - chunk->skb->len;
if (padding)
- memset(skb_put(chunk->skb, padding), 0, padding);
+ skb_put_zero(chunk->skb, padding);
if (chunk == packet->auth)
auth = (struct sctp_auth_chunk *)
skb_tail_pointer(nskb);
- memcpy(skb_put(nskb, chunk->skb->len), chunk->skb->data,
- chunk->skb->len);
+ skb_put_data(nskb, chunk->skb->data, chunk->skb->len);
pr_debug("*** Chunk:%p[%s] %s 0x%x, length:%d, chunk->skb->len:%d, rtt_in_progress:%d\n",
chunk,
@@ -538,6 +537,7 @@ merge:
} else {
chksum:
head->ip_summed = CHECKSUM_PARTIAL;
+ head->csum_not_inet = 1;
head->csum_start = skb_transport_header(head) - head->head;
head->csum_offset = offsetof(struct sctphdr, checksum);
}
@@ -585,7 +585,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
sctp_packet_set_owner_w(head, sk);
/* set sctp header */
- sh = (struct sctphdr *)skb_push(head, sizeof(struct sctphdr));
+ sh = skb_push(head, sizeof(struct sctphdr));
skb_reset_transport_header(head);
sh->source = htons(packet->source_port);
sh->dest = htons(packet->destination_port);
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index fe4c3d462f6e..20299df163b9 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -363,7 +363,7 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc,
sctp_insert_list(&asoc->outqueue.abandoned,
&chk->transmitted_list);
- streamout = &asoc->stream->out[chk->sinfo.sinfo_stream];
+ streamout = &asoc->stream.out[chk->sinfo.sinfo_stream];
asoc->sent_cnt_removable--;
asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
streamout->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
@@ -400,9 +400,9 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
q->out_qlen -= chk->skb->len;
asoc->sent_cnt_removable--;
asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
- if (chk->sinfo.sinfo_stream < asoc->stream->outcnt) {
+ if (chk->sinfo.sinfo_stream < asoc->stream.outcnt) {
struct sctp_stream_out *streamout =
- &asoc->stream->out[chk->sinfo.sinfo_stream];
+ &asoc->stream.out[chk->sinfo.sinfo_stream];
streamout->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
}
@@ -1036,7 +1036,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
* stream identifier.
*/
- if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) {
+ if (chunk->sinfo.sinfo_stream >= asoc->stream.outcnt) {
/* Mark as failed send. */
sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM);
@@ -1054,7 +1054,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
continue;
}
- if (asoc->stream->out[sid].state == SCTP_STREAM_CLOSED) {
+ if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
sctp_outq_head_data(q, chunk);
goto sctp_flush_out;
}
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index a0b29d43627f..8e34db56bc1d 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -218,8 +218,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
return -ENOMEM;
head = &sctp_ep_hashtable[hash];
- local_bh_disable();
- read_lock(&head->lock);
+ read_lock_bh(&head->lock);
sctp_for_each_hentry(epb, &head->chain) {
ep = sctp_ep(epb);
sk = epb->sk;
@@ -234,8 +233,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
sctp_seq_dump_local_addrs(seq, epb);
seq_printf(seq, "\n");
}
- read_unlock(&head->lock);
- local_bh_enable();
+ read_unlock_bh(&head->lock);
return 0;
}
@@ -361,8 +359,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
sctp_seq_dump_remote_addrs(seq, assoc);
seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d "
"%8d %8d %8d %8d",
- assoc->hbinterval, assoc->stream->incnt,
- assoc->stream->outcnt, assoc->max_retrans,
+ assoc->hbinterval, assoc->stream.incnt,
+ assoc->stream.outcnt, assoc->max_retrans,
assoc->init_retries, assoc->shutdown_retries,
assoc->rtx_data_chunks,
atomic_read(&sk->sk_wmem_alloc),
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 92e332e17391..4b1967997c16 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1296,8 +1296,7 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(sctp_authhdr_t),
&auth_hdr);
- hmac = skb_put(retval->skb, hmac_desc->hmac_len);
- memset(hmac, 0, hmac_desc->hmac_len);
+ hmac = skb_put_zero(retval->skb, hmac_desc->hmac_len);
/* Adjust the chunk header to include the empty MAC */
retval->chunk_hdr->length =
@@ -1390,7 +1389,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
goto nodata;
/* Make room for the chunk header. */
- chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t));
+ chunk_hdr = skb_put(skb, sizeof(sctp_chunkhdr_t));
chunk_hdr->type = type;
chunk_hdr->flags = flags;
chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t));
@@ -1475,15 +1474,11 @@ void sctp_chunk_put(struct sctp_chunk *ch)
void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
{
void *target;
- void *padding;
int chunklen = ntohs(chunk->chunk_hdr->length);
int padlen = SCTP_PAD4(chunklen) - chunklen;
- padding = skb_put(chunk->skb, padlen);
- target = skb_put(chunk->skb, len);
-
- memset(padding, 0, padlen);
- memcpy(target, data, len);
+ skb_put_zero(chunk->skb, padlen);
+ target = skb_put_data(chunk->skb, data, len);
/* Adjust the chunk length field. */
chunk->chunk_hdr->length = htons(chunklen + padlen + len);
@@ -1544,7 +1539,7 @@ void sctp_chunk_assign_ssn(struct sctp_chunk *chunk)
/* All fragments will be on the same stream */
sid = ntohs(chunk->subh.data_hdr->stream);
- stream = chunk->asoc->stream;
+ stream = &chunk->asoc->stream;
/* Now assign the sequence number to the entire message.
* All fragments must have the same stream sequence number.
@@ -2454,7 +2449,8 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
* stream sequence number shall be set to 0.
*/
- if (sctp_stream_init(asoc, gfp))
+ if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams,
+ asoc->c.sinit_max_instreams, gfp))
goto clean_up;
if (!asoc->temp && sctp_assoc_set_id(asoc, gfp))
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 25384fa82ba9..dfe1fcb520ba 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -818,6 +818,28 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
}
+static void sctp_cmd_assoc_update(sctp_cmd_seq_t *cmds,
+ struct sctp_association *asoc,
+ struct sctp_association *new)
+{
+ struct net *net = sock_net(asoc->base.sk);
+ struct sctp_chunk *abort;
+
+ if (!sctp_assoc_update(asoc, new))
+ return;
+
+ abort = sctp_make_abort(asoc, NULL, sizeof(sctp_errhdr_t));
+ if (abort) {
+ sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0);
+ sctp_add_cmd_sf(cmds, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+ }
+ sctp_add_cmd_sf(cmds, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNABORTED));
+ sctp_add_cmd_sf(cmds, SCTP_CMD_ASSOC_FAILED,
+ SCTP_PERR(SCTP_ERROR_RSRC_LOW));
+ SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+ SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
+}
+
/* Helper function to change the state of an association. */
static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc,
@@ -1294,7 +1316,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
break;
case SCTP_CMD_UPDATE_ASSOC:
- sctp_assoc_update(asoc, cmd->obj.asoc);
+ sctp_cmd_assoc_update(commands, asoc, cmd->obj.asoc);
break;
case SCTP_CMD_PURGE_OUTQUEUE:
@@ -1748,6 +1770,10 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
break;
case SCTP_CMD_SET_ASOC:
+ if (asoc && local_cork) {
+ sctp_outq_uncork(&asoc->outqueue, gfp);
+ local_cork = 0;
+ }
asoc = cmd->obj.asoc;
break;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index f863b5573e42..8feff96a5bef 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -770,8 +770,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
auth.skb = chunk->auth_chunk;
auth.asoc = chunk->asoc;
auth.sctp_hdr = chunk->sctp_hdr;
- auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk,
- sizeof(sctp_chunkhdr_t));
+ auth.chunk_hdr = skb_push(chunk->auth_chunk,
+ sizeof(sctp_chunkhdr_t));
skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t));
auth.transport = chunk->transport;
@@ -3958,7 +3958,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(struct net *net,
/* Silently discard the chunk if stream-id is not valid */
sctp_walk_fwdtsn(skip, chunk) {
- if (ntohs(skip->stream) >= asoc->stream->incnt)
+ if (ntohs(skip->stream) >= asoc->stream.incnt)
goto discard_noforce;
}
@@ -4029,7 +4029,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
/* Silently discard the chunk if stream-id is not valid */
sctp_walk_fwdtsn(skip, chunk) {
- if (ntohs(skip->stream) >= asoc->stream->incnt)
+ if (ntohs(skip->stream) >= asoc->stream.incnt)
goto gen_shutdown;
}
@@ -6365,7 +6365,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
* and discard the DATA chunk.
*/
sid = ntohs(data_hdr->stream);
- if (sid >= asoc->stream->incnt) {
+ if (sid >= asoc->stream.incnt) {
/* Mark tsn as received even though we drop it */
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
@@ -6387,7 +6387,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
* and is invalid.
*/
ssn = ntohs(data_hdr->ssn);
- if (ordered && SSN_lt(ssn, sctp_ssn_peek(asoc->stream, in, sid)))
+ if (ordered && SSN_lt(ssn, sctp_ssn_peek(&asoc->stream, in, sid)))
return SCTP_IERROR_PROTO_VIOLATION;
/* Send the data up to the user. Note: Schedule the
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 3a8318e518f1..7b6e20eb9451 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -103,7 +103,7 @@ static int sctp_autobind(struct sock *sk);
static void sctp_sock_migrate(struct sock *, struct sock *,
struct sctp_association *, sctp_socket_type_t);
-static int sctp_memory_pressure;
+static unsigned long sctp_memory_pressure;
static atomic_long_t sctp_memory_allocated;
struct percpu_counter sctp_sockets_allocated;
@@ -1494,7 +1494,7 @@ static void sctp_close(struct sock *sk, long timeout)
pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout);
- lock_sock(sk);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
sk->sk_shutdown = SHUTDOWN_MASK;
sk->sk_state = SCTP_SS_CLOSING;
@@ -1544,7 +1544,7 @@ static void sctp_close(struct sock *sk, long timeout)
* held and that should be grabbed before socket lock.
*/
spin_lock_bh(&net->sctp.addr_wq_lock);
- bh_lock_sock(sk);
+ bh_lock_sock_nested(sk);
/* Hold the sock, since sk_common_release() will put sock_put()
* and we have just a little more cleanup.
@@ -1920,7 +1920,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
}
/* Check for invalid stream. */
- if (sinfo->sinfo_stream >= asoc->stream->outcnt) {
+ if (sinfo->sinfo_stream >= asoc->stream.outcnt) {
err = -EINVAL;
goto out_free;
}
@@ -4497,8 +4497,8 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
info->sctpi_rwnd = asoc->a_rwnd;
info->sctpi_unackdata = asoc->unack_data;
info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
- info->sctpi_instrms = asoc->stream->incnt;
- info->sctpi_outstrms = asoc->stream->outcnt;
+ info->sctpi_instrms = asoc->stream.incnt;
+ info->sctpi_outstrms = asoc->stream.outcnt;
list_for_each(pos, &asoc->base.inqueue.in_chunk_list)
info->sctpi_inqueue++;
list_for_each(pos, &asoc->outqueue.out_chunk_list)
@@ -4726,8 +4726,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
status.sstat_unackdata = asoc->unack_data;
status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
- status.sstat_instrms = asoc->stream->incnt;
- status.sstat_outstrms = asoc->stream->outcnt;
+ status.sstat_instrms = asoc->stream.incnt;
+ status.sstat_outstrms = asoc->stream.outcnt;
status.sstat_fragmentation_point = asoc->frag_point;
status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
@@ -6599,10 +6599,10 @@ static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len,
goto out;
asoc = sctp_id2assoc(sk, params.sprstat_assoc_id);
- if (!asoc || params.sprstat_sid >= asoc->stream->outcnt)
+ if (!asoc || params.sprstat_sid >= asoc->stream.outcnt)
goto out;
- streamout = &asoc->stream->out[params.sprstat_sid];
+ streamout = &asoc->stream.out[params.sprstat_sid];
if (policy == SCTP_PR_SCTP_NONE) {
params.sprstat_abandoned_unsent = 0;
params.sprstat_abandoned_sent = 0;
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index dda53a293986..82e6d40052a8 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -35,70 +35,43 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
-int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp)
+int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
+ gfp_t gfp)
{
- struct sctp_stream *stream;
- int i;
-
- stream = kzalloc(sizeof(*stream), gfp);
- if (!stream)
- return -ENOMEM;
-
- stream->outcnt = asoc->c.sinit_num_ostreams;
- stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp);
- if (!stream->out) {
- kfree(stream);
- return -ENOMEM;
- }
- for (i = 0; i < stream->outcnt; i++)
- stream->out[i].state = SCTP_STREAM_OPEN;
-
- asoc->stream = stream;
-
- return 0;
-}
-
-int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp)
-{
- struct sctp_stream *stream = asoc->stream;
int i;
/* Initial stream->out size may be very big, so free it and alloc
* a new one with new outcnt to save memory.
*/
kfree(stream->out);
- stream->outcnt = asoc->c.sinit_num_ostreams;
- stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp);
+
+ stream->out = kcalloc(outcnt, sizeof(*stream->out), gfp);
if (!stream->out)
- goto nomem;
+ return -ENOMEM;
+ stream->outcnt = outcnt;
for (i = 0; i < stream->outcnt; i++)
stream->out[i].state = SCTP_STREAM_OPEN;
- stream->incnt = asoc->c.sinit_max_instreams;
- stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp);
+ if (!incnt)
+ return 0;
+
+ stream->in = kcalloc(incnt, sizeof(*stream->in), gfp);
if (!stream->in) {
kfree(stream->out);
- goto nomem;
+ stream->out = NULL;
+ return -ENOMEM;
}
- return 0;
-
-nomem:
- asoc->stream = NULL;
- kfree(stream);
+ stream->incnt = incnt;
- return -ENOMEM;
+ return 0;
}
void sctp_stream_free(struct sctp_stream *stream)
{
- if (unlikely(!stream))
- return;
-
kfree(stream->out);
kfree(stream->in);
- kfree(stream);
}
void sctp_stream_clear(struct sctp_stream *stream)
@@ -112,6 +85,19 @@ void sctp_stream_clear(struct sctp_stream *stream)
stream->in[i].ssn = 0;
}
+void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
+{
+ sctp_stream_free(stream);
+
+ stream->out = new->out;
+ stream->in = new->in;
+ stream->outcnt = new->outcnt;
+ stream->incnt = new->incnt;
+
+ new->out = NULL;
+ new->in = NULL;
+}
+
static int sctp_send_reconf(struct sctp_association *asoc,
struct sctp_chunk *chunk)
{
@@ -128,7 +114,7 @@ static int sctp_send_reconf(struct sctp_association *asoc,
int sctp_send_reset_streams(struct sctp_association *asoc,
struct sctp_reset_streams *params)
{
- struct sctp_stream *stream = asoc->stream;
+ struct sctp_stream *stream = &asoc->stream;
__u16 i, str_nums, *str_list;
struct sctp_chunk *chunk;
int retval = -EINVAL;
@@ -214,6 +200,7 @@ out:
int sctp_send_reset_assoc(struct sctp_association *asoc)
{
+ struct sctp_stream *stream = &asoc->stream;
struct sctp_chunk *chunk = NULL;
int retval;
__u16 i;
@@ -230,8 +217,8 @@ int sctp_send_reset_assoc(struct sctp_association *asoc)
return -ENOMEM;
/* Block further xmit of data until this request is completed */
- for (i = 0; i < asoc->stream->outcnt; i++)
- asoc->stream->out[i].state = SCTP_STREAM_CLOSED;
+ for (i = 0; i < stream->outcnt; i++)
+ stream->out[i].state = SCTP_STREAM_CLOSED;
asoc->strreset_chunk = chunk;
sctp_chunk_hold(asoc->strreset_chunk);
@@ -241,8 +228,8 @@ int sctp_send_reset_assoc(struct sctp_association *asoc)
sctp_chunk_put(asoc->strreset_chunk);
asoc->strreset_chunk = NULL;
- for (i = 0; i < asoc->stream->outcnt; i++)
- asoc->stream->out[i].state = SCTP_STREAM_OPEN;
+ for (i = 0; i < stream->outcnt; i++)
+ stream->out[i].state = SCTP_STREAM_OPEN;
return retval;
}
@@ -255,7 +242,7 @@ int sctp_send_reset_assoc(struct sctp_association *asoc)
int sctp_send_add_streams(struct sctp_association *asoc,
struct sctp_add_streams *params)
{
- struct sctp_stream *stream = asoc->stream;
+ struct sctp_stream *stream = &asoc->stream;
struct sctp_chunk *chunk = NULL;
int retval = -ENOMEM;
__u32 outcnt, incnt;
@@ -357,7 +344,7 @@ struct sctp_chunk *sctp_process_strreset_outreq(
struct sctp_ulpevent **evp)
{
struct sctp_strreset_outreq *outreq = param.v;
- struct sctp_stream *stream = asoc->stream;
+ struct sctp_stream *stream = &asoc->stream;
__u16 i, nums, flags = 0, *str_p = NULL;
__u32 result = SCTP_STRRESET_DENIED;
__u32 request_seq;
@@ -449,7 +436,7 @@ struct sctp_chunk *sctp_process_strreset_inreq(
struct sctp_ulpevent **evp)
{
struct sctp_strreset_inreq *inreq = param.v;
- struct sctp_stream *stream = asoc->stream;
+ struct sctp_stream *stream = &asoc->stream;
__u32 result = SCTP_STRRESET_DENIED;
struct sctp_chunk *chunk = NULL;
__u16 i, nums, *str_p;
@@ -523,7 +510,7 @@ struct sctp_chunk *sctp_process_strreset_tsnreq(
{
__u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
struct sctp_strreset_tsnreq *tsnreq = param.v;
- struct sctp_stream *stream = asoc->stream;
+ struct sctp_stream *stream = &asoc->stream;
__u32 result = SCTP_STRRESET_DENIED;
__u32 request_seq;
__u16 i;
@@ -612,7 +599,7 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out(
struct sctp_ulpevent **evp)
{
struct sctp_strreset_addstrm *addstrm = param.v;
- struct sctp_stream *stream = asoc->stream;
+ struct sctp_stream *stream = &asoc->stream;
__u32 result = SCTP_STRRESET_DENIED;
struct sctp_stream_in *streamin;
__u32 request_seq, incnt;
@@ -687,7 +674,7 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in(
struct sctp_ulpevent **evp)
{
struct sctp_strreset_addstrm *addstrm = param.v;
- struct sctp_stream *stream = asoc->stream;
+ struct sctp_stream *stream = &asoc->stream;
__u32 result = SCTP_STRRESET_DENIED;
struct sctp_stream_out *streamout;
struct sctp_chunk *chunk = NULL;
@@ -758,8 +745,8 @@ struct sctp_chunk *sctp_process_strreset_resp(
union sctp_params param,
struct sctp_ulpevent **evp)
{
+ struct sctp_stream *stream = &asoc->stream;
struct sctp_strreset_resp *resp = param.v;
- struct sctp_stream *stream = asoc->stream;
struct sctp_transport *t;
__u16 i, nums, flags = 0;
sctp_paramhdr_t *req;
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index ec2b3e013c2f..17854fb0e512 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -153,8 +153,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
/* Include the notification structure */
- sac = (struct sctp_assoc_change *)
- skb_push(skb, sizeof(struct sctp_assoc_change));
+ sac = skb_push(skb, sizeof(struct sctp_assoc_change));
/* Trim the buffer to the right length. */
skb_trim(skb, sizeof(struct sctp_assoc_change) +
@@ -167,8 +166,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
goto fail;
skb = sctp_event2skb(event);
- sac = (struct sctp_assoc_change *) skb_put(skb,
- sizeof(struct sctp_assoc_change));
+ sac = skb_put(skb, sizeof(struct sctp_assoc_change));
}
/* Socket Extensions for SCTP
@@ -270,8 +268,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
goto fail;
skb = sctp_event2skb(event);
- spc = (struct sctp_paddr_change *)
- skb_put(skb, sizeof(struct sctp_paddr_change));
+ spc = skb_put(skb, sizeof(struct sctp_paddr_change));
/* Sockets API Extensions for SCTP
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
@@ -402,7 +399,7 @@ sctp_ulpevent_make_remote_error(const struct sctp_association *asoc,
event = sctp_skb2event(skb);
sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
- sre = (struct sctp_remote_error *) skb_push(skb, sizeof(*sre));
+ sre = skb_push(skb, sizeof(*sre));
/* Trim the buffer to the right length. */
skb_trim(skb, sizeof(*sre) + elen);
@@ -453,8 +450,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
event = sctp_skb2event(skb);
sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
- ssf = (struct sctp_send_failed *)
- skb_push(skb, sizeof(struct sctp_send_failed));
+ ssf = skb_push(skb, sizeof(struct sctp_send_failed));
/* Socket Extensions for SCTP
* 5.3.1.4 SCTP_SEND_FAILED
@@ -549,8 +545,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
goto fail;
skb = sctp_event2skb(event);
- sse = (struct sctp_shutdown_event *)
- skb_put(skb, sizeof(struct sctp_shutdown_event));
+ sse = skb_put(skb, sizeof(struct sctp_shutdown_event));
/* Socket Extensions for SCTP
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
@@ -612,8 +607,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_adaptation_indication(
goto fail;
skb = sctp_event2skb(event);
- sai = (struct sctp_adaptation_event *)
- skb_put(skb, sizeof(struct sctp_adaptation_event));
+ sai = skb_put(skb, sizeof(struct sctp_adaptation_event));
sai->sai_type = SCTP_ADAPTATION_INDICATION;
sai->sai_flags = 0;
@@ -751,8 +745,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
goto fail;
skb = sctp_event2skb(event);
- pd = (struct sctp_pdapi_event *)
- skb_put(skb, sizeof(struct sctp_pdapi_event));
+ pd = skb_put(skb, sizeof(struct sctp_pdapi_event));
/* pdapi_type
* It should be SCTP_PARTIAL_DELIVERY_EVENT
@@ -803,8 +796,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_authkey(
goto fail;
skb = sctp_event2skb(event);
- ak = (struct sctp_authkey_event *)
- skb_put(skb, sizeof(struct sctp_authkey_event));
+ ak = skb_put(skb, sizeof(struct sctp_authkey_event));
ak->auth_type = SCTP_AUTHENTICATION_EVENT;
ak->auth_flags = 0;
@@ -842,8 +834,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event(
return NULL;
skb = sctp_event2skb(event);
- sdry = (struct sctp_sender_dry_event *)
- skb_put(skb, sizeof(struct sctp_sender_dry_event));
+ sdry = skb_put(skb, sizeof(struct sctp_sender_dry_event));
sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT;
sdry->sender_dry_flags = 0;
@@ -869,7 +860,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event(
return NULL;
skb = sctp_event2skb(event);
- sreset = (struct sctp_stream_reset_event *)skb_put(skb, length);
+ sreset = skb_put(skb, length);
sreset->strreset_type = SCTP_STREAM_RESET_EVENT;
sreset->strreset_flags = flags;
@@ -897,8 +888,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event(
return NULL;
skb = sctp_event2skb(event);
- areset = (struct sctp_assoc_reset_event *)
- skb_put(skb, sizeof(struct sctp_assoc_reset_event));
+ areset = skb_put(skb, sizeof(struct sctp_assoc_reset_event));
areset->assocreset_type = SCTP_ASSOC_RESET_EVENT;
areset->assocreset_flags = flags;
@@ -925,8 +915,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_stream_change_event(
return NULL;
skb = sctp_event2skb(event);
- schange = (struct sctp_stream_change_event *)
- skb_put(skb, sizeof(struct sctp_stream_change_event));
+ schange = skb_put(skb, sizeof(struct sctp_stream_change_event));
schange->strchange_type = SCTP_STREAM_CHANGE_EVENT;
schange->strchange_flags = flags;
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index aa3624d50278..25f7e4140566 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -764,7 +764,7 @@ static void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
__u16 sid, csid, cssn;
sid = event->stream;
- stream = ulpq->asoc->stream;
+ stream = &ulpq->asoc->stream;
event_list = (struct sk_buff_head *) sctp_event2skb(event)->prev;
@@ -858,7 +858,7 @@ static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
/* Note: The stream ID must be verified before this routine. */
sid = event->stream;
ssn = event->ssn;
- stream = ulpq->asoc->stream;
+ stream = &ulpq->asoc->stream;
/* Is this the expected SSN for this stream ID? */
if (ssn != sctp_ssn_peek(stream, in, sid)) {
@@ -893,7 +893,7 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
struct sk_buff_head *lobby = &ulpq->lobby;
__u16 csid, cssn;
- stream = ulpq->asoc->stream;
+ stream = &ulpq->asoc->stream;
/* We are holding the chunks by stream, by SSN. */
skb_queue_head_init(&temp);
@@ -958,7 +958,7 @@ void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn)
struct sctp_stream *stream;
/* Note: The stream ID must be verified before this routine. */
- stream = ulpq->asoc->stream;
+ stream = &ulpq->asoc->stream;
/* Is this an old SSN? If so ignore. */
if (SSN_lt(ssn, sctp_ssn_peek(stream, in, sid)))