diff options
| -rw-r--r-- | include/net/sctp/constants.h | 54 | ||||
| -rw-r--r-- | include/net/sctp/sctp.h | 6 | ||||
| -rw-r--r-- | include/net/sctp/structs.h | 53 | ||||
| -rw-r--r-- | net/sctp/Kconfig | 47 | ||||
| -rw-r--r-- | net/sctp/Makefile | 3 | ||||
| -rw-r--r-- | net/sctp/associola.c | 11 | ||||
| -rw-r--r-- | net/sctp/endpointola.c | 89 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 248 | ||||
| -rw-r--r-- | net/sctp/socket.c | 186 |
9 files changed, 381 insertions, 316 deletions
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 0d6a20a7390e..60fe2147486f 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -6,46 +6,42 @@ * * This file is part of the SCTP kernel reference Implementation * - * This file is part of the implementation of the add-IP extension, - * based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001, - * for the SCTP kernel reference Implementation. - * - * The SCTP reference implementation is free software; + * The SCTP reference implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * the SCTP reference implementation is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * - * Please send any bug reports or fixes you make to one of the following email - * addresses: + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp * - * La Monte H.P. Yarroll <piggy@acm.org> - * Karl Knutson <karl@athena.chicago.il.us> - * Randall Stewart <randall@stewart.chicago.il.us> - * Ken Morneau <kmorneau@cisco.com> - * Qiaobing Xie <qxie1@motorola.com> - * Xingang Guo <xingang.guo@intel.com> - * Sridhar Samudrala <samudrala@us.ibm.com> - * Daisy Chang <daisyc@us.ibm.com> + * Written or modified by: + * La Monte H.P. Yarroll <piggy@acm.org> + * Karl Knutson <karl@athena.chicago.il.us> + * Randall Stewart <randall@stewart.chicago.il.us> + * Ken Morneau <kmorneau@cisco.com> + * Qiaobing Xie <qxie1@motorola.com> + * Xingang Guo <xingang.guo@intel.com> + * Sridhar Samudrala <samudrala@us.ibm.com> + * Daisy Chang <daisyc@us.ibm.com> * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. - * - * There are still LOTS of bugs in this code... I always run on the motto - * "it is a wonder any code ever works :)" - * - * */ #ifndef __sctp_constants_h__ @@ -336,10 +332,18 @@ typedef enum { #define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */ -#define SCTP_COOKIE_MULTIPLE 64 /* Pad out our cookie to make our hash +#define SCTP_COOKIE_MULTIPLE 32 /* Pad out our cookie to make our hash * functions simpler to write. */ +#if defined (CONFIG_SCTP_HMAC_MD5) +#define SCTP_COOKIE_HMAC_ALG "md5" +#elif defined (CONFIG_SCTP_HMAC_SHA1) +#define SCTP_COOKIE_HMAC_ALG "sha1" +#else +#define SCTP_COOKIE_HMAC_ALG NULL +#endif + /* These return values describe the success or failure of a number of * routines which form the lower interface to SCTP_outqueue. */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index f964badf7062..5743ea6ace44 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -178,12 +178,6 @@ extern void sctp_err_finish(struct sock *, struct sctp_endpoint *, struct sctp_association *); extern void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, struct sctp_transport *t, __u32 pmtu); -/* - * sctp/hashdriver.c - */ -extern void sctp_hash_digest(const char *secret, const int secret_len, - const char *text, const int text_len, - __u8 *digest); /* * Section: Macros, externs, and inlines diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 5cf74d3c2882..5e7d728b2130 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -283,8 +283,11 @@ struct sctp_opt { /* PF_ family specific functions. */ struct sctp_pf *pf; + /* Access to HMAC transform. */ + struct crypto_tfm *hmac; + /* What is our base endpointer? */ - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* Various Socket Options. */ __u16 default_stream; @@ -1054,11 +1057,6 @@ struct sctp_endpoint { /* Common substructure for endpoint and association. */ sctp_endpoint_common_t base; - /* These are the system-wide defaults and other stuff which is - * endpoint-independent. - */ - struct sctp_protocol *proto; - /* Associations: A list of current associations and mappings * to the data consumers for each association. This * may be in the form of a hash table or other @@ -1092,28 +1090,29 @@ struct sctp_endpoint { }; /* Recover the outter endpoint structure. */ -static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base) +static inline struct sctp_endpoint *sctp_ep(sctp_endpoint_common_t *base) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; - ep = container_of(base, sctp_endpoint_t, base); + ep = container_of(base, struct sctp_endpoint, base); return ep; } /* These are function signatures for manipulating endpoints. */ -sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *, struct sock *, int); -sctp_endpoint_t *sctp_endpoint_init(struct sctp_endpoint *, - struct sctp_protocol *, - struct sock *, int gfp); -void sctp_endpoint_free(sctp_endpoint_t *); -void sctp_endpoint_put(sctp_endpoint_t *); -void sctp_endpoint_hold(sctp_endpoint_t *); -void sctp_endpoint_add_asoc(sctp_endpoint_t *, struct sctp_association *asoc); -struct sctp_association *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, - const union sctp_addr *paddr, - struct sctp_transport **); -int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *); -sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, +struct sctp_endpoint *sctp_endpoint_new(struct sock *, int); +struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *, + struct sock *, int gfp); +void sctp_endpoint_free(struct sctp_endpoint *); +void sctp_endpoint_put(struct sctp_endpoint *); +void sctp_endpoint_hold(struct sctp_endpoint *); +void sctp_endpoint_add_asoc(struct sctp_endpoint *, struct sctp_association *); +struct sctp_association *sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, + const union sctp_addr *paddr, + struct sctp_transport **); +int sctp_endpoint_is_peeled_off(struct sctp_endpoint *, + const union sctp_addr *); +struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *, const union sctp_addr *); int sctp_has_association(const union sctp_addr *laddr, const union sctp_addr *paddr); @@ -1126,8 +1125,8 @@ int sctp_process_init(struct sctp_association *, sctp_cid_t cid, sctp_init_chunk_t *init, int gfp); int sctp_process_param(struct sctp_association *, union sctp_params param, const union sctp_addr *from, int gfp); -__u32 sctp_generate_tag(const sctp_endpoint_t *); -__u32 sctp_generate_tsn(const sctp_endpoint_t *); +__u32 sctp_generate_tag(const struct sctp_endpoint *); +__u32 sctp_generate_tsn(const struct sctp_endpoint *); /* RFC2960 @@ -1162,7 +1161,7 @@ struct sctp_association { __u32 eyecatcher; /* This is our parent endpoint. */ - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* These are those association elements needed in the cookie. */ sctp_cookie_t c; @@ -1571,10 +1570,10 @@ static inline struct sctp_association *sctp_assoc(sctp_endpoint_common_t *base) struct sctp_association * -sctp_association_new(const sctp_endpoint_t *, const struct sock *, +sctp_association_new(const struct sctp_endpoint *, const struct sock *, sctp_scope_t scope, int gfp); struct sctp_association * -sctp_association_init(struct sctp_association *, const sctp_endpoint_t *, +sctp_association_init(struct sctp_association *, const struct sctp_endpoint *, const struct sock *, sctp_scope_t scope, int gfp); void sctp_association_free(struct sctp_association *); diff --git a/net/sctp/Kconfig b/net/sctp/Kconfig index 500d0e988b47..4df681dde7e5 100644 --- a/net/sctp/Kconfig +++ b/net/sctp/Kconfig @@ -43,12 +43,12 @@ config SCTP_ADLER32 bool "SCTP: Use old checksum (Adler-32)" depends on IP_SCTP help - RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. + RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. This has been deprecated and replaced by an algorithm now referred to as crc32c. - If you say Y, this will use the Adler-32 algorithm, this might be useful - for interoperation with downlevel peers. + If you say Y, this will use the Adler-32 algorithm, this might be + useful for interoperation with downlevel peers. If unsure, say N. @@ -58,19 +58,46 @@ config SCTP_DBG_MSG help If you say Y, this will enable verbose debugging messages. - If unsure, say N. However, if you are running into problems, use this - option to gather detailed trace information + If unsure, say N. However, if you are running into problems, use + this option to gather detailed trace information config SCTP_DBG_OBJCNT bool "SCTP: Debug object counts" depends on IP_SCTP help - If you say Y, this will enable debugging support for counting the types - of objects that are currently allocated. This is useful for identifying - memory leaks. If the /proc filesystem is enabled this debug information - can be viewed by 'cat /proc/net/sctp/sctp_dbg_objcnt' + If you say Y, this will enable debugging support for counting the + type of objects that are currently allocated. This is useful for + identifying memory leaks. If the /proc filesystem is enabled this + debug information can be viewed by + 'cat /proc/net/sctp/sctp_dbg_objcnt' If unsure, say N -endmenu +choice + prompt "SCTP: Cookie HMAC Algorithm" + help + HMAC algorithm to be used during association initialization. It + is strongly recommended to use HMAC-SHA1 or HMAC-MD5. See + configuration for Cryptographic API and enable those algorithms + to make usable by SCTP. + +config SCTP_HMAC_NONE + bool "None" + help + Choosing this disables the use of an HMAC during association + establishment. It is advised to use either HMAC-MD5 or HMAC-SHA1. + +config SCTP_HMAC_SHA1 + bool "HMAC-SHA1" if CRYPTO_HMAC=y && CRYPTO_SHA1=y || CRYPTO_SHA1=m + help + Enable the use of HMAC-SHA1 during association establishment. It + is advised to use either HMAC-MD5 or HMAC-SHA1. + +config SCTP_HMAC_MD5 + bool "HMAC-MD5" if CRYPTO_HMAC=y && CRYPTO_MD5=y || CRYPTO_MD5=m + help + Enable the use of HMAC-MD5 during association establishment. It is + advised to use either HMAC-MD5 or HMAC-SHA1. +endchoice +endmenu diff --git a/net/sctp/Makefile b/net/sctp/Makefile index 545fad836084..96f3a421379f 100644 --- a/net/sctp/Makefile +++ b/net/sctp/Makefile @@ -9,8 +9,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ transport.o sm_make_chunk.o ulpevent.o \ inqueue.o outqueue.o ulpqueue.o command.o \ tsnmap.o bind_addr.o socket.o primitive.o \ - output.o input.o hashdriver.o sla1.o \ - debug.o ssnmap.o proc.o + output.o input.o debug.o ssnmap.o proc.o ifeq ($(CONFIG_SCTP_ADLER32), y) sctp-y += adler32.o diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 6ffeb79ba851..6264095aabe9 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -96,6 +96,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, int priority) { struct sctp_opt *sp; + struct sctp_protocol *proto = sctp_get_protocol(); int i; /* Retrieve the SCTP per socket area. */ @@ -136,10 +137,10 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, asoc->frag_point = 0; /* Initialize the default association max_retrans and RTO values. */ - asoc->max_retrans = ep->proto->max_retrans_association; - asoc->rto_initial = ep->proto->rto_initial; - asoc->rto_max = ep->proto->rto_max; - asoc->rto_min = ep->proto->rto_min; + asoc->max_retrans = proto->max_retrans_association; + asoc->rto_initial = proto->rto_initial; + asoc->rto_max = proto->rto_max; + asoc->rto_min = proto->rto_min; asoc->overall_error_threshold = 0; asoc->overall_error_count = 0; @@ -147,7 +148,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, /* Initialize the maximum mumber of new data packets that can be sent * in a burst. */ - asoc->max_burst = ep->proto->max_burst; + asoc->max_burst = proto->max_burst; /* Copy things from the endpoint. */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 5a1d749da57c..f4bdabee9b05 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -54,27 +54,27 @@ #include <linux/slab.h> #include <linux/in.h> #include <linux/random.h> /* get_random_bytes() */ +#include <linux/crypto.h> #include <net/sock.h> #include <net/ipv6.h> #include <net/sctp/sctp.h> #include <net/sctp/sm.h> /* Forward declarations for internal helpers. */ -static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep); +static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep); -/* Create a sctp_endpoint_t with all that boring stuff initialized. +/* Create a sctp_endpoint with all that boring stuff initialized. * Returns NULL if there isn't enough memory. */ -sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto, - struct sock *sk, int priority) +struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* Build a local endpoint. */ - ep = t_new(sctp_endpoint_t, priority); + ep = t_new(struct sctp_endpoint, gfp); if (!ep) goto fail; - if (!sctp_endpoint_init(ep, proto, sk, priority)) + if (!sctp_endpoint_init(ep, sk, gfp)) goto fail_init; ep->base.malloced = 1; SCTP_DBG_OBJCNT_INC(ep); @@ -89,12 +89,11 @@ fail: /* * Initialize the base fields of the endpoint structure. */ -sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, - struct sctp_protocol *proto, - struct sock *sk, int priority) +struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, + struct sock *sk, int gfp) { struct sctp_opt *sp = sctp_sk(sk); - memset(ep, 0, sizeof(sctp_endpoint_t)); + memset(ep, 0, sizeof(struct sctp_endpoint)); /* Initialize the base structure. */ /* What type of endpoint are we? */ @@ -110,8 +109,7 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, /* Set its top-half handler */ sctp_inq_set_th_handler(&ep->base.inqueue, - (void (*)(void *))sctp_endpoint_bh_rcv, - ep); + (void (*)(void *))sctp_endpoint_bh_rcv, ep); /* Initialize the bind addr area */ sctp_bind_addr_init(&ep->base.bind_addr, 0); @@ -121,21 +119,16 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, ep->base.sk = sk; sock_hold(ep->base.sk); - /* This pointer is useful to access the default protocol parameter - * values. - */ - ep->proto = proto; - /* Create the lists of associations. */ INIT_LIST_HEAD(&ep->asocs); /* Set up the base timeout information. */ ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; - ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = SCTP_DEFAULT_TIMEOUT_T1_COOKIE; - ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = SCTP_DEFAULT_TIMEOUT_T1_INIT; - ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = sp->rtoinfo.srto_initial; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; @@ -146,11 +139,11 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] = 5 * sp->rtoinfo.srto_max; - ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = + ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; - ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = + ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = SCTP_DEFAULT_TIMEOUT_SACK; - ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = + ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; /* Set up the default send/receive buffer space. */ @@ -175,7 +168,8 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, } /* Add an association to an endpoint. */ -void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) +void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, + struct sctp_association *asoc) { struct sock *sk = ep->base.sk; @@ -191,14 +185,14 @@ void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) /* Free the endpoint structure. Delay cleanup until * all users have released their reference count on this structure. */ -void sctp_endpoint_free(sctp_endpoint_t *ep) +void sctp_endpoint_free(struct sctp_endpoint *ep) { ep->base.dead = 1; sctp_endpoint_put(ep); } /* Final destructor for endpoint. */ -void sctp_endpoint_destroy(sctp_endpoint_t *ep) +void sctp_endpoint_destroy(struct sctp_endpoint *ep) { SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); @@ -207,9 +201,12 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep) /* Unlink this endpoint, so we can't find it again! */ sctp_unhash_endpoint(ep); - /* Cleanup the inqueue. */ - sctp_inq_free(&ep->base.inqueue); + /* Free up the HMAC transform. */ + if (sctp_sk(ep->base.sk)->hmac) + crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); + /* Cleanup. */ + sctp_inq_free(&ep->base.inqueue); sctp_bind_addr_free(&ep->base.bind_addr); /* Remove and free the port */ @@ -228,7 +225,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep) } /* Hold a reference to an endpoint. */ -void sctp_endpoint_hold(sctp_endpoint_t *ep) +void sctp_endpoint_hold(struct sctp_endpoint *ep) { atomic_inc(&ep->base.refcnt); } @@ -236,17 +233,17 @@ void sctp_endpoint_hold(sctp_endpoint_t *ep) /* Release a reference to an endpoint and clean up if there are * no more references. */ -void sctp_endpoint_put(sctp_endpoint_t *ep) +void sctp_endpoint_put(struct sctp_endpoint *ep) { if (atomic_dec_and_test(&ep->base.refcnt)) sctp_endpoint_destroy(ep); } /* Is this the endpoint we are looking for? */ -sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, - const union sctp_addr *laddr) +struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep, + const union sctp_addr *laddr) { - sctp_endpoint_t *retval; + struct sctp_endpoint *retval; sctp_read_lock(&ep->base.addr_lock); if (ep->base.bind_addr.port == laddr->v4.sin_port) { @@ -268,19 +265,19 @@ out: * We do a linear search of the associations for this endpoint. * We return the matching transport address too. */ -sctp_association_t *__sctp_endpoint_lookup_assoc( - const sctp_endpoint_t *endpoint, +struct sctp_association *__sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, const union sctp_addr *paddr, struct sctp_transport **transport) { int rport; - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; rport = paddr->v4.sin_port; - list_for_each(pos, &endpoint->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, struct sctp_association, asocs); if (rport == asoc->peer.port) { sctp_read_lock(&asoc->base.addr_lock); *transport = sctp_assoc_lookup_paddr(asoc, paddr); @@ -296,12 +293,12 @@ sctp_association_t *__sctp_endpoint_lookup_assoc( } /* Lookup association on an endpoint based on a peer address. BH-safe. */ -sctp_association_t *sctp_endpoint_lookup_assoc( - const sctp_endpoint_t *ep, +struct sctp_association *sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, const union sctp_addr *paddr, struct sctp_transport **transport) { - sctp_association_t *asoc; + struct sctp_association *asoc; sctp_local_bh_disable(); asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport); @@ -313,7 +310,7 @@ sctp_association_t *sctp_endpoint_lookup_assoc( /* Look for any peeled off association from the endpoint that matches the * given peer address. */ -int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep, +int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep, const union sctp_addr *paddr) { struct list_head *pos; @@ -337,9 +334,9 @@ int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep, /* Do delayed input processing. This is scheduled by sctp_rcv(). * This may be called on BH or task time. */ -static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) +static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sock *sk; struct sctp_transport *transport; sctp_chunk_t *chunk; @@ -355,7 +352,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) inqueue = &ep->base.inqueue; sk = ep->base.sk; - while (NULL != (chunk = sctp_inq_pop(inqueue))) { + while (NULL != (chunk = sctp_inq_pop(inqueue))) { subtype.chunk = chunk->chunk_hdr->type; /* We might have grown an association since last we diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index fb373acf5eb4..87dc7ad07583 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -59,6 +59,8 @@ #include <linux/ipv6.h> #include <linux/net.h> #include <linux/inet.h> +#include <asm/scatterlist.h> +#include <linux/crypto.h> #include <net/sock.h> #include <linux/skbuff.h> @@ -156,7 +158,7 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, * Host Name Address (Note 3) Optional 11 * Supported Address Types (Note 4) Optional 12 */ -sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_init(const struct sctp_association *asoc, const sctp_bind_addr_t *bp, int gfp, int vparam_len) { @@ -236,7 +238,7 @@ nodata: return retval; } -sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_init_ack(const struct sctp_association *asoc, const sctp_chunk_t *chunk, int gfp, int unkparam_len) { @@ -294,7 +296,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); /* We need to remove the const qualifier at this point. */ - retval->asoc = (sctp_association_t *) asoc; + retval->asoc = (struct sctp_association *) asoc; /* RFC 2960 6.4 Multi-homed SCTP Endpoints * @@ -350,7 +352,7 @@ nomem_rawaddr: * An implementation SHOULD make the cookie as small as possible * to insure interoperability. */ -sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_cookie_echo(const struct sctp_association *asoc, const sctp_chunk_t *chunk) { sctp_chunk_t *retval; @@ -401,7 +403,7 @@ nodata: * * Set to zero on transmit and ignored on receipt. */ -sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_cookie_ack(const struct sctp_association *asoc, const sctp_chunk_t *chunk) { sctp_chunk_t *retval; @@ -446,7 +448,7 @@ sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc, * * Note: The CWR is considered a Control chunk. */ -sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_cwr(const struct sctp_association *asoc, const __u32 lowest_tsn, const sctp_chunk_t *chunk) { @@ -481,7 +483,7 @@ nodata: } /* Make an ECNE chunk. This is a congestion experienced report. */ -sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_ecne(const struct sctp_association *asoc, const __u32 lowest_tsn) { sctp_chunk_t *retval; @@ -502,7 +504,7 @@ nodata: /* Make a DATA chunk for the given association from the provided * parameters. However, do not populate the data payload. */ -sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, +sctp_chunk_t *sctp_make_datafrag_empty(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, __u8 flags, __u16 ssn) { @@ -537,7 +539,7 @@ nodata: /* Make a DATA chunk for the given association. Populate the data * payload. */ -sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc, +sctp_chunk_t *sctp_make_datafrag(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, const __u8 *data, __u8 flags, __u16 ssn) @@ -554,7 +556,7 @@ sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc, /* Make a DATA chunk for the given association to ride on stream id * 'stream', with a payload id of 'payload', and a body of 'data'. */ -sctp_chunk_t *sctp_make_data(sctp_association_t *asoc, +sctp_chunk_t *sctp_make_data(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, const __u8 *data) { @@ -571,7 +573,7 @@ sctp_chunk_t *sctp_make_data(sctp_association_t *asoc, * hold 'data_len' octets of data. We use this version when we need * to build the message AFTER allocating memory. */ -sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, +sctp_chunk_t *sctp_make_data_empty(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len) { @@ -584,7 +586,7 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, * association. This reports on which TSN's we've seen to date, * including duplicates and gaps. */ -sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) +sctp_chunk_t *sctp_make_sack(const struct sctp_association *asoc) { sctp_chunk_t *retval; sctp_sackhdr_t sack; @@ -599,11 +601,13 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn); /* Count the number of Gap Ack Blocks. */ - sctp_tsnmap_iter_init(map, &iter); - for (num_gabs = 0; - sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end); - num_gabs++) { - /* Do nothing. */ + num_gabs = 0; + + if (sctp_tsnmap_has_gap(map)) { + sctp_tsnmap_iter_init(map, &iter); + while (sctp_tsnmap_next_gap_ack(map, &iter, + &gab.start, &gab.end)) + num_gabs++; } num_dup_tsns = sctp_tsnmap_num_dups(map); @@ -659,11 +663,15 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) sctp_addto_chunk(retval, sizeof(sack), &sack); /* Put the Gap Ack Blocks into the chunk. */ - sctp_tsnmap_iter_init(map, &iter); - while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) { - gab.start = htons(gab.start); - gab.end = htons(gab.end); - sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), &gab); + if (num_gabs) { + sctp_tsnmap_iter_init(map, &iter); + while(sctp_tsnmap_next_gap_ack(map, &iter, + &gab.start, &gab.end)) { + gab.start = htons(gab.start); + gab.end = htons(gab.end); + sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), + &gab); + } } /* Register the duplicates. */ @@ -675,7 +683,7 @@ nodata: } /* Make a SHUTDOWN chunk. */ -sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) +sctp_chunk_t *sctp_make_shutdown(const struct sctp_association *asoc) { sctp_chunk_t *retval; sctp_shutdownhdr_t shut; @@ -695,7 +703,7 @@ nodata: return retval; } -sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_shutdown_ack(const struct sctp_association *asoc, const sctp_chunk_t *chunk) { sctp_chunk_t *retval; @@ -717,7 +725,7 @@ sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, return retval; } -sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_shutdown_complete(const struct sctp_association *asoc, const sctp_chunk_t *chunk) { sctp_chunk_t *retval; @@ -747,7 +755,7 @@ sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc, /* Create an ABORT. Note that we set the T bit if we have no * association. */ -sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_abort(const struct sctp_association *asoc, const sctp_chunk_t *chunk, const size_t hint) { @@ -775,7 +783,7 @@ sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc, } /* Helper to create ABORT with a NO_USER_DATA error. */ -sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_abort_no_data(const struct sctp_association *asoc, const sctp_chunk_t *chunk, __u32 tsn) { sctp_chunk_t *retval; @@ -809,7 +817,7 @@ no_mem: } /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */ -sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_abort_user(const struct sctp_association *asoc, const sctp_chunk_t *chunk, const struct msghdr *msg) { @@ -856,7 +864,7 @@ err_chunk: } /* Make a HEARTBEAT chunk. */ -sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_heartbeat(const struct sctp_association *asoc, const struct sctp_transport *transport, const void *payload, const size_t paylen) { @@ -876,7 +884,7 @@ nodata: return retval; } -sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_heartbeat_ack(const struct sctp_association *asoc, const sctp_chunk_t *chunk, const void *payload, const size_t paylen) { @@ -906,7 +914,7 @@ nodata: /* Create an Operation Error chunk with the specified space reserved. * This routine can be used for containing multiple causes in the chunk. */ -sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_op_error_space(const struct sctp_association *asoc, const sctp_chunk_t *chunk, size_t size) { @@ -933,7 +941,7 @@ nodata: } /* Create an Operation Error chunk. */ -sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_op_error(const struct sctp_association *asoc, const sctp_chunk_t *chunk, __u16 cause_code, const void *payload, size_t paylen) @@ -956,7 +964,8 @@ nodata: /* Turn an skb into a chunk. * FIXME: Eventually move the structure directly inside the skb->cb[]. */ -sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, +sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, + const struct sctp_association *asoc, struct sock *sk) { sctp_chunk_t *retval = t_new(sctp_chunk_t, GFP_ATOMIC); @@ -970,7 +979,7 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, } retval->skb = skb; - retval->asoc = (sctp_association_t *) asoc; + retval->asoc = (struct sctp_association *)asoc; retval->num_times_sent = 0; retval->has_tsn = 0; retval->has_ssn = 0; @@ -1023,7 +1032,7 @@ const union sctp_addr *sctp_source(const sctp_chunk_t *chunk) /* Create a new chunk, setting the type and flags headers from the * arguments, reserving enough space for a 'paylen' byte payload. */ -sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, +sctp_chunk_t *sctp_make_chunk(const struct sctp_association *asoc, __u8 type, __u8 flags, int paylen) { sctp_chunk_t *retval; @@ -1032,7 +1041,7 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, struct sock *sk; /* No need to allocate LL here, as this is only a chunk. */ - skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), + skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), GFP_ATOMIC); if (!skb) goto nodata; @@ -1135,7 +1144,7 @@ out: */ -int sctp_datachunks_from_user(sctp_association_t *asoc, +int sctp_datachunks_from_user(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, struct msghdr *msg, int msg_len, struct sk_buff_head *chunks) @@ -1291,10 +1300,10 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) } /* Create a CLOSED association to use with an incoming packet. */ -sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep, +struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep, struct sctp_chunk *chunk, int gfp) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sk_buff *skb; sctp_scope_t scope; @@ -1339,15 +1348,18 @@ fail: /* Build a cookie representing asoc. * This INCLUDES the param header needed to put the cookie in the INIT ACK. */ -sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_chunk_t *init_chunk, int *cookie_len, const __u8 *raw_addrs, int addrs_len) { sctp_cookie_param_t *retval; sctp_signed_cookie_t *cookie; + struct scatterlist sg; int headersize, bodysize; + unsigned int keylen = SCTP_SECRET_SIZE; + char *key; headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; bodysize = sizeof(sctp_cookie_t) @@ -1361,8 +1373,8 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, - (bodysize % SCTP_COOKIE_MULTIPLE); *cookie_len = headersize + bodysize; - retval = (sctp_cookie_param_t *) - kmalloc(*cookie_len, GFP_ATOMIC); + retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC); + if (!retval) { *cookie_len = 0; goto nodata; @@ -1392,31 +1404,39 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, ntohs(init_chunk->chunk_hdr->length)); /* Copy the raw local address list of the association. */ - memcpy((__u8 *)&cookie->c.peer_init[0] + - ntohs(init_chunk->chunk_hdr->length), raw_addrs, - addrs_len); - - /* Sign the message. */ - sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE, - (__u8 *) &cookie->c, bodysize, cookie->signature); + memcpy((__u8 *)&cookie->c.peer_init[0] + + ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len); + + if (sctp_sk(ep->base.sk)->hmac) { + /* Sign the message. */ + sg.page = virt_to_page(&cookie->c); + sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE; + sg.length = bodysize; + key = (char *)ep->secret_key[ep->current_key]; + + crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, + cookie->signature); + } nodata: return retval; } /* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ -sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, int gfp, - int *error, sctp_chunk_t **err_chk_p) +struct sctp_association *sctp_unpack_cookie( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + sctp_chunk_t *chunk, int gfp, + int *error, sctp_chunk_t **errp) { - sctp_association_t *retval = NULL; + struct sctp_association *retval = NULL; sctp_signed_cookie_t *cookie; sctp_cookie_t *bear_cookie; - int headersize, bodysize; - int fixed_size; - __u8 digest_buf[SCTP_SIGNATURE_SIZE]; - int secret; + int headersize, bodysize, fixed_size; + __u8 digest[SCTP_SIGNATURE_SIZE]; + struct scatterlist sg; + unsigned int keylen; + char *key; sctp_scope_t scope; struct sk_buff *skb = chunk->skb; @@ -1440,23 +1460,34 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, cookie = chunk->subh.cookie_hdr; bear_cookie = &cookie->c; + if (!sctp_sk(ep->base.sk)->hmac) + goto no_hmac; + /* Check the signature. */ - secret = ep->current_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (__u8 *) bear_cookie, bodysize, - digest_buf); - if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { - /* Try the previous key. */ - secret = ep->last_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (__u8 *) bear_cookie, bodysize, digest_buf); - if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + keylen = SCTP_SECRET_SIZE; + sg.page = virt_to_page(bear_cookie); + sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE; + sg.length = bodysize; + key = (char *)ep->secret_key[ep->current_key]; + + memset(digest, 0x00, sizeof(digest)); + crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, digest); + + if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { + /* Try the previous key. */ + key = (char *)ep->secret_key[ep->last_key]; + memset(digest, 0x00, sizeof(digest)); + crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, + digest); + + if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Yikes! Still bad signature! */ *error = -SCTP_IERROR_BAD_SIG; goto fail; } } +no_hmac: /* Check to see if the cookie is stale. If there is already * an association, there is no need to check cookie's expiration * for init collision case of lost COOKIE ACK. @@ -1472,15 +1503,15 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, * Cookie that has expired. */ len = ntohs(chunk->chunk_hdr->length); - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) { + *errp = sctp_make_op_error_space(asoc, chunk, len); + if (*errp) { suseconds_t usecs = (skb->stamp.tv_sec - bear_cookie->expiration.tv_sec) * 1000000L + skb->stamp.tv_usec - bear_cookie->expiration.tv_usec; usecs = htonl(usecs); - sctp_init_cause(*err_chk_p, SCTP_ERROR_STALE_COOKIE, + sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, &usecs, sizeof(usecs)); *error = -SCTP_IERROR_STALE_COOKIE; } else @@ -1541,10 +1572,10 @@ struct __sctp_missing { /* * Report a missing mandatory parameter. */ -static int sctp_process_missing_param(const sctp_association_t *asoc, +static int sctp_process_missing_param(const struct sctp_association *asoc, sctp_param_t paramtype, sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + sctp_chunk_t **errp) { struct __sctp_missing report; __u16 len; @@ -1554,13 +1585,13 @@ static int sctp_process_missing_param(const sctp_association_t *asoc, /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) { + if (*errp) { report.num_missing = htonl(1); report.type = paramtype; - sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, + sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, &report, sizeof(report)); } @@ -1569,17 +1600,17 @@ static int sctp_process_missing_param(const sctp_association_t *asoc, } /* Report an Invalid Mandatory Parameter. */ -static int sctp_process_inv_mandatory(const sctp_association_t *asoc, +static int sctp_process_inv_mandatory(const struct sctp_association *asoc, sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + sctp_chunk_t **errp) { /* Invalid Mandatory Parameter Error has no payload. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, 0); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, 0); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, NULL, 0); + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0); /* Stop processing this chunk. */ return 0; @@ -1588,19 +1619,19 @@ static int sctp_process_inv_mandatory(const sctp_association_t *asoc, /* Do not attempt to handle the HOST_NAME parm. However, do * send back an indicator to the peer. */ -static int sctp_process_hn_param(const sctp_association_t *asoc, +static int sctp_process_hn_param(const struct sctp_association *asoc, union sctp_params param, sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + sctp_chunk_t **errp) { __u16 len = ntohs(param.p->length); /* Make an ERROR chunk. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_DNS_FAILED, + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, param.v, len); /* Stop processing this chunk. */ @@ -1633,10 +1664,10 @@ static int sctp_process_hn_param(const sctp_association_t *asoc, * 0 - discard the chunk * 1 - continue with the chunk */ -static int sctp_process_unk_param(const sctp_association_t *asoc, +static int sctp_process_unk_param(const struct sctp_association *asoc, union sctp_params param, sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + sctp_chunk_t **errp) { int retval = 1; @@ -1649,12 +1680,12 @@ static int sctp_process_unk_param(const sctp_association_t *asoc, /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (NULL == *err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, + if (NULL == *errp) + *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, param.v, WORD_ROUND(ntohs(param.p->length))); @@ -1665,12 +1696,12 @@ static int sctp_process_unk_param(const sctp_association_t *asoc, /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (NULL == *err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, + if (NULL == *errp) + *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); - if (*err_chk_p) { - sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, + if (*errp) { + sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, param.v, WORD_ROUND(ntohs(param.p->length))); } else { @@ -1695,7 +1726,7 @@ static int sctp_process_unk_param(const sctp_association_t *asoc, * 0 - discard the chunk * 1 - continue with the chunk */ -static int sctp_verify_param(const sctp_association_t *asoc, +static int sctp_verify_param(const struct sctp_association *asoc, union sctp_params param, sctp_cid_t cid, sctp_chunk_t *chunk, @@ -1733,11 +1764,11 @@ static int sctp_verify_param(const sctp_association_t *asoc, } /* Verify the INIT packet before we process it. */ -int sctp_verify_init(const sctp_association_t *asoc, +int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t cid, sctp_init_chunk_t *peer_init, sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + sctp_chunk_t **errp) { union sctp_params param; int has_cookie = 0; @@ -1746,7 +1777,7 @@ int sctp_verify_init(const sctp_association_t *asoc, if ((0 == peer_init->init_hdr.num_outbound_streams) || (0 == peer_init->init_hdr.num_inbound_streams)) { - sctp_process_inv_mandatory(asoc, chunk, err_chk_p); + sctp_process_inv_mandatory(asoc, chunk, errp); return 0; } @@ -1762,9 +1793,8 @@ int sctp_verify_init(const sctp_association_t *asoc, * the state cookie for an INIT-ACK chunk. */ if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) { - sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, - chunk, err_chk_p); + chunk, errp); return 0; } @@ -1772,7 +1802,7 @@ int sctp_verify_init(const sctp_association_t *asoc, sctp_walk_params(param, peer_init, init_hdr.params) { - if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p)) + if (!sctp_verify_param(asoc, param, cid, chunk, errp)) return 0; } /* for (loop through all parameters) */ @@ -1784,7 +1814,7 @@ int sctp_verify_init(const sctp_association_t *asoc, * Returns 0 on failure, else success. * FIXME: This is an association method. */ -int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, +int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, const union sctp_addr *peer_addr, sctp_init_chunk_t *peer_init, int gfp) { @@ -1923,7 +1953,7 @@ nomem: * work we do. In particular, we should not build transport * structures for the addresses. */ -int sctp_process_param(sctp_association_t *asoc, union sctp_params param, +int sctp_process_param(struct sctp_association *asoc, union sctp_params param, const union sctp_addr *peer_addr, int gfp) { union sctp_addr addr; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ab54b2b63ed6..de5e9ddfd9b4 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -55,7 +55,6 @@ #include <linux/config.h> #include <linux/types.h> -#include <linux/compiler.h> #include <linux/kernel.h> #include <linux/wait.h> #include <linux/time.h> @@ -63,6 +62,7 @@ #include <linux/fcntl.h> #include <linux/poll.h> #include <linux/init.h> +#include <linux/crypto.h> #include <net/ip.h> #include <net/icmp.h> @@ -96,15 +96,16 @@ static int sctp_do_bind(struct sock *, union sctp_addr *, int); static int sctp_autobind(struct sock *sk); static void sctp_sock_migrate(struct sock *, struct sock *, struct sctp_association *, sctp_socket_type_t); +static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; /* Look up the association by its id. If this is not a UDP-style * socket, the ID field is always ignored. */ -sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) +struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) { - sctp_association_t *asoc = NULL; + struct sctp_association *asoc = NULL; - /* If this is not a UDP-style socket, assoc id should be + /* If this is not a UDP-style socket, assoc id should be * ignored. */ if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { @@ -116,9 +117,9 @@ sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) /* First, verify that this is a kernel address. */ if (sctp_is_valid_kaddr((unsigned long) id)) { - sctp_association_t *temp = (sctp_association_t *) id; + struct sctp_association *temp = (sctp_association_t *) id; - /* Verify that this _is_ an sctp_association_t + /* Verify that this _is_ an sctp_association * data structure and if so, that the socket matches. */ if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) && @@ -188,7 +189,6 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, return af; } - /* Bind a local address either to an endpoint or to an association. */ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) { @@ -637,7 +637,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, /* Alloc space for the address array in kernel memory. */ kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL); - if (unlikely(NULL == kaddrs)) + if (unlikely(!kaddrs)) return -ENOMEM; if (copy_from_user(kaddrs, addrs, addrssize)) { @@ -1134,8 +1134,9 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) */ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); -SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - int len, int noblock, int flags, int *addr_len) +SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, int len, int noblock, + int flags, int *addr_len) { struct sctp_ulpevent *event = NULL; struct sctp_opt *sp = sctp_sk(sk); @@ -1156,7 +1157,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr err = -ENOTCONN; goto out; } - + skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; @@ -1271,7 +1272,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, } static int sctp_setsockopt_peer_addr_params(struct sock *sk, - char *optval, int optlen) + char *optval, int optlen) { struct sctp_paddrparams params; sctp_association_t *asoc; @@ -1329,8 +1330,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, return 0; } -static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, - int optlen) +static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) { if (optlen != sizeof(struct sctp_initmsg)) return -EINVAL; @@ -1340,7 +1340,6 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, } /* - * * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) * * Applications that wish to use the sendto() system call may wish to @@ -1428,12 +1427,10 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, if (optlen < sizeof(__u8)) return -EINVAL; - if (get_user(val, (__u8 *)optval)) return -EFAULT; sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; - return 0; } @@ -1590,7 +1587,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, /* connect() cannot be done on a socket that is already in ESTABLISHED * state - UDP-style peeled off socket or a TCP-style socket that - * is already connected. + * is already connected. * It cannot be done even on a TCP-style listening socket. */ if ((SCTP_SS_ESTABLISHED == sk->state) || @@ -1690,10 +1687,10 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err) struct sctp_opt *sp; struct sctp_endpoint *ep; struct sock *newsk = NULL; - struct sctp_association *assoc; + struct sctp_association *asoc; long timeo; int error = 0; - + sctp_lock_sock(sk); sp = sctp_sk(sk); @@ -1715,21 +1712,21 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err) if (error) goto out; - /* We treat the list of associations on the endpoint as the accept - * queue and pick the first association on the list. + /* We treat the list of associations on the endpoint as the accept + * queue and pick the first association on the list. */ - assoc = list_entry(ep->asocs.next, struct sctp_association, asocs); + asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); - newsk = sp->pf->create_accept_sk(sk, assoc); + newsk = sp->pf->create_accept_sk(sk, asoc); if (!newsk) { error = -ENOMEM; goto out; } /* Populate the fields of the newsk from the oldsk and migrate the - * assoc to the newsk. - */ - sctp_sock_migrate(sk, newsk, assoc, SCTP_SOCKET_TCP); + * asoc to the newsk. + */ + sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); out: sctp_release_sock(sk); @@ -1737,10 +1734,10 @@ out: return newsk; } -/* FIXME: Write Comments. */ +/* The SCTP ioctl handler. */ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - return -EOPNOTSUPP; /* STUB */ + return -ENOIOCTLCMD; } /* This is the function which gets called during socket creation to @@ -1835,11 +1832,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) * change the data structure relationships, this may still * be useful for storing pre-connect address information. */ - ep = sctp_endpoint_new(proto, sk, GFP_KERNEL); - if (NULL == ep) + ep = sctp_endpoint_new(sk, GFP_KERNEL); + if (!ep) return -ENOMEM; sp->ep = ep; + sp->hmac = NULL; SCTP_DBG_OBJCNT_INC(sock); return 0; @@ -1848,7 +1846,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) /* Cleanup any SCTP per socket resources. */ SCTP_STATIC int sctp_destroy_sock(struct sock *sk) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); @@ -1877,7 +1875,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, int *optlen) { struct sctp_status status; - sctp_association_t *assoc = NULL; + struct sctp_association *asoc = NULL; struct sctp_transport *transport; sctp_assoc_t associd; int retval = 0; @@ -1893,22 +1891,22 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, } associd = status.sstat_assoc_id; - assoc = sctp_id2assoc(sk, associd); - if (!assoc) { + asoc = sctp_id2assoc(sk, associd); + if (!asoc) { retval = -EINVAL; goto out; } - transport = assoc->peer.primary_path; + transport = asoc->peer.primary_path; - status.sstat_assoc_id = sctp_assoc2id(assoc); - status.sstat_state = assoc->state; - status.sstat_rwnd = assoc->peer.rwnd; - status.sstat_unackdata = assoc->unack_data; - status.sstat_penddata = assoc->peer.tsn_map.pending_data; - status.sstat_instrms = assoc->c.sinit_max_instreams; - status.sstat_outstrms = assoc->c.sinit_num_ostreams; - status.sstat_fragmentation_point = assoc->frag_point; + status.sstat_assoc_id = sctp_assoc2id(asoc); + status.sstat_state = asoc->state; + status.sstat_rwnd = asoc->peer.rwnd; + status.sstat_unackdata = asoc->unack_data; + status.sstat_penddata = asoc->peer.tsn_map.pending_data; + status.sstat_instrms = asoc->c.sinit_max_instreams; + status.sstat_outstrms = asoc->c.sinit_num_ostreams; + 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), sizeof(union sctp_addr)); @@ -1975,33 +1973,29 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int } /* Helper routine to branch off an association to a new socket. */ -SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) +SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, + struct socket **sockp) { - struct sock *oldsk = assoc->base.sk; - struct sock *newsk; - struct socket *tmpsock; + struct sock *sk = asoc->base.sk; + struct socket *sock; int err = 0; /* An association cannot be branched off from an already peeled-off * socket, nor is this supported for tcp style sockets. */ - if (SCTP_SOCKET_UDP != sctp_sk(oldsk)->type) - return -EOPNOTSUPP; + if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) + return -EINVAL; /* Create a new socket. */ - err = sock_create(oldsk->family, SOCK_SEQPACKET, IPPROTO_SCTP, - &tmpsock); + err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); if (err < 0) return err; - newsk = tmpsock->sk; - /* Populate the fields of the newsk from the oldsk and migrate the * assoc to the newsk. - */ - sctp_sock_migrate(oldsk, newsk, assoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); - - *newsock = tmpsock; + */ + sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); + *sockp = sock; return err; } @@ -2019,7 +2013,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int * return -EFAULT; assoc = sctp_id2assoc(sk, peeloff.associd); - if (NULL == assoc) { + if (!assoc) { retval = -EINVAL; goto out; } @@ -2049,7 +2043,7 @@ out: return retval; } -static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, +static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, char *optval, int *optlen) { struct sctp_paddrparams params; @@ -2102,7 +2096,7 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int * return 0; } -static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, +static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, char *optval, int *optlen) { sctp_assoc_t id; @@ -2350,7 +2344,7 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, * integer boolean flag. */ -static int sctp_getsockopt_nodelay(struct sock *sk, int len, +static int sctp_getsockopt_nodelay(struct sock *sk, int len, char *optval, int *optlen) { __u8 val; @@ -2418,7 +2412,7 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); break; case SCTP_GET_PEER_ADDRS_NUM: - retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, + retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, optlen); break; case SCTP_GET_LOCAL_ADDRS_NUM: @@ -2553,7 +2547,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) } - if (pp != NULL && pp->sk != NULL) { + if (pp && pp->sk) { /* We had a port hash table hit - there is an * available port (pp != NULL) and it is being * used by other socket (pp->sk != NULL); that other @@ -2601,18 +2595,17 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) /* If there was a hash table miss, create a new port. */ ret = 1; - if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL) + if (!pp && !(pp = sctp_bucket_create(head, snum))) goto fail_unlock; /* In either case (hit or miss), make sure fastreuse is 1 only * if sk->reuse is too (that is, if the caller requested * SO_REUSEADDR on this socket -sk-). */ - if (pp->sk == NULL) { + if (!pp->sk) pp->fastreuse = sk->reuse ? 1 : 0; - } else if (pp->fastreuse && sk->reuse == 0) { + else if (pp->fastreuse && sk->reuse == 0) pp->fastreuse = 0; - } /* We are set, so fill up all the data in the hash table * entry, tie the socket list information with the rest of the @@ -2702,7 +2695,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) /* * 4.1.3 listen() - TCP Style Syntax * - * Applications uses listen() to ready the SCTP endpoint for accepting + * Applications uses listen() to ready the SCTP endpoint for accepting * inbound associations. */ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) @@ -2739,15 +2732,25 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) int sctp_inet_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; - int err; + struct crypto_tfm *tfm=NULL; + int err = -EINVAL; + + if (unlikely(backlog < 0)) + goto out; sctp_lock_sock(sk); - err = -EINVAL; if (sock->state != SS_UNCONNECTED) goto out; - if (unlikely(backlog < 0)) - goto out; + + /* Allocate HMAC for generating cookie. */ + if (sctp_hmac_alg) { + tfm = crypto_alloc_tfm(sctp_hmac_alg, 0); + if (!tfm) { + err = -ENOSYS; + goto out; + } + } switch (sock->type) { case SOCK_SEQPACKET: @@ -2756,14 +2759,21 @@ int sctp_inet_listen(struct socket *sock, int backlog) case SOCK_STREAM: err = sctp_stream_listen(sk, backlog); break; - default: - goto out; + break; }; + if (err) + goto cleanup; + /* Store away the transform reference. */ + sctp_sk(sk)->hmac = tfm; out: sctp_release_sock(sk); return err; +cleanup: + if (tfm) + crypto_free_tfm(tfm); + goto out; } /* @@ -2967,7 +2977,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, /* Strictly check lengths following example in SCM code. */ switch (cmsg->cmsg_type) { case SCTP_INIT: - /* SCTP Socket API Extension (draft 1) + /* SCTP Socket API Extension * 5.2.1 SCTP Initiation Structure (SCTP_INIT) * * This cmsghdr structure provides information for @@ -2987,7 +2997,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, break; case SCTP_SNDRCV: - /* SCTP Socket API Extension (draft 1) + /* SCTP Socket API Extension * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) * * This cmsghdr structure specifies SCTP options for @@ -3002,7 +3012,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) return -EINVAL; - cmsgs->info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + cmsgs->info = + (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); /* Minimally, validate the sinfo_flags. */ if (cmsgs->info->sinfo_flags & @@ -3085,13 +3096,14 @@ out: * Note: This is pretty much the same routine as in core/datagram.c * with a few changes to make lksctp work. */ -static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) +static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, + int noblock, int *err) { int error; struct sk_buff *skb; long timeo; - /* Caller is allowed not to check sk->err before skb_recv_datagram() */ + /* Caller is allowed not to check sk->err before calling. */ error = sock_error(sk); if (error) goto no_packet; @@ -3140,7 +3152,7 @@ no_packet: } /* Verify that this is a valid address. */ -static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, +static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len) { struct sctp_af *af; @@ -3443,11 +3455,12 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo) return err; } -/* Populate the fields of the newsk from the oldsk and migrate the assoc +/* Populate the fields of the newsk from the oldsk and migrate the assoc * and its messages to the newsk. - */ -void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, - struct sctp_association *assoc, sctp_socket_type_t type) + */ +static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, + struct sctp_association *assoc, + sctp_socket_type_t type) { struct sctp_opt *oldsp = sctp_sk(oldsk); struct sctp_opt *newsp = sctp_sk(newsk); @@ -3466,6 +3479,7 @@ void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, * copy. */ newsp->ep = newep; + newsp->hmac = NULL; /* Move any messages in the old socket's receive queue that are for the * peeled off association to the new socket's receive queue. @@ -3526,7 +3540,7 @@ void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, newsk->state = SCTP_SS_ESTABLISHED; } - + /* This proto struct describes the ULP interface for SCTP. */ struct proto sctp_prot = { .name = "SCTP", |
