diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 12:31:59 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 12:31:59 -0700 |
commit | 5518b69b76680a4f2df96b1deca260059db0c2de (patch) | |
tree | f33cd1519c8efb4590500f2f9617400be233238c /net/sctp | |
parent | 8ad06e56dcbc1984ef0ff8f6e3c19982c5809f73 (diff) | |
parent | 0e72582270c07850b92cac351c8b97d4f9c123b9 (diff) | |
download | linux-5518b69b76680a4f2df96b1deca260059db0c2de.tar.gz linux-5518b69b76680a4f2df96b1deca260059db0c2de.tar.bz2 linux-5518b69b76680a4f2df96b1deca260059db0c2de.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
"Reasonably busy this cycle, but perhaps not as busy as in the 4.12
merge window:
1) Several optimizations for UDP processing under high load from
Paolo Abeni.
2) Support pacing internally in TCP when using the sch_fq packet
scheduler for this is not practical. From Eric Dumazet.
3) Support mutliple filter chains per qdisc, from Jiri Pirko.
4) Move to 1ms TCP timestamp clock, from Eric Dumazet.
5) Add batch dequeueing to vhost_net, from Jason Wang.
6) Flesh out more completely SCTP checksum offload support, from
Davide Caratti.
7) More plumbing of extended netlink ACKs, from David Ahern, Pablo
Neira Ayuso, and Matthias Schiffer.
8) Add devlink support to nfp driver, from Simon Horman.
9) Add RTM_F_FIB_MATCH flag to RTM_GETROUTE queries, from Roopa
Prabhu.
10) Add stack depth tracking to BPF verifier and use this information
in the various eBPF JITs. From Alexei Starovoitov.
11) Support XDP on qed device VFs, from Yuval Mintz.
12) Introduce BPF PROG ID for better introspection of installed BPF
programs. From Martin KaFai Lau.
13) Add bpf_set_hash helper for TC bpf programs, from Daniel Borkmann.
14) For loads, allow narrower accesses in bpf verifier checking, from
Yonghong Song.
15) Support MIPS in the BPF selftests and samples infrastructure, the
MIPS eBPF JIT will be merged in via the MIPS GIT tree. From David
Daney.
16) Support kernel based TLS, from Dave Watson and others.
17) Remove completely DST garbage collection, from Wei Wang.
18) Allow installing TCP MD5 rules using prefixes, from Ivan
Delalande.
19) Add XDP support to Intel i40e driver, from Björn Töpel
20) Add support for TC flower offload in nfp driver, from Simon
Horman, Pieter Jansen van Vuuren, Benjamin LaHaise, Jakub
Kicinski, and Bert van Leeuwen.
21) IPSEC offloading support in mlx5, from Ilan Tayari.
22) Add HW PTP support to macb driver, from Rafal Ozieblo.
23) Networking refcount_t conversions, From Elena Reshetova.
24) Add sock_ops support to BPF, from Lawrence Brako. This is useful
for tuning the TCP sockopt settings of a group of applications,
currently via CGROUPs"
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1899 commits)
net: phy: dp83867: add workaround for incorrect RX_CTRL pin strap
dt-bindings: phy: dp83867: provide a workaround for incorrect RX_CTRL pin strap
cxgb4: Support for get_ts_info ethtool method
cxgb4: Add PTP Hardware Clock (PHC) support
cxgb4: time stamping interface for PTP
nfp: default to chained metadata prepend format
nfp: remove legacy MAC address lookup
nfp: improve order of interfaces in breakout mode
net: macb: remove extraneous return when MACB_EXT_DESC is defined
bpf: add missing break in for the TCP_BPF_SNDCWND_CLAMP case
bpf: fix return in load_bpf_file
mpls: fix rtm policy in mpls_getroute
net, ax25: convert ax25_cb.refcount from atomic_t to refcount_t
net, ax25: convert ax25_route.refcount from atomic_t to refcount_t
net, ax25: convert ax25_uid_assoc.refcount from atomic_t to refcount_t
net, sctp: convert sctp_ep_common.refcnt from atomic_t to refcount_t
net, sctp: convert sctp_transport.refcnt from atomic_t to refcount_t
net, sctp: convert sctp_chunk.refcnt from atomic_t to refcount_t
net, sctp: convert sctp_datamsg.refcnt from atomic_t to refcount_t
net, sctp: convert sctp_auth_bytes.refcnt from atomic_t to refcount_t
...
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/associola.c | 59 | ||||
-rw-r--r-- | net/sctp/auth.c | 32 | ||||
-rw-r--r-- | net/sctp/chunk.c | 10 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 27 | ||||
-rw-r--r-- | net/sctp/input.c | 24 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 15 | ||||
-rw-r--r-- | net/sctp/offload.c | 7 | ||||
-rw-r--r-- | net/sctp/output.c | 14 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 12 | ||||
-rw-r--r-- | net/sctp/proc.c | 12 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 102 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 35 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 140 | ||||
-rw-r--r-- | net/sctp/sm_statetable.c | 4 | ||||
-rw-r--r-- | net/sctp/socket.c | 120 | ||||
-rw-r--r-- | net/sctp/stream.c | 97 | ||||
-rw-r--r-- | net/sctp/transport.c | 62 | ||||
-rw-r--r-- | net/sctp/ulpevent.c | 39 | ||||
-rw-r--r-- | net/sctp/ulpqueue.c | 10 |
19 files changed, 450 insertions, 371 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 95238284c422..40ec83679d6e 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -71,7 +71,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a { struct net *net = sock_net(sk); struct sctp_sock *sp; - sctp_paramhdr_t *p; + struct sctp_paramhdr *p; int i; /* Retrieve the SCTP per socket area. */ @@ -88,7 +88,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->base.type = SCTP_EP_TYPE_ASSOCIATION; /* Initialize the object handling fields. */ - atomic_set(&asoc->base.refcnt, 1); + refcount_set(&asoc->base.refcnt, 1); /* Initialize the bind addr area. */ sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); @@ -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 @@ -283,15 +284,15 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a ntohs(ep->auth_chunk_list->param_hdr.length)); /* Get the AUTH random number for this association */ - p = (sctp_paramhdr_t *)asoc->c.auth_random; + p = (struct sctp_paramhdr *)asoc->c.auth_random; p->type = SCTP_PARAM_RANDOM; - p->length = htons(sizeof(sctp_paramhdr_t) + SCTP_AUTH_RANDOM_LENGTH); + p->length = htons(sizeof(*p) + SCTP_AUTH_RANDOM_LENGTH); get_random_bytes(p+1, SCTP_AUTH_RANDOM_LENGTH); 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); @@ -872,7 +873,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, /* Hold a reference to an association. */ void sctp_association_hold(struct sctp_association *asoc) { - atomic_inc(&asoc->base.refcnt); + refcount_inc(&asoc->base.refcnt); } /* Release a reference to an association and cleanup @@ -880,7 +881,7 @@ void sctp_association_hold(struct sctp_association *asoc) */ void sctp_association_put(struct sctp_association *asoc) { - if (atomic_dec_and_test(&asoc->base.refcnt)) + if (refcount_dec_and_test(&asoc->base.refcnt)) sctp_association_destroy(asoc); } @@ -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/auth.c b/net/sctp/auth.c index f99d4855d3de..e001b01b0e68 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -63,7 +63,7 @@ void sctp_auth_key_put(struct sctp_auth_bytes *key) if (!key) return; - if (atomic_dec_and_test(&key->refcnt)) { + if (refcount_dec_and_test(&key->refcnt)) { kzfree(key); SCTP_DBG_OBJCNT_DEC(keys); } @@ -84,7 +84,7 @@ static struct sctp_auth_bytes *sctp_auth_create_key(__u32 key_len, gfp_t gfp) return NULL; key->len = key_len; - atomic_set(&key->refcnt, 1); + refcount_set(&key->refcnt, 1); SCTP_DBG_OBJCNT_INC(keys); return key; @@ -538,7 +538,8 @@ struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc) if (!hmacs) return NULL; - n_elt = (ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t)) >> 1; + n_elt = (ntohs(hmacs->param_hdr.length) - + sizeof(struct sctp_paramhdr)) >> 1; for (i = 0; i < n_elt; i++) { id = ntohs(hmacs->hmac_ids[i]); @@ -589,7 +590,8 @@ int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, return 0; hmacs = (struct sctp_hmac_algo_param *)asoc->c.auth_hmacs; - n_elt = (ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t)) >> 1; + n_elt = (ntohs(hmacs->param_hdr.length) - + sizeof(struct sctp_paramhdr)) >> 1; return __sctp_auth_find_hmacid(hmacs->hmac_ids, n_elt, hmac_id); } @@ -612,8 +614,8 @@ void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, if (asoc->default_hmac_id) return; - n_params = (ntohs(hmacs->param_hdr.length) - - sizeof(sctp_paramhdr_t)) >> 1; + n_params = (ntohs(hmacs->param_hdr.length) - + sizeof(struct sctp_paramhdr)) >> 1; ep = asoc->ep; for (i = 0; i < n_params; i++) { id = ntohs(hmacs->hmac_ids[i]); @@ -632,7 +634,7 @@ void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, /* Check to see if the given chunk is supposed to be authenticated */ -static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param) +static int __sctp_auth_cid(enum sctp_cid chunk, struct sctp_chunks_param *param) { unsigned short len; int found = 0; @@ -641,7 +643,7 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param) if (!param || param->param_hdr.length == 0) return 0; - len = ntohs(param->param_hdr.length) - sizeof(sctp_paramhdr_t); + len = ntohs(param->param_hdr.length) - sizeof(struct sctp_paramhdr); /* SCTP-AUTH, Section 3.2 * The chunk types for INIT, INIT-ACK, SHUTDOWN-COMPLETE and AUTH @@ -668,7 +670,7 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param) } /* Check if peer requested that this chunk is authenticated */ -int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc) +int sctp_auth_send_cid(enum sctp_cid chunk, const struct sctp_association *asoc) { if (!asoc) return 0; @@ -680,7 +682,7 @@ int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc) } /* Check if we requested that peer authenticate this chunk. */ -int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc) +int sctp_auth_recv_cid(enum sctp_cid chunk, const struct sctp_association *asoc) { if (!asoc) return 0; @@ -775,7 +777,7 @@ int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id) /* Check if we can add this chunk to the array */ param_len = ntohs(p->param_hdr.length); - nchunks = param_len - sizeof(sctp_paramhdr_t); + nchunks = param_len - sizeof(struct sctp_paramhdr); if (nchunks == SCTP_NUM_CHUNK_TYPES) return -EINVAL; @@ -812,9 +814,11 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, return -EINVAL; for (i = 0; i < hmacs->shmac_num_idents; i++) - ep->auth_hmacs_list->hmac_ids[i] = htons(hmacs->shmac_idents[i]); - ep->auth_hmacs_list->param_hdr.length = htons(sizeof(sctp_paramhdr_t) + - hmacs->shmac_num_idents * sizeof(__u16)); + ep->auth_hmacs_list->hmac_ids[i] = + htons(hmacs->shmac_idents[i]); + ep->auth_hmacs_list->param_hdr.length = + htons(sizeof(struct sctp_paramhdr) + + hmacs->shmac_num_idents * sizeof(__u16)); return 0; } diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 697721a7a3f1..1323d41e68b8 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -49,7 +49,7 @@ /* Initialize datamsg from memory. */ static void sctp_datamsg_init(struct sctp_datamsg *msg) { - atomic_set(&msg->refcnt, 1); + refcount_set(&msg->refcnt, 1); msg->send_failed = 0; msg->send_error = 0; msg->can_delay = 1; @@ -136,13 +136,13 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg) /* Hold a reference. */ static void sctp_datamsg_hold(struct sctp_datamsg *msg) { - atomic_inc(&msg->refcnt); + refcount_inc(&msg->refcnt); } /* Release a reference. */ void sctp_datamsg_put(struct sctp_datamsg *msg) { - if (atomic_dec_and_test(&msg->refcnt)) + if (refcount_dec_and_test(&msg->refcnt)) sctp_datamsg_destroy(msg); } @@ -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/endpointola.c b/net/sctp/endpointola.c index 3dcd0ecf3d99..0e86f988f836 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -90,12 +90,13 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, */ auth_hmacs->param_hdr.type = SCTP_PARAM_HMAC_ALGO; auth_hmacs->param_hdr.length = - htons(sizeof(sctp_paramhdr_t) + 2); + htons(sizeof(struct sctp_paramhdr) + 2); auth_hmacs->hmac_ids[0] = htons(SCTP_AUTH_HMAC_ID_SHA1); /* Initialize the CHUNKS parameter */ auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; - auth_chunks->param_hdr.length = htons(sizeof(sctp_paramhdr_t)); + auth_chunks->param_hdr.length = + htons(sizeof(struct sctp_paramhdr)); /* If the Add-IP functionality is enabled, we must * authenticate, ASCONF and ASCONF-ACK chunks @@ -104,7 +105,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, auth_chunks->chunks[0] = SCTP_CID_ASCONF; auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK; auth_chunks->param_hdr.length = - htons(sizeof(sctp_paramhdr_t) + 2); + htons(sizeof(struct sctp_paramhdr) + 2); } } @@ -113,7 +114,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ep->base.type = SCTP_EP_TYPE_SOCKET; /* Initialize the basic object fields. */ - atomic_set(&ep->base.refcnt, 1); + refcount_set(&ep->base.refcnt, 1); ep->base.dead = false; /* Create an input queue. */ @@ -268,16 +269,14 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) memset(ep->secret_key, 0, sizeof(ep->secret_key)); - /* Give up our hold on the sock. */ sk = ep->base.sk; - if (sk != NULL) { - /* Remove and free the port */ - if (sctp_sk(sk)->bind_hash) - sctp_put_port(sk); + /* Remove and free the port */ + if (sctp_sk(sk)->bind_hash) + sctp_put_port(sk); - sctp_sk(sk)->ep = NULL; - sock_put(sk); - } + sctp_sk(sk)->ep = NULL; + /* Give up our hold on the sock */ + sock_put(sk); kfree(ep); SCTP_DBG_OBJCNT_DEC(ep); @@ -286,7 +285,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) /* Hold a reference to an endpoint. */ void sctp_endpoint_hold(struct sctp_endpoint *ep) { - atomic_inc(&ep->base.refcnt); + refcount_inc(&ep->base.refcnt); } /* Release a reference to an endpoint and clean up if there are @@ -294,7 +293,7 @@ void sctp_endpoint_hold(struct sctp_endpoint *ep) */ void sctp_endpoint_put(struct sctp_endpoint *ep) { - if (atomic_dec_and_test(&ep->base.refcnt)) + if (refcount_dec_and_test(&ep->base.refcnt)) sctp_endpoint_destroy(ep); } diff --git a/net/sctp/input.c b/net/sctp/input.c index ba9ad32fc447..41eb2ec10460 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -663,19 +663,19 @@ out_unlock: */ static int sctp_rcv_ootb(struct sk_buff *skb) { - sctp_chunkhdr_t *ch, _ch; + struct sctp_chunkhdr *ch, _ch; int ch_end, offset = 0; /* Scan through all the chunks in the packet. */ do { /* Make sure we have at least the header there */ - if (offset + sizeof(sctp_chunkhdr_t) > skb->len) + if (offset + sizeof(_ch) > skb->len) break; ch = skb_header_pointer(skb, offset, sizeof(*ch), &_ch); /* Break out if chunk length is less then minimal. */ - if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) + if (ntohs(ch->length) < sizeof(_ch)) break; ch_end = offset + SCTP_PAD4(ntohs(ch->length)); @@ -1051,7 +1051,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net, union sctp_addr *paddr = &addr; struct sctphdr *sh = sctp_hdr(skb); union sctp_params params; - sctp_init_chunk_t *init; + struct sctp_init_chunk *init; struct sctp_af *af; /* @@ -1070,7 +1070,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net, /* Find the start of the TLVs and the end of the chunk. This is * the region we search for address parameters. */ - init = (sctp_init_chunk_t *)skb->data; + init = (struct sctp_init_chunk *)skb->data; /* Walk the parameters looking for embedded addresses. */ sctp_walk_params(params, init, init_hdr.params) { @@ -1106,7 +1106,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net, */ static struct sctp_association *__sctp_rcv_asconf_lookup( struct net *net, - sctp_chunkhdr_t *ch, + struct sctp_chunkhdr *ch, const union sctp_addr *laddr, __be16 peer_port, struct sctp_transport **transportp) @@ -1144,7 +1144,7 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net, struct sctp_transport **transportp) { struct sctp_association *asoc = NULL; - sctp_chunkhdr_t *ch; + struct sctp_chunkhdr *ch; int have_auth = 0; unsigned int chunk_num = 1; __u8 *ch_end; @@ -1152,10 +1152,10 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net, /* Walk through the chunks looking for AUTH or ASCONF chunks * to help us find the association. */ - ch = (sctp_chunkhdr_t *) skb->data; + ch = (struct sctp_chunkhdr *)skb->data; do { /* Break out if chunk length is less then minimal. */ - if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) + if (ntohs(ch->length) < sizeof(*ch)) break; ch_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length)); @@ -1192,7 +1192,7 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net, if (asoc) break; - ch = (sctp_chunkhdr_t *) ch_end; + ch = (struct sctp_chunkhdr *)ch_end; chunk_num++; } while (ch_end < skb_tail_pointer(skb)); @@ -1210,7 +1210,7 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net, const union sctp_addr *laddr, struct sctp_transport **transportp) { - sctp_chunkhdr_t *ch; + struct sctp_chunkhdr *ch; /* We do not allow GSO frames here as we need to linearize and * then cannot guarantee frame boundaries. This shouldn't be an @@ -1220,7 +1220,7 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net, if ((skb_shinfo(skb)->gso_type & SKB_GSO_SCTP) == SKB_GSO_SCTP) return NULL; - ch = (sctp_chunkhdr_t *) skb->data; + ch = (struct sctp_chunkhdr *)skb->data; /* The code below will attempt to walk the chunk and extract * parameter information. Before we do that, we need to verify diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index f731de3e8428..48392552ee7c 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -99,7 +99,7 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue) { struct sctp_chunk *chunk; - sctp_chunkhdr_t *ch = NULL; + struct sctp_chunkhdr *ch = NULL; chunk = queue->in_progress; /* If there is no more chunks in this packet, say so */ @@ -108,7 +108,7 @@ struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue) chunk->pdiscard) return NULL; - ch = (sctp_chunkhdr_t *)chunk->chunk_end; + ch = (struct sctp_chunkhdr *)chunk->chunk_end; return ch; } @@ -122,7 +122,7 @@ struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue) struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) { struct sctp_chunk *chunk; - sctp_chunkhdr_t *ch = NULL; + struct sctp_chunkhdr *ch = NULL; /* The assumption is that we are safe to process the chunks * at this time. @@ -151,7 +151,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) chunk = queue->in_progress = NULL; } else { /* Nothing to do. Next chunk in the packet, please. */ - ch = (sctp_chunkhdr_t *) chunk->chunk_end; + ch = (struct sctp_chunkhdr *)chunk->chunk_end; /* Force chunk->skb->data to chunk->chunk_end. */ skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data); /* We are guaranteed to pull a SCTP header. */ @@ -195,7 +195,7 @@ next_chunk: new_skb: /* This is the first chunk in the packet. */ - ch = (sctp_chunkhdr_t *) chunk->skb->data; + ch = (struct sctp_chunkhdr *)chunk->skb->data; chunk->singleton = 1; chunk->data_accepted = 0; chunk->pdiscard = 0; @@ -214,11 +214,10 @@ new_skb: chunk->chunk_hdr = ch; chunk->chunk_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length)); - skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); + skb_pull(chunk->skb, sizeof(*ch)); chunk->subh.v = NULL; /* Subheader is no longer valid. */ - if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) < - skb_tail_pointer(chunk->skb)) { + if (chunk->chunk_end + sizeof(*ch) < skb_tail_pointer(chunk->skb)) { /* This is not a singleton */ chunk->singleton = 0; } else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) { 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..9d8504985744 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -402,7 +402,7 @@ static void sctp_packet_set_owner_w(struct sk_buff *skb, struct sock *sk) * therefore only reserve a single byte to keep socket around until * the packet has been transmitted. */ - atomic_inc(&sk->sk_wmem_alloc); + refcount_inc(&sk->sk_wmem_alloc); } static int sctp_packet_pack(struct sctp_packet *packet, @@ -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); @@ -723,8 +723,8 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, /* Check whether this chunk and all the rest of pending data will fit * or delay in hopes of bundling a full sized packet. */ - if (chunk->skb->len + q->out_qlen > - transport->pathmtu - packet->overhead - sizeof(sctp_data_chunk_t) - 4) + if (chunk->skb->len + q->out_qlen > transport->pathmtu - + packet->overhead - sizeof(struct sctp_data_chunk) - 4) /* Enough data queued to fill a packet */ return SCTP_XMIT_OK; diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index fe4c3d462f6e..e8762702a313 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; } @@ -1102,7 +1102,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) : "illegal chunk", ntohl(chunk->subh.data_hdr->tsn), chunk->skb ? chunk->skb->head : NULL, chunk->skb ? - atomic_read(&chunk->skb->users) : -1); + refcount_read(&chunk->skb->users) : -1); /* Add the chunk to the packet. */ status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp); diff --git a/net/sctp/proc.c b/net/sctp/proc.c index a0b29d43627f..26b4be6b4172 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,11 +359,11 @@ 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), + refcount_read(&sk->sk_wmem_alloc), sk->sk_wmem_queued, sk->sk_sndbuf, sk->sk_rcvbuf); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 92e332e17391..4e16b02ed832 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -217,7 +217,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, { struct net *net = sock_net(asoc->base.sk); struct sctp_endpoint *ep = asoc->ep; - sctp_inithdr_t init; + struct sctp_inithdr init; union sctp_params addrs; size_t chunksize; struct sctp_chunk *retval = NULL; @@ -229,7 +229,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, sctp_supported_ext_param_t ext_param; int num_ext = 0; __u8 extensions[3]; - sctp_paramhdr_t *auth_chunks = NULL, + struct sctp_paramhdr *auth_chunks = NULL, *auth_hmacs = NULL; /* RFC 2960 3.3.2 Initiation (INIT) (1) @@ -286,14 +286,14 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, chunksize += sizeof(asoc->c.auth_random); /* Add HMACS parameter length if any were defined */ - auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; + auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs; if (auth_hmacs->length) chunksize += SCTP_PAD4(ntohs(auth_hmacs->length)); else auth_hmacs = NULL; /* Add CHUNKS parameter length */ - auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; + auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks; if (auth_chunks->length) chunksize += SCTP_PAD4(ntohs(auth_chunks->length)); else @@ -385,7 +385,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, const struct sctp_chunk *chunk, gfp_t gfp, int unkparam_len) { - sctp_inithdr_t initack; + struct sctp_inithdr initack; struct sctp_chunk *retval; union sctp_params addrs; struct sctp_sock *sp; @@ -397,7 +397,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, sctp_supported_ext_param_t ext_param; int num_ext = 0; __u8 extensions[3]; - sctp_paramhdr_t *auth_chunks = NULL, + struct sctp_paramhdr *auth_chunks = NULL, *auth_hmacs = NULL, *auth_random = NULL; @@ -448,16 +448,16 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, chunksize += sizeof(aiparam); if (asoc->peer.auth_capable) { - auth_random = (sctp_paramhdr_t *)asoc->c.auth_random; + auth_random = (struct sctp_paramhdr *)asoc->c.auth_random; chunksize += ntohs(auth_random->length); - auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; + auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs; if (auth_hmacs->length) chunksize += SCTP_PAD4(ntohs(auth_hmacs->length)); else auth_hmacs = NULL; - auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; + auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks; if (auth_chunks->length) chunksize += SCTP_PAD4(ntohs(auth_chunks->length)); else @@ -1085,18 +1085,18 @@ struct sctp_chunk *sctp_make_abort_violation( struct sctp_chunk *retval; struct sctp_paramhdr phdr; - retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen - + sizeof(sctp_paramhdr_t)); + retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen + + sizeof(phdr)); if (!retval) goto end; - sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen - + sizeof(sctp_paramhdr_t)); + sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen + + sizeof(phdr)); phdr.type = htons(chunk->chunk_hdr->type); phdr.length = chunk->chunk_hdr->length; sctp_addto_chunk(retval, paylen, payload); - sctp_addto_param(retval, sizeof(sctp_paramhdr_t), &phdr); + sctp_addto_param(retval, sizeof(phdr), &phdr); end: return retval; @@ -1110,16 +1110,16 @@ struct sctp_chunk *sctp_make_violation_paramlen( struct sctp_chunk *retval; static const char error[] = "The following parameter had invalid length:"; size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t) + - sizeof(sctp_paramhdr_t); + sizeof(*param); retval = sctp_make_abort(asoc, chunk, payload_len); if (!retval) goto nodata; sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, - sizeof(error) + sizeof(sctp_paramhdr_t)); + sizeof(error) + sizeof(*param)); sctp_addto_chunk(retval, sizeof(error), error); - sctp_addto_param(retval, sizeof(sctp_paramhdr_t), param); + sctp_addto_param(retval, sizeof(*param), param); nodata: return retval; @@ -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 = @@ -1346,7 +1345,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, INIT_LIST_HEAD(&retval->transmitted_list); INIT_LIST_HEAD(&retval->frag_list); SCTP_DBG_OBJCNT_INC(chunk); - atomic_set(&retval->refcnt, 1); + refcount_set(&retval->refcnt, 1); nodata: return retval; @@ -1380,20 +1379,20 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, gfp_t gfp) { struct sctp_chunk *retval; - sctp_chunkhdr_t *chunk_hdr; + struct sctp_chunkhdr *chunk_hdr; struct sk_buff *skb; struct sock *sk; /* No need to allocate LL here, as this is only a chunk. */ - skb = alloc_skb(SCTP_PAD4(sizeof(sctp_chunkhdr_t) + paylen), gfp); + skb = alloc_skb(SCTP_PAD4(sizeof(*chunk_hdr) + paylen), gfp); if (!skb) goto nodata; /* Make room for the chunk header. */ - chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t)); + chunk_hdr = (struct sctp_chunkhdr *)skb_put(skb, sizeof(*chunk_hdr)); chunk_hdr->type = type; chunk_hdr->flags = flags; - chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t)); + chunk_hdr->length = htons(sizeof(*chunk_hdr)); sk = asoc ? asoc->base.sk : NULL; retval = sctp_chunkify(skb, asoc, sk, gfp); @@ -1403,7 +1402,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, } retval->chunk_hdr = chunk_hdr; - retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(struct sctp_chunkhdr); + retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(*chunk_hdr); /* Determine if the chunk needs to be authenticated */ if (sctp_auth_send_cid(type, asoc)) @@ -1459,13 +1458,13 @@ void sctp_chunk_free(struct sctp_chunk *chunk) /* Grab a reference to the chunk. */ void sctp_chunk_hold(struct sctp_chunk *ch) { - atomic_inc(&ch->refcnt); + refcount_inc(&ch->refcnt); } /* Release a reference to the chunk. */ void sctp_chunk_put(struct sctp_chunk *ch) { - if (atomic_dec_and_test(&ch->refcnt)) + if (refcount_dec_and_test(&ch->refcnt)) sctp_chunk_destroy(ch); } @@ -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. @@ -1619,7 +1614,7 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, /* Header size is static data prior to the actual cookie, including * any padding. */ - headersize = sizeof(sctp_paramhdr_t) + + headersize = sizeof(struct sctp_paramhdr) + (sizeof(struct sctp_signed_cookie) - sizeof(struct sctp_cookie)); bodysize = sizeof(struct sctp_cookie) @@ -1715,7 +1710,7 @@ struct sctp_association *sctp_unpack_cookie( /* Header size is static data prior to the actual cookie, including * any padding. */ - headersize = sizeof(sctp_chunkhdr_t) + + headersize = sizeof(struct sctp_chunkhdr) + (sizeof(struct sctp_signed_cookie) - sizeof(struct sctp_cookie)); bodysize = ntohs(chunk->chunk_hdr->length) - headersize; @@ -1887,7 +1882,7 @@ struct __sctp_missing { * Report a missing mandatory parameter. */ static int sctp_process_missing_param(const struct sctp_association *asoc, - sctp_param_t paramtype, + enum sctp_param paramtype, struct sctp_chunk *chunk, struct sctp_chunk **errp) { @@ -1980,7 +1975,7 @@ static int sctp_process_hn_param(const struct sctp_association *asoc, static int sctp_verify_ext_param(struct net *net, union sctp_params param) { - __u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t); + __u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); int have_auth = 0; int have_asconf = 0; int i; @@ -2015,7 +2010,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc, union sctp_params param) { struct net *net = sock_net(asoc->base.sk); - __u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t); + __u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); int i; for (i = 0; i < num_ext; i++) { @@ -2128,7 +2123,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net, const struct sctp_endpoint *ep, const struct sctp_association *asoc, union sctp_params param, - sctp_cid_t cid, + enum sctp_cid cid, struct sctp_chunk *chunk, struct sctp_chunk **err_chunk) { @@ -2185,7 +2180,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net, * cause 'Protocol Violation'. */ if (SCTP_AUTH_RANDOM_LENGTH != - ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) { + ntohs(param.p->length) - sizeof(struct sctp_paramhdr)) { sctp_process_inv_paramlength(asoc, param.p, chunk, err_chunk); retval = SCTP_IERROR_ABORT; @@ -2213,7 +2208,8 @@ static sctp_ierror_t sctp_verify_param(struct net *net, goto fallthrough; hmacs = (struct sctp_hmac_algo_param *)param.p; - n_elt = (ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) >> 1; + n_elt = (ntohs(param.p->length) - + sizeof(struct sctp_paramhdr)) >> 1; /* SCTP-AUTH: Section 6.1 * The HMAC algorithm based on SHA-1 MUST be supported and @@ -2245,9 +2241,9 @@ fallthrough: /* Verify the INIT packet before we process it. */ int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep, - const struct sctp_association *asoc, sctp_cid_t cid, - sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk, - struct sctp_chunk **errp) + const struct sctp_association *asoc, enum sctp_cid cid, + struct sctp_init_chunk *peer_init, + struct sctp_chunk *chunk, struct sctp_chunk **errp) { union sctp_params param; bool has_cookie = false; @@ -2311,7 +2307,7 @@ int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep, */ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, const union sctp_addr *peer_addr, - sctp_init_chunk_t *peer_init, gfp_t gfp) + struct sctp_init_chunk *peer_init, gfp_t gfp) { struct net *net = sock_net(asoc->base.sk); union sctp_params param; @@ -2454,7 +2450,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)) @@ -2569,7 +2566,7 @@ do_addr_param: asoc->peer.ipv4_address = 1; /* Cycle through address types; avoid divide by 0. */ - sat = ntohs(param.p->length) - sizeof(sctp_paramhdr_t); + sat = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); if (sat) sat /= sizeof(__u16); @@ -2596,7 +2593,7 @@ do_addr_param: case SCTP_PARAM_STATE_COOKIE: asoc->peer.cookie_len = - ntohs(param.p->length) - sizeof(sctp_paramhdr_t); + ntohs(param.p->length) - sizeof(struct sctp_paramhdr); asoc->peer.cookie = param.cookie->body; break; @@ -3180,7 +3177,7 @@ bool sctp_verify_asconf(const struct sctp_association *asoc, return false; length = ntohs(param.addip->param_hdr.length); if (length < sizeof(sctp_addip_param_t) + - sizeof(sctp_paramhdr_t)) + sizeof(**errp)) return false; break; case SCTP_PARAM_SUCCESS_REPORT: @@ -3222,7 +3219,8 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, int chunk_len; __u32 serial; - chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); + chunk_len = ntohs(asconf->chunk_hdr->length) - + sizeof(struct sctp_chunkhdr); hdr = (sctp_addiphdr_t *)asconf->skb->data; serial = ntohl(hdr->serial); @@ -3368,7 +3366,7 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack, err_code = SCTP_ERROR_REQ_REFUSED; asconf_ack_len = ntohs(asconf_ack->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t); + sizeof(struct sctp_chunkhdr); /* Skip the addiphdr from the asconf_ack chunk and store a pointer to * the first asconf_ack parameter. diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 25384fa82ba9..d6e5e9e0fd6d 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -647,7 +647,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, static int sctp_cmd_process_init(sctp_cmd_seq_t *commands, struct sctp_association *asoc, struct sctp_chunk *chunk, - sctp_init_chunk_t *peer_init, + struct sctp_init_chunk *peer_init, gfp_t gfp) { int error; @@ -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, @@ -933,9 +955,10 @@ static void sctp_cmd_process_operr(sctp_cmd_seq_t *cmds, switch (err_hdr->cause) { case SCTP_ERROR_UNKNOWN_CHUNK: { - sctp_chunkhdr_t *unk_chunk_hdr; + struct sctp_chunkhdr *unk_chunk_hdr; - unk_chunk_hdr = (sctp_chunkhdr_t *)err_hdr->variable; + unk_chunk_hdr = (struct sctp_chunkhdr *) + err_hdr->variable; switch (unk_chunk_hdr->type) { /* ADDIP 4.1 A9) If the peer responds to an ASCONF with * an ERROR chunk reporting that it did not recognized @@ -1294,7 +1317,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 +1771,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..b2a74c3823ee 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -235,7 +235,7 @@ sctp_disposition_t sctp_sf_do_4_C(struct net *net, return sctp_sf_violation_chunk(net, ep, asoc, type, arg, commands); /* Make sure that the SHUTDOWN_COMPLETE chunk has a valid length. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -345,7 +345,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net, * error, but since we don't have an association, we'll * just discard the packet. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk))) return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); /* If the INIT is coming toward a closing socket, we'll send back @@ -360,7 +360,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net, /* Verify the INIT chunk before processing it. */ err_chunk = NULL; if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, - (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, + (struct sctp_init_chunk *)chunk->chunk_hdr, chunk, &err_chunk)) { /* This chunk contains fatal error. It is to be discarded. * Send an ABORT, with causes if there is any. @@ -368,9 +368,9 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net, if (err_chunk) { packet = sctp_abort_pkt_new(net, ep, asoc, arg, (__u8 *)(err_chunk->chunk_hdr) + - sizeof(sctp_chunkhdr_t), + sizeof(struct sctp_chunkhdr), ntohs(err_chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t)); + sizeof(struct sctp_chunkhdr)); sctp_chunk_free(err_chunk); @@ -389,10 +389,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net, } /* Grab the INIT header. */ - chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; + chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data; /* Tag the variable length parameters. */ - chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); if (!new_asoc) @@ -405,7 +405,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net, /* The call, sctp_process_init(), can fail on memory allocation. */ if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), - (sctp_init_chunk_t *)chunk->chunk_hdr, + (struct sctp_init_chunk *)chunk->chunk_hdr, GFP_ATOMIC)) goto nomem_init; @@ -417,7 +417,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net, len = 0; if (err_chunk) len = ntohs(err_chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t); + sizeof(struct sctp_chunkhdr); repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); if (!repl) @@ -437,7 +437,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net, */ unk_param = (sctp_unrecognized_param_t *) ((__u8 *)(err_chunk->chunk_hdr) + - sizeof(sctp_chunkhdr_t)); + sizeof(struct sctp_chunkhdr)); /* Replace the cause code with the "Unrecognized parameter" * parameter type. */ @@ -503,7 +503,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net, sctp_cmd_seq_t *commands) { struct sctp_chunk *chunk = arg; - sctp_init_chunk_t *initchunk; + struct sctp_init_chunk *initchunk; struct sctp_chunk *err_chunk; struct sctp_packet *packet; @@ -522,12 +522,12 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net, return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); /* Grab the INIT header. */ - chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; + chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data; /* Verify the INIT chunk before processing it. */ err_chunk = NULL; if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, - (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, + (struct sctp_init_chunk *)chunk->chunk_hdr, chunk, &err_chunk)) { sctp_error_t error = SCTP_ERROR_NO_RESOURCE; @@ -540,9 +540,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net, if (err_chunk) { packet = sctp_abort_pkt_new(net, ep, asoc, arg, (__u8 *)(err_chunk->chunk_hdr) + - sizeof(sctp_chunkhdr_t), + sizeof(struct sctp_chunkhdr), ntohs(err_chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t)); + sizeof(struct sctp_chunkhdr)); sctp_chunk_free(err_chunk); @@ -576,9 +576,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net, /* Tag the variable length parameters. Note that we never * convert the parameters in an INIT chunk. */ - chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); - initchunk = (sctp_init_chunk_t *) chunk->chunk_hdr; + initchunk = (struct sctp_init_chunk *)chunk->chunk_hdr; sctp_add_cmd_sf(commands, SCTP_CMD_PEER_INIT, SCTP_PEER_INIT(initchunk)); @@ -653,7 +653,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net, { struct sctp_chunk *chunk = arg; struct sctp_association *new_asoc; - sctp_init_chunk_t *peer_init; + struct sctp_init_chunk *peer_init; struct sctp_chunk *repl; struct sctp_ulpevent *ev, *ai_ev = NULL; int error = 0; @@ -673,7 +673,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net, * chunk header. More detailed verification is done * in sctp_unpack_cookie(). */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); /* If the endpoint is not listening or if the number of associations @@ -691,7 +691,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net, chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t))) + sizeof(struct sctp_chunkhdr))) goto nomem; /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint @@ -770,9 +770,10 @@ 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)); - skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t)); + auth.chunk_hdr = (struct sctp_chunkhdr *) + skb_push(chunk->auth_chunk, + sizeof(struct sctp_chunkhdr)); + skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr)); auth.transport = chunk->transport; ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth); @@ -886,7 +887,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(struct net *net, /* Verify that the chunk length for the COOKIE-ACK is OK. * If we don't do this, any bundled chunks may be junked. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -1080,7 +1081,7 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net, void *arg, sctp_cmd_seq_t *commands) { - sctp_paramhdr_t *param_hdr; + struct sctp_paramhdr *param_hdr; struct sctp_chunk *chunk = arg; struct sctp_chunk *reply; size_t paylen = 0; @@ -1097,9 +1098,9 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net, * respond with a HEARTBEAT ACK that contains the Heartbeat * Information field copied from the received HEARTBEAT chunk. */ - chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; - param_hdr = (sctp_paramhdr_t *) chunk->subh.hb_hdr; - paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); + chunk->subh.hb_hdr = (sctp_heartbeathdr_t *)chunk->skb->data; + param_hdr = (struct sctp_paramhdr *)chunk->subh.hb_hdr; + paylen = ntohs(chunk->chunk_hdr->length) - sizeof(struct sctp_chunkhdr); if (ntohs(param_hdr->length) > paylen) return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, @@ -1164,7 +1165,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(struct net *net, return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); /* Make sure that the HEARTBEAT-ACK chunk has a valid length. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t) + + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr) + sizeof(sctp_sender_hb_info_t))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -1449,19 +1450,19 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( * In this case, we generate a protocol violation since we have * an association established. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); /* Grab the INIT header. */ - chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; + chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data; /* Tag the variable length parameters. */ - chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); /* Verify the INIT chunk before processing it. */ err_chunk = NULL; if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, - (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, + (struct sctp_init_chunk *)chunk->chunk_hdr, chunk, &err_chunk)) { /* This chunk contains fatal error. It is to be discarded. * Send an ABORT, with causes if there is any. @@ -1469,9 +1470,9 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( if (err_chunk) { packet = sctp_abort_pkt_new(net, ep, asoc, arg, (__u8 *)(err_chunk->chunk_hdr) + - sizeof(sctp_chunkhdr_t), + sizeof(struct sctp_chunkhdr), ntohs(err_chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t)); + sizeof(struct sctp_chunkhdr)); if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, @@ -1508,7 +1509,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( * place (local tie-tag and per tie-tag) within the state cookie. */ if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), - (sctp_init_chunk_t *)chunk->chunk_hdr, + (struct sctp_init_chunk *)chunk->chunk_hdr, GFP_ATOMIC)) goto nomem; @@ -1535,7 +1536,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( len = 0; if (err_chunk) { len = ntohs(err_chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t); + sizeof(struct sctp_chunkhdr); } repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); @@ -1556,7 +1557,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( */ unk_param = (sctp_unrecognized_param_t *) ((__u8 *)(err_chunk->chunk_hdr) + - sizeof(sctp_chunkhdr_t)); + sizeof(struct sctp_chunkhdr)); /* Replace the cause code with the "Unrecognized parameter" * parameter type. */ @@ -1729,7 +1730,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net, sctp_cmd_seq_t *commands, struct sctp_association *new_asoc) { - sctp_init_chunk_t *peer_init; + struct sctp_init_chunk *peer_init; struct sctp_ulpevent *ev; struct sctp_chunk *repl; struct sctp_chunk *err; @@ -1844,7 +1845,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(struct net *net, sctp_cmd_seq_t *commands, struct sctp_association *new_asoc) { - sctp_init_chunk_t *peer_init; + struct sctp_init_chunk *peer_init; struct sctp_chunk *repl; /* new_asoc is a brand-new association, so these are not yet @@ -2044,7 +2045,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(struct net *net, * enough for the chunk header. Cookie length verification is * done later. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -2053,7 +2054,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(struct net *net, */ chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t))) + sizeof(struct sctp_chunkhdr))) goto nomem; /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie @@ -2806,7 +2807,7 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(struct net *net, struct sctp_chunk *reply; /* Make sure that the chunk has a valid length */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -2989,7 +2990,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(struct net *net, return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); } - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_data_chunk))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -3009,7 +3010,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(struct net *net, return SCTP_DISPOSITION_ABORT; case SCTP_IERROR_PROTO_VIOLATION: return sctp_sf_abort_violation(net, ep, asoc, chunk, commands, - (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t)); + (u8 *)chunk->subh.data_hdr, + sizeof(struct sctp_datahdr)); default: BUG(); } @@ -3107,7 +3109,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(struct net *net, return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); } - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_data_chunk))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -3123,7 +3125,8 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(struct net *net, return SCTP_DISPOSITION_ABORT; case SCTP_IERROR_PROTO_VIOLATION: return sctp_sf_abort_violation(net, ep, asoc, chunk, commands, - (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t)); + (u8 *)chunk->subh.data_hdr, + sizeof(struct sctp_datahdr)); default: BUG(); } @@ -3358,7 +3361,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(struct net *net, return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); /* Make sure that the SHUTDOWN_ACK chunk has a valid length. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); /* 10.2 H) SHUTDOWN COMPLETE notification @@ -3435,7 +3438,7 @@ sctp_disposition_t sctp_sf_ootb(struct net *net, { struct sctp_chunk *chunk = arg; struct sk_buff *skb = chunk->skb; - sctp_chunkhdr_t *ch; + struct sctp_chunkhdr *ch; sctp_errhdr_t *err; __u8 *ch_end; int ootb_shut_ack = 0; @@ -3443,10 +3446,10 @@ sctp_disposition_t sctp_sf_ootb(struct net *net, SCTP_INC_STATS(net, SCTP_MIB_OUTOFBLUES); - ch = (sctp_chunkhdr_t *) chunk->chunk_hdr; + ch = (struct sctp_chunkhdr *)chunk->chunk_hdr; do { /* Report violation if the chunk is less then minimal */ - if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) + if (ntohs(ch->length) < sizeof(*ch)) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -3487,7 +3490,7 @@ sctp_disposition_t sctp_sf_ootb(struct net *net, } } - ch = (sctp_chunkhdr_t *) ch_end; + ch = (struct sctp_chunkhdr *)ch_end; } while (ch_end < skb_tail_pointer(skb)); if (ootb_shut_ack) @@ -3560,7 +3563,7 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(struct net *net, /* If the chunk length is invalid, we don't want to process * the reset of the packet. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); /* We need to discard the rest of the packet to prevent @@ -3591,7 +3594,7 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(struct net *net, struct sctp_chunk *chunk = arg; /* Make sure that the SHUTDOWN_ACK chunk has a valid length. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -3958,7 +3961,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 +4032,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; } @@ -4256,7 +4259,7 @@ sctp_disposition_t sctp_sf_unk_chunk(struct net *net, { struct sctp_chunk *unk_chunk = arg; struct sctp_chunk *err_chunk; - sctp_chunkhdr_t *hdr; + struct sctp_chunkhdr *hdr; pr_debug("%s: processing unknown chunk id:%d\n", __func__, type.chunk); @@ -4267,7 +4270,7 @@ sctp_disposition_t sctp_sf_unk_chunk(struct net *net, * Since we don't know the chunk type, we use a general * chunkhdr structure to make a comparison. */ - if (!sctp_chunk_length_valid(unk_chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(unk_chunk, sizeof(*hdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -4340,7 +4343,7 @@ sctp_disposition_t sctp_sf_discard_chunk(struct net *net, * Since we don't know the chunk type, we use a general * chunkhdr structure to make a comparison. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -4405,7 +4408,7 @@ sctp_disposition_t sctp_sf_violation(struct net *net, struct sctp_chunk *chunk = arg; /* Make sure that the chunk has a valid length. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); @@ -6121,9 +6124,9 @@ static struct sctp_packet *sctp_ootb_pkt_new(struct net *net, switch (chunk->chunk_hdr->type) { case SCTP_CID_INIT: { - sctp_init_chunk_t *init; + struct sctp_init_chunk *init; - init = (sctp_init_chunk_t *)chunk->chunk_hdr; + init = (struct sctp_init_chunk *)chunk->chunk_hdr; vtag = ntohl(init->init_hdr.init_tag); break; } @@ -6196,7 +6199,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, struct sctp_chunk *chunk, sctp_cmd_seq_t *commands) { - sctp_datahdr_t *data_hdr; + struct sctp_datahdr *data_hdr; struct sctp_chunk *err; size_t datalen; sctp_verb_t deliver; @@ -6209,8 +6212,9 @@ static int sctp_eat_data(const struct sctp_association *asoc, u16 sid; u8 ordered = 0; - data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); + data_hdr = (struct sctp_datahdr *)chunk->skb->data; + chunk->subh.data_hdr = data_hdr; + skb_pull(chunk->skb, sizeof(*data_hdr)); tsn = ntohl(data_hdr->tsn); pr_debug("%s: TSN 0x%x\n", __func__, tsn); @@ -6258,7 +6262,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, * Actually, allow a little bit of overflow (up to a MTU). */ datalen = ntohs(chunk->chunk_hdr->length); - datalen -= sizeof(sctp_data_chunk_t); + datalen -= sizeof(struct sctp_data_chunk); deliver = SCTP_CMD_CHUNK_ULP; @@ -6365,7 +6369,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 +6391,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/sm_statetable.c b/net/sctp/sm_statetable.c index 419b18ebb056..3e958c1c4b95 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -53,7 +53,7 @@ static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES]; static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(struct net *net, - sctp_cid_t cid, + enum sctp_cid cid, sctp_state_t state); @@ -968,7 +968,7 @@ static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][S }; static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(struct net *net, - sctp_cid_t cid, + enum sctp_cid cid, sctp_state_t state) { if (state > SCTP_STATE_MAX) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3a8318e518f1..1db478e34520 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; @@ -164,7 +164,7 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) sizeof(struct sk_buff) + sizeof(struct sctp_chunk); - atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); + refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); sk->sk_wmem_queued += chunk->skb->truesize; sk_mem_charge(sk, chunk->skb->truesize); } @@ -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, @@ -4933,11 +4933,47 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) } EXPORT_SYMBOL(sctp_do_peeloff); +static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *peeloff, + struct file **newfile, unsigned flags) +{ + struct socket *newsock; + int retval; + + retval = sctp_do_peeloff(sk, peeloff->associd, &newsock); + if (retval < 0) + goto out; + + /* Map the socket to an unused fd that can be returned to the user. */ + retval = get_unused_fd_flags(flags & SOCK_CLOEXEC); + if (retval < 0) { + sock_release(newsock); + goto out; + } + + *newfile = sock_alloc_file(newsock, 0, NULL); + if (IS_ERR(*newfile)) { + put_unused_fd(retval); + sock_release(newsock); + retval = PTR_ERR(*newfile); + *newfile = NULL; + return retval; + } + + pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, + retval); + + peeloff->sd = retval; + + if (flags & SOCK_NONBLOCK) + (*newfile)->f_flags |= O_NONBLOCK; +out: + return retval; +} + static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) { sctp_peeloff_arg_t peeloff; - struct socket *newsock; - struct file *newfile; + struct file *newfile = NULL; int retval = 0; if (len < sizeof(sctp_peeloff_arg_t)) @@ -4946,26 +4982,44 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval if (copy_from_user(&peeloff, optval, len)) return -EFAULT; - retval = sctp_do_peeloff(sk, peeloff.associd, &newsock); + retval = sctp_getsockopt_peeloff_common(sk, &peeloff, &newfile, 0); if (retval < 0) goto out; - /* Map the socket to an unused fd that can be returned to the user. */ - retval = get_unused_fd_flags(0); - if (retval < 0) { - sock_release(newsock); - goto out; + /* Return the fd mapped to the new socket. */ + if (put_user(len, optlen)) { + fput(newfile); + put_unused_fd(retval); + return -EFAULT; } - newfile = sock_alloc_file(newsock, 0, NULL); - if (IS_ERR(newfile)) { + if (copy_to_user(optval, &peeloff, len)) { + fput(newfile); put_unused_fd(retval); - sock_release(newsock); - return PTR_ERR(newfile); + return -EFAULT; } + fd_install(retval, newfile); +out: + return retval; +} - pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, - retval); +static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + sctp_peeloff_flags_arg_t peeloff; + struct file *newfile = NULL; + int retval = 0; + + if (len < sizeof(sctp_peeloff_flags_arg_t)) + return -EINVAL; + len = sizeof(sctp_peeloff_flags_arg_t); + if (copy_from_user(&peeloff, optval, len)) + return -EFAULT; + + retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg, + &newfile, peeloff.flags); + if (retval < 0) + goto out; /* Return the fd mapped to the new socket. */ if (put_user(len, optlen)) { @@ -4973,7 +5027,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval put_unused_fd(retval); return -EFAULT; } - peeloff.sd = retval; + if (copy_to_user(optval, &peeloff, len)) { fput(newfile); put_unused_fd(retval); @@ -6033,7 +6087,8 @@ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, return -EACCES; hmacs = ep->auth_hmacs_list; - data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t); + data_len = ntohs(hmacs->param_hdr.length) - + sizeof(struct sctp_paramhdr); if (len < sizeof(struct sctp_hmacalgo) + data_len) return -EINVAL; @@ -6117,7 +6172,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, goto num; /* See if the user provided enough room for all the data */ - num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); if (len < num_chunks) return -EINVAL; @@ -6165,7 +6220,7 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, if (!ch) goto num; - num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); if (len < sizeof(struct sctp_authchunks) + num_chunks) return -EINVAL; @@ -6599,10 +6654,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; @@ -6758,6 +6813,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_SOCKOPT_PEELOFF: retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); break; + case SCTP_SOCKOPT_PEELOFF_FLAGS: + retval = sctp_getsockopt_peeloff_flags(sk, len, optval, optlen); + break; case SCTP_PEER_ADDR_PARAMS: retval = sctp_getsockopt_peer_addr_params(sk, len, optval, optlen); @@ -7563,7 +7621,7 @@ struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, if (flags & MSG_PEEK) { skb = skb_peek(&sk->sk_receive_queue); if (skb) - atomic_inc(&skb->users); + refcount_inc(&skb->users); } else { skb = __skb_dequeue(&sk->sk_receive_queue); } @@ -7684,7 +7742,7 @@ static void sctp_wfree(struct sk_buff *skb) sizeof(struct sk_buff) + sizeof(struct sctp_chunk); - atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); + WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc)); /* * This undoes what is done via sctp_set_owner_w and sk_mem_charge diff --git a/net/sctp/stream.c b/net/sctp/stream.c index dda53a293986..63ea15503714 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; @@ -317,7 +304,7 @@ out: return retval; } -static sctp_paramhdr_t *sctp_chunk_lookup_strreset_param( +static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param( struct sctp_association *asoc, __u32 resp_seq, __be16 type) { @@ -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,11 +745,11 @@ 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; + struct sctp_paramhdr *req; __u32 result; req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0); diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 721eeebfcd8a..80a97c8501a7 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -99,7 +99,7 @@ static struct sctp_transport *sctp_transport_init(struct net *net, /* Initialize the 64-bit random nonce sent with heartbeat. */ get_random_bytes(&peer->hb_nonce, sizeof(peer->hb_nonce)); - atomic_set(&peer->refcnt, 1); + refcount_set(&peer->refcnt, 1); return peer; } @@ -172,7 +172,7 @@ static void sctp_transport_destroy_rcu(struct rcu_head *head) */ static void sctp_transport_destroy(struct sctp_transport *transport) { - if (unlikely(atomic_read(&transport->refcnt))) { + if (unlikely(refcount_read(&transport->refcnt))) { WARN(1, "Attempt to destroy undead transport %p!\n", transport); return; } @@ -311,7 +311,7 @@ void sctp_transport_route(struct sctp_transport *transport, /* Hold a reference to a transport. */ int sctp_transport_hold(struct sctp_transport *transport) { - return atomic_add_unless(&transport->refcnt, 1, 0); + return refcount_inc_not_zero(&transport->refcnt); } /* Release a reference to a transport and clean up @@ -319,7 +319,7 @@ int sctp_transport_hold(struct sctp_transport *transport) */ void sctp_transport_put(struct sctp_transport *transport) { - if (atomic_dec_and_test(&transport->refcnt)) + if (refcount_dec_and_test(&transport->refcnt)) sctp_transport_destroy(transport); } @@ -405,14 +405,6 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport, TSN_lte(asoc->fast_recovery_exit, sack_ctsn)) asoc->fast_recovery = 0; - /* The appropriate cwnd increase algorithm is performed if, and only - * if the cumulative TSN whould advanced and the congestion window is - * being fully utilized. - */ - if (TSN_lte(sack_ctsn, transport->asoc->ctsn_ack_point) || - (flight_size < cwnd)) - return; - ssthresh = transport->ssthresh; pba = transport->partial_bytes_acked; pmtu = transport->asoc->pathmtu; @@ -435,6 +427,14 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport, if (asoc->fast_recovery) return; + /* The appropriate cwnd increase algorithm is performed + * if, and only if the congestion window is being fully + * utilized. Note that RFC4960 Errata 3.22 removed the + * other condition on ctsn moving. + */ + if (flight_size < cwnd) + return; + if (bytes_acked > pmtu) cwnd += pmtu; else @@ -446,23 +446,33 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport, flight_size, pba); } else { /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, - * upon each SACK arrival that advances the Cumulative TSN Ack - * Point, increase partial_bytes_acked by the total number of - * bytes of all new chunks acknowledged in that SACK including - * chunks acknowledged by the new Cumulative TSN Ack and by - * Gap Ack Blocks. + * upon each SACK arrival, increase partial_bytes_acked + * by the total number of bytes of all new chunks + * acknowledged in that SACK including chunks + * acknowledged by the new Cumulative TSN Ack and by Gap + * Ack Blocks. (updated by RFC4960 Errata 3.22) + * + * When partial_bytes_acked is greater than cwnd and + * before the arrival of the SACK the sender had less + * bytes of data outstanding than cwnd (i.e., before + * arrival of the SACK, flightsize was less than cwnd), + * reset partial_bytes_acked to cwnd. (RFC 4960 Errata + * 3.26) * - * When partial_bytes_acked is equal to or greater than cwnd - * and before the arrival of the SACK the sender had cwnd or - * more bytes of data outstanding (i.e., before arrival of the - * SACK, flightsize was greater than or equal to cwnd), - * increase cwnd by MTU, and reset partial_bytes_acked to - * (partial_bytes_acked - cwnd). + * When partial_bytes_acked is equal to or greater than + * cwnd and before the arrival of the SACK the sender + * had cwnd or more bytes of data outstanding (i.e., + * before arrival of the SACK, flightsize was greater + * than or equal to cwnd), partial_bytes_acked is reset + * to (partial_bytes_acked - cwnd). Next, cwnd is + * increased by MTU. (RFC 4960 Errata 3.12) */ pba += bytes_acked; - if (pba >= cwnd) { + if (pba > cwnd && flight_size < cwnd) + pba = cwnd; + if (pba >= cwnd && flight_size >= cwnd) { + pba = pba - cwnd; cwnd += pmtu; - pba = ((cwnd < pba) ? (pba - cwnd) : 0); } pr_debug("%s: congestion avoidance: transport:%p, " @@ -559,6 +569,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, */ transport->cwnd = max(transport->cwnd/2, 4*asoc->pathmtu); + /* RFC 4960 Errata 3.27.2: also adjust sshthresh */ + transport->ssthresh = transport->cwnd; break; } diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index ec2b3e013c2f..5f86c5062a98 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -153,13 +153,12 @@ 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) + ntohs(chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t)); + sizeof(struct sctp_chunkhdr)); } else { event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), MSG_NOTIFICATION, gfp); @@ -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..0225d62a869f 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))) @@ -1090,7 +1090,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, if (chunk) { needed = ntohs(chunk->chunk_hdr->length); - needed -= sizeof(sctp_data_chunk_t); + needed -= sizeof(struct sctp_data_chunk); } else needed = SCTP_DEFAULT_MAXWINDOW; |