diff options
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/associola.c | 6 | ||||
-rw-r--r-- | net/sctp/auth.c | 1 | ||||
-rw-r--r-- | net/sctp/bind_addr.c | 1 | ||||
-rw-r--r-- | net/sctp/chunk.c | 1 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 1 | ||||
-rw-r--r-- | net/sctp/input.c | 1 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 1 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 1 | ||||
-rw-r--r-- | net/sctp/output.c | 1 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 1 | ||||
-rw-r--r-- | net/sctp/primitive.c | 1 | ||||
-rw-r--r-- | net/sctp/protocol.c | 1 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 95 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 27 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 9 | ||||
-rw-r--r-- | net/sctp/socket.c | 15 | ||||
-rw-r--r-- | net/sctp/ssnmap.c | 1 | ||||
-rw-r--r-- | net/sctp/transport.c | 1 | ||||
-rw-r--r-- | net/sctp/tsnmap.c | 1 | ||||
-rw-r--r-- | net/sctp/ulpevent.c | 1 | ||||
-rw-r--r-- | net/sctp/ulpqueue.c | 1 |
21 files changed, 136 insertions, 32 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index df5abbff63e..99c93ee98ad 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1194,8 +1194,10 @@ void sctp_assoc_update(struct sctp_association *asoc, /* Remove any peer addresses not present in the new association. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { trans = list_entry(pos, struct sctp_transport, transports); - if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr)) - sctp_assoc_del_peer(asoc, &trans->ipaddr); + if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr)) { + sctp_assoc_rm_peer(asoc, trans); + continue; + } if (asoc->state >= SCTP_STATE_ESTABLISHED) sctp_transport_reset(trans); diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 56935bbc149..86366390038 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -34,6 +34,7 @@ * be incorporated into the next SCTP release. */ +#include <linux/slab.h> #include <linux/types.h> #include <linux/crypto.h> #include <linux/scatterlist.h> diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index bef13373168..faf71d179e4 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -43,6 +43,7 @@ */ #include <linux/types.h> +#include <linux/slab.h> #include <linux/in.h> #include <net/sock.h> #include <net/ipv6.h> diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 8e4320040f0..3eab6db59a3 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -42,6 +42,7 @@ #include <linux/net.h> #include <linux/inet.h> #include <linux/skbuff.h> +#include <linux/slab.h> #include <net/sock.h> #include <net/sctp/sctp.h> #include <net/sctp/sm.h> diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 905fda582b9..7ec09ba03a1 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -144,6 +144,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, /* Use SCTP specific send buffer space queues. */ ep->sndbuf_policy = sctp_sndbuf_policy; + sk->sk_data_ready = sctp_data_ready; sk->sk_write_space = sctp_write_space; sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); diff --git a/net/sctp/input.c b/net/sctp/input.c index 3d74b264ea2..2a570184e5a 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -53,6 +53,7 @@ #include <linux/socket.h> #include <linux/ip.h> #include <linux/time.h> /* For struct timeval */ +#include <linux/slab.h> #include <net/ip.h> #include <net/icmp.h> #include <net/snmp.h> diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index bbf5dd2a97c..ccb6dc48d15 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -46,6 +46,7 @@ #include <net/sctp/sctp.h> #include <net/sctp/sm.h> #include <linux/interrupt.h> +#include <linux/slab.h> /* Initialize an SCTP inqueue. */ void sctp_inq_init(struct sctp_inq *queue) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 1d7ac70ba39..9fb5d37c37a 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -58,6 +58,7 @@ #include <linux/netdevice.h> #include <linux/init.h> #include <linux/ipsec.h> +#include <linux/slab.h> #include <linux/ipv6.h> #include <linux/icmpv6.h> diff --git a/net/sctp/output.c b/net/sctp/output.c index 7c558936343..fad261d41ec 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -48,6 +48,7 @@ #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/init.h> +#include <linux/slab.h> #include <net/inet_ecn.h> #include <net/ip.h> #include <net/icmp.h> diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 229690f02a1..abfc0b8dee7 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -50,6 +50,7 @@ #include <linux/list.h> /* For struct list_head */ #include <linux/socket.h> #include <linux/ip.h> +#include <linux/slab.h> #include <net/sock.h> /* For skb_set_owner_w */ #include <net/sctp/sctp.h> diff --git a/net/sctp/primitive.c b/net/sctp/primitive.c index 8cb4f060bce..534c7eae9d1 100644 --- a/net/sctp/primitive.c +++ b/net/sctp/primitive.c @@ -50,6 +50,7 @@ #include <linux/socket.h> #include <linux/ip.h> #include <linux/time.h> /* For struct timeval */ +#include <linux/gfp.h> #include <net/sock.h> #include <net/sctp/sctp.h> #include <net/sctp/sm.h> diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index e771690f6d5..a56f98e82f9 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -54,6 +54,7 @@ #include <linux/bootmem.h> #include <linux/highmem.h> #include <linux/swap.h> +#include <linux/slab.h> #include <net/net_namespace.h> #include <net/protocol.h> #include <net/ip.h> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 9e732916b67..30c1767186b 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -58,6 +58,7 @@ #include <linux/inet.h> #include <linux/scatterlist.h> #include <linux/crypto.h> +#include <linux/slab.h> #include <net/sock.h> #include <linux/skbuff.h> @@ -107,7 +108,7 @@ static const struct sctp_paramhdr prsctp_param = { cpu_to_be16(sizeof(struct sctp_paramhdr)), }; -/* A helper to initialize to initialize an op error inside a +/* A helper to initialize an op error inside a * provided chunk, as most cause codes will be embedded inside an * abort chunk. */ @@ -124,6 +125,29 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); } +/* A helper to initialize an op error inside a + * provided chunk, as most cause codes will be embedded inside an + * abort chunk. Differs from sctp_init_cause in that it won't oops + * if there isn't enough space in the op error chunk + */ +int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code, + size_t paylen) +{ + sctp_errhdr_t err; + __u16 len; + + /* Cause code constants are now defined in network order. */ + err.cause = cause_code; + len = sizeof(sctp_errhdr_t) + paylen; + err.length = htons(len); + + if (skb_tailroom(chunk->skb) > len) + return -ENOSPC; + chunk->subh.err_hdr = sctp_addto_chunk_fixed(chunk, + sizeof(sctp_errhdr_t), + &err); + return 0; +} /* 3.3.2 Initiation (INIT) (1) * * This chunk is used to initiate a SCTP association between two @@ -207,7 +231,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, sp = sctp_sk(asoc->base.sk); num_types = sp->pf->supported_addrs(sp, types); - chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); + chunksize = sizeof(init) + addrs_len; + chunksize += WORD_ROUND(SCTP_SAT_LEN(num_types)); chunksize += sizeof(ecap_param); if (sctp_prsctp_enable) @@ -237,14 +262,14 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, /* Add HMACS parameter length if any were defined */ auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; if (auth_hmacs->length) - chunksize += ntohs(auth_hmacs->length); + chunksize += WORD_ROUND(ntohs(auth_hmacs->length)); else auth_hmacs = NULL; /* Add CHUNKS parameter length */ auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; if (auth_chunks->length) - chunksize += ntohs(auth_chunks->length); + chunksize += WORD_ROUND(ntohs(auth_chunks->length)); else auth_chunks = NULL; @@ -254,7 +279,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, /* If we have any extensions to report, account for that */ if (num_ext) - chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; + chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) + + num_ext); /* RFC 2960 3.3.2 Initiation (INIT) (1) * @@ -396,13 +422,13 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; if (auth_hmacs->length) - chunksize += ntohs(auth_hmacs->length); + chunksize += WORD_ROUND(ntohs(auth_hmacs->length)); else auth_hmacs = NULL; auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; if (auth_chunks->length) - chunksize += ntohs(auth_chunks->length); + chunksize += WORD_ROUND(ntohs(auth_chunks->length)); else auth_chunks = NULL; @@ -411,7 +437,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, } if (num_ext) - chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; + chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) + + num_ext); /* Now allocate and fill out the chunk. */ retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); @@ -1128,6 +1155,24 @@ nodata: return retval; } +/* Create an Operation Error chunk of a fixed size, + * specifically, max(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT) + * This is a helper function to allocate an error chunk for + * for those invalid parameter codes in which we may not want + * to report all the errors, if the incomming chunk is large + */ +static inline struct sctp_chunk *sctp_make_op_error_fixed( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk) +{ + size_t size = asoc ? asoc->pathmtu : 0; + + if (!size) + size = SCTP_DEFAULT_MAXSEGMENT; + + return sctp_make_op_error_space(asoc, chunk, size); +} + /* Create an Operation Error chunk. */ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, const struct sctp_chunk *chunk, @@ -1370,6 +1415,18 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) return target; } +/* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient + * space in the chunk + */ +void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk, + int len, const void *data) +{ + if (skb_tailroom(chunk->skb) > len) + return sctp_addto_chunk(chunk, len, data); + else + return NULL; +} + /* Append bytes from user space to the end of a chunk. Will panic if * chunk is not big enough. * Returns a kernel err value. @@ -1973,13 +2030,12 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc, * returning multiple unknown parameters. */ if (NULL == *errp) - *errp = sctp_make_op_error_space(asoc, chunk, - ntohs(chunk->chunk_hdr->length)); + *errp = sctp_make_op_error_fixed(asoc, chunk); if (*errp) { - sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, + sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM, WORD_ROUND(ntohs(param.p->length))); - sctp_addto_chunk(*errp, + sctp_addto_chunk_fixed(*errp, WORD_ROUND(ntohs(param.p->length)), param.v); } else { @@ -3314,21 +3370,6 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, sctp_chunk_free(asconf); asoc->addip_last_asconf = NULL; - /* Send the next asconf chunk from the addip chunk queue. */ - if (!list_empty(&asoc->addip_chunk_list)) { - struct list_head *entry = asoc->addip_chunk_list.next; - asconf = list_entry(entry, struct sctp_chunk, list); - - list_del_init(entry); - - /* Hold the chunk until an ASCONF_ACK is received. */ - sctp_chunk_hold(asconf); - if (sctp_primitive_ASCONF(asoc, asconf)) - sctp_chunk_free(asconf); - else - asoc->addip_last_asconf = asconf; - } - return retval; } diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 500886bda9b..d5ae450b6f0 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -51,6 +51,7 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/ip.h> +#include <linux/gfp.h> #include <net/sock.h> #include <net/sctp/sctp.h> #include <net/sctp/sm.h> @@ -961,6 +962,29 @@ static int sctp_cmd_send_msg(struct sctp_association *asoc, } +/* Sent the next ASCONF packet currently stored in the association. + * This happens after the ASCONF_ACK was succeffully processed. + */ +static void sctp_cmd_send_asconf(struct sctp_association *asoc) +{ + /* Send the next asconf chunk from the addip chunk + * queue. + */ + if (!list_empty(&asoc->addip_chunk_list)) { + struct list_head *entry = asoc->addip_chunk_list.next; + struct sctp_chunk *asconf = list_entry(entry, + struct sctp_chunk, list); + list_del_init(entry); + + /* Hold the chunk until an ASCONF_ACK is received. */ + sctp_chunk_hold(asconf); + if (sctp_primitive_ASCONF(asoc, asconf)) + sctp_chunk_free(asconf); + else + asoc->addip_last_asconf = asconf; + } +} + /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real @@ -1616,6 +1640,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, } error = sctp_cmd_send_msg(asoc, cmd->obj.msg); break; + case SCTP_CMD_SEND_NEXT_ASCONF: + sctp_cmd_send_asconf(asoc); + break; default: printk(KERN_WARNING "Impossible command: %u, %p\n", cmd->verb, cmd->obj.ptr); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 47bc20d3a85..24b2cd55563 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -56,6 +56,7 @@ #include <linux/ipv6.h> #include <linux/net.h> #include <linux/inet.h> +#include <linux/slab.h> #include <net/sock.h> #include <net/inet_ecn.h> #include <linux/skbuff.h> @@ -3675,8 +3676,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); if (!sctp_process_asconf_ack((struct sctp_association *)asoc, - asconf_ack)) + asconf_ack)) { + /* Successfully processed ASCONF_ACK. We can + * release the next asconf if we have one. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_NEXT_ASCONF, + SCTP_NULL()); return SCTP_DISPOSITION_CONSUME; + } abort = sctp_make_abort(asoc, asconf_ack, sizeof(sctp_errhdr_t)); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index dfc5c127efd..44a1ab03a3f 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -67,6 +67,7 @@ #include <linux/poll.h> #include <linux/init.h> #include <linux/crypto.h> +#include <linux/slab.h> #include <net/ip.h> #include <net/icmp.h> @@ -3718,12 +3719,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->hmac = NULL; SCTP_DBG_OBJCNT_INC(sock); - percpu_counter_inc(&sctp_sockets_allocated); /* Set socket backlog limit. */ sk->sk_backlog.limit = sysctl_sctp_rmem[1]; local_bh_disable(); + percpu_counter_inc(&sctp_sockets_allocated); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); local_bh_enable(); @@ -3740,8 +3741,8 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk) /* Release our hold on the endpoint. */ ep = sctp_sk(sk)->ep; sctp_endpoint_free(ep); - percpu_counter_dec(&sctp_sockets_allocated); local_bh_disable(); + percpu_counter_dec(&sctp_sockets_allocated); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); local_bh_enable(); } @@ -6188,6 +6189,16 @@ do_nonblock: goto out; } +void sctp_data_ready(struct sock *sk, int len) +{ + read_lock_bh(&sk->sk_callback_lock); + if (sk_has_sleeper(sk)) + wake_up_interruptible_sync_poll(sk->sk_sleep, POLLIN | + POLLRDNORM | POLLRDBAND); + sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); + read_unlock_bh(&sk->sk_callback_lock); +} + /* If socket sndbuf has changed, wake up all per association waiters. */ void sctp_write_space(struct sock *sk) { diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c index 737d330e5ff..442ad4ed631 100644 --- a/net/sctp/ssnmap.c +++ b/net/sctp/ssnmap.c @@ -37,6 +37,7 @@ */ #include <linux/types.h> +#include <linux/slab.h> #include <net/sctp/sctp.h> #include <net/sctp/sm.h> diff --git a/net/sctp/transport.c b/net/sctp/transport.c index b827d21dbe5..be4d63d5a5c 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -48,6 +48,7 @@ * be incorporated into the next SCTP release. */ +#include <linux/slab.h> #include <linux/types.h> #include <linux/random.h> #include <net/sctp/sctp.h> diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c index 9bd64565021..747d5412c46 100644 --- a/net/sctp/tsnmap.c +++ b/net/sctp/tsnmap.c @@ -42,6 +42,7 @@ * be incorporated into the next SCTP release. */ +#include <linux/slab.h> #include <linux/types.h> #include <linux/bitmap.h> #include <net/sctp/sctp.h> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 8b3560fd876..aa72e89c3ee 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -43,6 +43,7 @@ * be incorporated into the next SCTP release. */ +#include <linux/slab.h> #include <linux/types.h> #include <linux/skbuff.h> #include <net/sctp/structs.h> diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 7b23803343c..3a448536f0b 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -41,6 +41,7 @@ * be incorporated into the next SCTP release. */ +#include <linux/slab.h> #include <linux/types.h> #include <linux/skbuff.h> #include <net/sock.h> |