Commit d77fdda9 authored by Jon Grimm's avatar Jon Grimm

[SCTP] Use Crypto API

Rip out our own HMAC-SHA1 and replace with crypto API.  
Can now choose hmac-sha1, hmac-md5, or none with regards to what
HMAC to use for cookie echo verification.
parent 38d05e5b
......@@ -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.
*/
......
......@@ -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
......
......@@ -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 *);
......
......@@ -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
......@@ -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
......
......@@ -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) {
......
......@@ -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 @@ sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto,
/*
* 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 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
* 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
......
......@@ -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 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
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 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
* 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 @@ sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc,
*
* 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 @@ sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc,
}
/* 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 @@ sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc,
/* 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 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc,
/* 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;
......@@ -603,7 +605,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
if (sctp_tsnmap_has_gap(map)) {
sctp_tsnmap_iter_init(map, &iter);
while (sctp_tsnmap_next_gap_ack(map, &iter,
while (sctp_tsnmap_next_gap_ack(map, &iter,
&gab.start, &gab.end))
num_gabs++;
}
......@@ -663,11 +665,11 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
/* Put the Gap Ack Blocks into the chunk. */
if (num_gabs) {
sctp_tsnmap_iter_init(map, &iter);
while(sctp_tsnmap_next_gap_ack(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),
sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t),
&gab);
}
}
......@@ -681,7 +683,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
}
/* 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;
......@@ -701,7 +703,7 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
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;
......@@ -723,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;
......@@ -753,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)
{
......@@ -781,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;
......@@ -815,7 +817,7 @@ sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc,
}
/* 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)
{
......@@ -862,7 +864,7 @@ sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc,
}
/* 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)
{
......@@ -882,7 +884,7 @@ sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc,
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)
{
......@@ -912,7 +914,7 @@ sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc,
/* 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)
{
......@@ -939,7 +941,7 @@ sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc,
}
/* 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)
......@@ -962,7 +964,8 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc,
/* 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);
......@@ -976,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;
......@@ -1029,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;
......@@ -1038,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;
......@@ -1141,7 +1144,7 @@ static int sctp_user_addto_chunk(sctp_chunk_t *chunk, int off, int len,
*/
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)
......@@ -1297,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;
......@@ -1345,15 +1348,18 @@ sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
/* 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)
......@@ -1367,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;
......@@ -1398,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;
......@@ -1446,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.
......@@ -1478,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
......@@ -1547,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;
......@@ -1560,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));
}
......@@ -1575,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;
......@@ -1594,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. */
......@@ -1639,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;
......@@ -1655,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)));
......@@ -1671,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 {
......@@ -1701,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,
......@@ -1739,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;
......@@ -1752,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;
}
......@@ -1768,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;
}
......@@ -1778,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) */
......@@ -1790,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)
{
......@@ -1929,7 +1953,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* 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;
......
......@@ -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 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err)
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 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *
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 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
* 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 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
}
/* 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",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment